理解复杂SQL语句的最佳方法是什么?

Eri*_*ess 43 sql database

有没有人有方法来理解复杂的SQL语句?在阅读结构/ OO代码时,通常有一些抽象层可以帮助您将其分解为可管理的块.但是,通常在SQL中,您似乎必须同时跟踪查询的多个部分中发生的情况.

此问题的推动力是此问题中讨论的关于复杂连接的SQL查询.在盯着答案查询几分钟后,我终于决定使用特定记录逐步查询查看发生了什么.这是我能想到的唯一方法来逐一理解查询.

有没有更好的方法将SQL查询分解为可管理的部分?

HLG*_*GEM 40

当我查看一段复杂的SQL代码时,这就是我所做的.

首先,如果是更新或删除,我添加代码(如果它不存在并注释掉)以使其成为选择.切勿首次尝试更新或删除,而不先在选择中查看结果.如果是更新,我确保选择显示当前值以及我将其设置为什么,以确保我得到所需的结果.

了解连接对于理解复杂的SQL至关重要.对于每次加入我都会问自己为什么会这样?有四个基本原因.你需要一个select列的列,你需要一个where子句的字段,你需要join作为第三个表的桥接,或者你需要加入到表中来过滤记录(比如检查有订单的客户的详细信息)但是不需要订单细节,这通常可以通过IF EXISTS where子句更好地完成.如果是左连接或右连接(我倾向于重写所以一切都是左连接,这使生活更简单.),我考虑内部连接是否有效.为什么我需要左连接?如果我不知道答案,我会双向运行,看看数据中的差异是什么.如果有派生表,我将首先看一下(运行select的那一部分以查看结果是什么)来理解它为什么存在.如果存在子查询,我将尝试理解它们,如果它们很慢,则会尝试转换为派生表,因为它们通常要快得多.

接下来,我看看这些where条款.在这个地方,您的特定数据库中的坚实基础会派上用场.例如,我知道在我的数据库中,我可能需要查看邮件地址以及我可能需要查看其他地址的场合.这有助于我知道where子句中是否缺少某些内容.否则我会考虑条款中的每个项目,where并弄清楚为什么需要在那里,然后我会考虑是否有任何遗漏应该存在.在查看之后,我考虑是否可以进行调整以使查询变得可搜索.

我还考虑下一个选择列表的任何复杂位.那个案例陈述做了什么?为什么有子查询?这些功能有什么作用?(我总是查找我不熟悉的任何函数的函数代码.)为什么有明显的?是否可以通过使用派生表或聚合函数和group by语句来消除它?

最后,最重要的是,我运行选择并根据我对业务的了解确定结果是否正确.如果您不了解您的业务,您将不知道查询是否正确.语法正确并不意味着正确的结果.通常,您现有的用户界面中有一部分可用作指导结果是否正确的指南.如果我有一个显示客户订单的屏幕,并且我正在做包含客户订单的报告,我可能会检查一些个别客户,以确保它显示正确的结果.

如果当前查询过滤不正确,我将删除它的一些内容,以找出什么是摆脱我不想要的记录或添加我不想要的记录.通常你会发现连接是一对多的,你需要一对一(在这种情况下使用派生表!)或者你会发现你认为你需要的一些信息where对于所有人都不是真的您需要的数据或where缺少某些条款的数据.它有助于拥有所有领域where当你执行此操作时,在select中的子句(如果它们不在select中).它甚至可以帮助显示所有连接表中的所有字段并真正查看数据.当我这样做时,我经常在where子句中添加一点点来获取我不应该存在的一些记录而不是所有记录.

一个会破坏大量查询的偷偷摸摸的东西是where引用左连接右侧表格中的字段的子句.这将它变成了一个内部联接.如果您确实需要左连接,则应将这些条件添加到连接本身.


Kon*_*Kon 17

这些可能是一些有用的提示..

  • 评论 - 弄清楚一个小块的作用并对其进行评论,以便您在以后再参考它时理解它.
  • 语法突出显示 - 确保您正在查看带有对查询进行颜色编码的代码.
  • 缩进 - 重新组织查询以使您有意义..选项卡结束,添加回车符.

例如:

select ID, Description, Status from ABC where Status = 1 OR Status = 3
Run Code Online (Sandbox Code Playgroud)

可以更好地写为:

select 
  ID,
  Description,
  Status
from ABC
where
  Status = 1 OR
  Status = 3
Run Code Online (Sandbox Code Playgroud)

通过更复杂的查询,您将看到更大的好处.


Joh*_*yre 12

这是解开查询的过程.

  1. 首先我格式化SQL.
  2. 然后我注释掉SQL的所有部分,而不是最主要或最重要的表的基本部分来回答问题.
  3. 然后我将开始取消注释连接,选择列,分组,顺序字段和过滤器以分析查询的不同部分以查看发生的情况.或突出显示 - 执行在某些工具中有效.
  4. 子查询通常可以独立执行.

