【问题标题】:Optimizing WHERE clause SQL query优化 WHERE 子句 SQL 查询
【发布时间】:2013-11-30 22:11:08
【问题描述】:

我正在使用 SQL Server。我发现自己在 WHERE 子句中使用以下语法进行复杂查询:

SELECT ..
WHERE StudentID IS NULL OR StudentID NOT IN (SELECT StudentID from Students)

想知道是否有更好的方法/更清洁的方法来替换它,因为这是我正在执行的更大查询的一个小示例,其中包含多个类似的条件。

如您所见,我正在尝试为特定列过滤其列值为 null 或无效 id 的行。

编辑

课程

|CourseID   | StudentID | StudentID2|
|-----------------------------------|
| 1         | 100       | NULL      |
| 2         | NULL      | 200       |
| 3         | 1         | 1         |

学生

|StudentID  | Name  |
|--------------------
| 1         | A     |
| 2         | B     |
| 3         | C     |

查询:

SELECT CourseID 
FROM Courses 
WHERE
   StudentID IS NULL OR StudentID NOT IN (SELECT * FROM Students)
   OR StudentID2 IS NULL OR StudentID2 NOT IN (SELECT * FROM Students)

结果:

| CourseID  |
|-----------|
| 1         |
| 2         |

如您所见,课程 1 和 2 的学生无效。

【问题讨论】:

  • StudentId 可以是非空的,但它不是学生,那你为什么需要子查询呢?
  • 这些信息太少,无法真正帮助您。考虑添加该选择的功能示例,其中包含表结构、示例数据和预期输出。
  • 同时告诉我们您正在使用哪个 DBMS。后格雷斯?甲骨文?
  • 我已经用表格示例编辑了我的问题,希望你能提供帮助

标签: sql sql-server where


【解决方案1】:

Alain 很接近,除了 studentID2 列与课程表相关联。此外,这是将每个 studentID 列连接到学生表的一个实例,最后的 WHERE 正在测试学生 ID 是否失败,因此即使 Student1 有效并且在 Student2 上仍然失败,它也会按照您的意图捕获课程.

SELECT 
      C.CourseID 
   FROM 
      Courses C
         LEFT JOIN Students S
            ON C.StudentId = S.StudentId
         LEFT JOIN Students S2
            OR C.StudentId2 = S2.StudentId
   WHERE
         S.StudentId IS NULL 
      OR S2.StudentID IS NULL

【讨论】:

  • 与您的 ;) 同时重新发布,但我认为 Popokoko 希望拥有 all 不匹配的学生,所以我认为它应该是 WHERE 部分中的 AND 而不是 OR ?
  • @Alain_Deloin,虽然他的数据没有显示,但我认为这是一个 OR...如果学生 ID #1 为 1(有效),而 #2 为 NULL 或 100(均无效)怎么办.他们会想要查看该记录。
  • 应该是 OR 但你们仍然摇滚,我勾选了 Alain 的回答 :) 非常感谢这两个解决方案!
  • @Popokoko,如果应该是 OR,你为什么要检查 AND 答案... Alain 的版本。在他的版本中,如果您有一门 StudentID = 1 且 StudentID2 = NULL 的课程,它将不会在您的结果集中返回该课程。
  • 嗯,我猜是因为我尊重你们俩的努力,但你们做得对。不想混淆别人所以我重新编辑。谢谢。
【解决方案2】:

这不是一个确定的镜头,但我有经验表明这比问题之一表现更好:

SELECT CourseID from Courses WHERE
Courses.StudentID NOT exists (SELECT 1 FROM Students where Students.StudentID=nvl(Courses.StudentID,-1));

还要在学生表中的 StudentId 上创建索引。

如果您的数据模型支持在 2 个表之间创建主键外键关系。这样你绝对可以避免课程表中的无效值。

更新后:

SELECT CourseID from Courses WHERE
Courses.StudentID NOT exists (SELECT 1 FROM Students where Students.StudentID=nvl(Courses.StudentID1,-1) or Students.StudentID=nvl(Courses.StudentID2,-1));

【讨论】:

  • 1.什么是nvl? 2.如果学生表没有pk怎么办?
  • 如果你的数据模型定义良好,你可以在表上创建一个pk,它应该有pk。而 NVL 是一个函数,它表示如果第一个参数给出的值为 null 则使用第二个参数作为输出,因此它满足 Student id is null 部分
  • 感谢您的回复,但您不觉得还是有点乱吗?或者没有其他方法可以做到这一点?
  • 如果你有 2 列要检查,它会变得混乱。这就是为什么我建议你使用 PK-FK 关系。这样你就可以首先避免无效的学生
  • 您也可以根据需要进行特定更改。建立数据校正功能。在执行时,它会在发现无效值的地方用 -1 更新学生 ID。然后你只需查询 -1 值。这种方式更快更高效。您可以定期或在触发器内安排函数。
【解决方案3】:

NOT EXISTS 模式很好,但是,您有几种方法可以做到这一点。

你应该检查herehere

例如使用 LEFT JOIN(两个左连接,因为检查了两个变量)

SELECT *
from Courses 
LEFT JOIN Students Student1
    on Courses.StudentId = Student1.StudentId
LEFT JOIN Students Student2
    on Courses.StudentId2 = Student2.StudentId
WHERE
    -- No matching Student
    student1.StudentId IS NULL 
    and student2.StudentId IS NULL 

【讨论】:

  • 这个查询的问题是它不能解决我的课程表中存在无效 ID 的问题。这就是我添加“OR StudentID NOT IN (..)”部分的原因。该表并不完美,我无法编辑它的关系,你建议我保留我的原始查询吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多