30

我正在编写一些带有多个子查询和大量连接的 SQL 查询,包括子查询内部和子查询的结果表。

我们没有使用视图,所以这是不可能的。

写完之后,我看着它,挠头想知道它在做什么,因为我无法理解它。

你用什么样的格式来尝试清理这样的混乱?可能是缩进?

4

11 回答 11

20

对于大型查询,我倾向于非常依赖使用WITH. 这允许预先定义结果集,并使主查询更简单。命名结果集也可能有助于使查询计划更有效,例如 postgres 将结果集存储在临时表中。

例子:

WITH 
  cubed_data AS (
     SELECT 
        dimension1_id,
        dimension2_id,
        dimension3_id,
        measure_id,
        SUM(value) value
     FROM
        source_data
     GROUP BY
        CUBE(dimension1, dimension2, dimension3),
        measure
  ), 
  dimension1_label AS(
     SELECT 
        dimension1_id,
        dimension1_label
     FROM 
        labels 
     WHERE 
        object = 'dimension1'
  ), ...
SELECT 
  *
FROM  
  cubed_data
  JOIN dimension1_label USING (dimension1_id)
  JOIN dimension2_label USING (dimension2_id)
  JOIN dimension3_label USING (dimension3_id)
  JOIN measure_label USING (measure_id)

这个例子有点做作,但我希望它显示出与内联子查询相比清晰度的提高。当我为 OLAP 使用准备数据时,命名结果集对我有很大帮助。如果您有/想要创建递归查询,则还必须使用命名结果集。

WITH至少在当前版本的 Postgres、Oracle 和 SQL Server 上工作

于 2011-03-28T16:01:19.380 回答
10

男孩这是一个加载的问题。:) 这个网站上有多少聪明人,就有多少方法可以做到这一点。也就是说,这是我在构建复杂的 sql 语句时保持理智的方法:

select
    c.customer_id
   ,c.customer_name
   ,o.order_id
   ,o.order_date
   ,o.amount_taxable
   ,od.order_detail_id
   ,p.product_name
   ,pt.product_type_name
from
    customer c
inner join
    order o
    on c.customer_id = o.customer_id
inner join
    order_detail od
    on o.order_id = od.order_id
inner join
    product p
    on od.product_id = p.product_id
inner join
    product_type pt
    on p.product_type_id = pt.product_type_id
where
    o.order_date between '1/1/2011' and '1/5/2011'
and
    (
        pt.product_type_name = 'toys'
     or
        pt.product_type_name like '%kids%'
    )
order by
    o.order_date
   ,pt.product_type_name
   ,p.product_name

如果您有兴趣,我可以发布/发送插入、更新和删除以及相关子查询和复杂连接谓词的布局。

这回答了你的问题了吗?

于 2011-03-28T16:53:39.837 回答
4

通常,人们会在保留字上换行,并缩进任何子查询:

SELECT *
FROM tablename
WHERE value in
   (SELECT *
   FROM tablename2 
   WHERE condition)
ORDER BY column
于 2011-03-28T15:47:40.790 回答
4

表别名和简单的一致性将使您走得更远

看起来不错的是主要关键字 SELECT、FROM、WHERE(等等)的断行。

连接可能更棘手,缩进连接的 ON 部分会将其重要部分带到前面。

在同一级别上打破复杂的逻辑表达式(连接和 where 条件)也有帮助。

逻辑上相同级别的语句缩进(子查询、左括号等)

将所有关键字和标准函数大写。

真正复杂的 SQL 不会回避注释 - 尽管通常您在 SQL 脚本中发现这些不是动态 SQL。

编辑示例:

SELECT a.name, SUM(b.tax)
FROM   db_prefix_registered_users a 
       INNER JOIN db_prefix_transactions b 
           ON a.id = b.user_id
       LEFT JOIN db_countries
           ON b.paid_from_country_id = c.id
WHERE  a.type IN (1, 2, 7) AND
       b.date < (SELECT MAX(date) 
                 FROM audit) AND
       c.country = 'CH'

所以,最后总结一下——一致性最重要。

于 2011-03-28T15:47:59.963 回答
3

格式化 SQL唯一真正正确的方法是:

SELECT t.mycolumn        AS column1
      ,t.othercolumn     AS column2
      ,SUM(t.tweedledum) AS column3
FROM   table1 t
      ,(SELECT u.anothercol
              ,u.memaw                  /*this is a comment*/
        FROM   table2       u
              ,anothertable x
        WHERE  u.bla       = :b1        /*the bla value*/
        AND    x.uniquecol = :b2        /*the widget id*/
       ) v
WHERE  t.tweedledee = v.anothercol
AND    t.hohum      = v.memaw
GROUP BY t.mycolumn
        ,t.othercolumn
HAVING COUNT(*) > 1
;

;)

不过说真的,我喜欢使用 WITH 子句(如前所述)来驯服非常复杂的 SQL 查询。

于 2011-03-29T04:59:44.127 回答
3

一般来说,我遵循一组简单的分层格式规则。基本上,SELECT、FROM、ORDER BY 等关键字都在自己的行中。每个字段都有自己的一行(以递归方式)

SELECT 
    F.FIELD1,
    F.FIELD2,
    F.FIELD3
FROM
    FOO F 
WHERE 
    F.FIELD4 IN 
    (
        SELECT 
            B.BAR
        FROM 
            BAR B
        WHERE
            B.TYPE = 4
            AND B.OTHER = 7
    )
于 2011-03-28T15:49:34.040 回答
3

我喜欢使用类似的东西:

SELECT    col1,
          col2,
          ...
FROM
    MyTable as T1
INNER JOIN
    MyOtherTable as T2
        ON t1.col1 = t2.col1
        AND t1.col2 = t2.col2
LEFT JOIN
    (   
        SELECT 1,2,3
        FROM Someothertable
        WHERE somestuff = someotherstuff
    ) as T3
    ON t1.field = t3.field
于 2011-03-28T15:49:42.317 回答
2

哇,这里有很多回复,但我在很多人中没有看到的一件事是评论!我倾向于在整个过程中添加很多注释,尤其是对于大型 SQL 语句。格式很重要,但放置得当且有意义的注释非常重要,不仅对您,对需要维护代码的可怜人来说;)

于 2011-03-29T11:04:44.307 回答
2

一个古老的问题,有一千种意见,没有一个正确的答案,也是我的最爱之一。这是我的两分钱。

关于子查询,最近我发现使用“极端”缩进和添加评论更容易理解:

SELECT mt.Col1, mt.Col2, subQ.Dollars
 from MyTable1 mt
  inner join (--  Get the dollar total for each SubCol
              select SubCol, sum(Dollars) Dollars
               from MyTable2
               group by SubCol) subQ
   on subQ.SubCol = mt.Col1
 order by mt.Col2

至于其他分,我只在第一个单词上使用大写。通过连续查询页面,可以更轻松地确定新查询何时开始。

当然,您的里程会有所不同。

于 2011-03-28T16:09:22.993 回答
2

将其放在视图中以便更容易可视化,也许将屏幕截图作为文档的一部分。您不必保存视图或将其用于任何其他目的。

于 2011-03-28T15:49:07.730 回答
2

当然可以缩进,但您也可以将子查询与注释分开,使您的别名真正有意义并指定它们引用的子查询,例如innerCustomer、outerCustomer。

在某些情况下,公用表表达式确实可以帮助将查询分解为有意义的部分。

于 2011-03-28T15:51:00.257 回答