执行这些中的每一个通常可以让我更好地掌握查询中发生的事情.


Ste*_*ier 9

大多数情况下,这只是经验和适当的缩进.


Evi*_*ach 8

缩进和评论有很多帮助.我遇到的最有价值的事情是WITH语句.它在Oracle中,处理子查询重构.它允许您将大型查询分解为一组看似较小的查询.每个只是更易于管理.

这是一个例子

WITH 
ssnInfo AS
(
    SELECT SSN, 
           UPPER(LAST_NAME), 
           UPPER(FIRST_NAME), 
           TAXABLE_INCOME,          
           CHARITABLE_DONATIONS
    FROM IRS_MASTER_FILE
    WHERE STATE = 'MN'                 AND -- limit to in-state
          TAXABLE_INCOME > 250000      AND -- is rich 
          CHARITABLE_DONATIONS > 5000      -- might donate too

),
doltishApplicants AS
(
    SELECT SSN, 
           SAT_SCORE,
           SUBMISSION_DATE
    FROM COLLEGE_ADMISSIONS
    WHERE SAT_SCORE < 100          -- About as smart as a Moose.
),
todaysAdmissions AS
(
    SELECT doltishApplicants.SSN, 
           TRUNC(SUBMISSION_DATE)  SUBMIT_DATE, 
           LAST_NAME, FIRST_NAME, 
           TAXABLE_INCOME
    FROM ssnInfo,
         doltishApplicants
    WHERE ssnInfo.SSN = doltishApplicants.SSN

)
SELECT 'Dear ' || FIRST_NAME || 
       ' your admission to WhatsaMattaU has been accepted.'
FROM todaysAdmissions
WHERE SUBMIT_DATE = TRUNC(SYSDATE)    -- For stuff received today only
;
Run Code Online (Sandbox Code Playgroud)

使用内联视图可以完成同样的操作,但是还可以在需要时创建临时表.在某些情况下,您可以复制出子查询并在大型查询的上下文之外执行它.

此表单还允许您将过滤器子句与单个子查询放在一起,并保存最终选择的连接子句.

在工作中,我们的开发小组通常发现它们更容易维护,而且通常更快.

  • SQL Server 2005 和 SQL Server 2008 也支持WITH 子句。 (3认同)

Ste*_*owe 5

格式化有所帮助,但理解集合论和扩展,关系理论,甚至更有帮助.

对查询执行方式的模糊理解也不会造成影响(表扫描,索引扫描,索引跳转,哈希表合并等); 查询计划程序可以向您显示这些操作

一些操作(有,存在,有)一开始可能很麻烦

首先要了解每个表发生了什么,以及如何连接表


fra*_*tor 5

我发现返回到逻辑查询处理阶段并使用示例数据一点点地取消查询通常很有帮助。

(以下内容借自《Inside Microsoft SQL Server 2005:T-SQL 查询》,作者:Itzik Ben-Gan。)

(8) SELECT (9) DISTINCT (11) <TOP_specification> <select_list>
(1) FROM <left_table>
(3) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH {CUBE | ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY <order_by_list>
Run Code Online (Sandbox Code Playgroud)
  1. FROM:FROM 子句中的前两个表之间进行笛卡尔积(交叉连接),生成虚拟表 VT1。
  2. ON : ON 滤波器应用于 VT1。仅将 为 TRUE 的行插入到 VT2 中。
  3. OUTER(连接):如果指定了 OUTER JOIN(与 CROSS JOIN 或 INNER JOIN 相反),则保留的表中的行或未找到匹配项的表中的行将作为外部行添加到 VT2 中的行,生成VT3。如果 FROM 子句中出现两个以上的表,则在最后一个联接的结果与 FROM 子句中的下一个表之间重复应用步骤 1 到 3,直到处理完所有表。
  4. WHERE:WHERE 过滤器应用于 VT3。仅将 为 TRUE 的行插入到 VT4。
  5. GROUP BY:VT4 中的行根据 GROUP BY 子句中指定的列列表分组排列。生成VT5。
  6. 立方体 | ROLLUP:将超组(组的组)添加到 VT5 的行中,生成 VT6。
  7. HAVING:HAVING 滤波器应用于 VT6。仅将 为 TRUE 的组插入到 VT7。
  8. SELECT:处理 SELECT 列表,生成 VT8。
  9. DISTINCT:从 VT8 中删除重复的行。VT9 已生成。
  10. ORDER BY:VT9 中的行根据 ORDER BY 子句中指定的列列表进行排序。生成游标 (VC10)。
  11. TOP:从 VC10 的开头选择指定数量或百分比的行。表VT11被生成并返回给调用者。