Форматирование понятных и читаемых запросов SQL - PullRequest
28 голосов
/ 28 марта 2011

Я пишу несколько SQL-запросов с несколькими подзапросами и множеством объединений повсюду, как внутри подзапроса, так и в результирующей таблице из подзапроса.

Мы не используем представления, поэтому об этом не может быть и речи.

После того, как я написал это, я смотрю на него и чешу голову, размышляя о том, что он вообще делает, потому что не могу за ним следить.

Какое форматирование вы используете, чтобы попытаться устранить такой беспорядок? Отступы что ли?

Ответы [ 11 ]

19 голосов
/ 28 марта 2011

При больших запросах я склонен полагаться на именованные наборы результатов, используя 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

10 голосов
/ 28 марта 2011

Мальчик, это загруженный вопрос.:) Существует столько способов сделать это правильно, сколько умных людей на этом сайте.Тем не менее, вот как я сохраняю себя в здравом уме при построении сложных операторов 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

Если вам интересно, я могу публиковать / отправлять макеты для вставок, обновлений и удалений, а также коррелированных подзапросов и сложныхпредикаты объединения.

Отвечает ли это на ваш вопрос?

4 голосов
/ 28 марта 2011

Псевдонимы таблиц и простая согласованность позволят вам проделать долгий и длинный путь

Что выглядит прилично, так это разрыв строки по основным ключевым словам SELECT, FROM, WHERE (и т. Д.).

Объединения могутБудьте хитрее, если сделать отступ включенной части соединений, то выведите важную часть на передний план.

Помогает также разбивание сложных логических выражений (объединений и условий обоих) на одном уровне.

Логическое отступление одного и того же уровня оператора (подзапросы, открывающие скобки и т. Д.)

Использование всех ключевых слов и стандартных функций с заглавной буквы.

Действительно сложный SQL не будет уклоняться от комментариев - хотя обычно вы найдете их вСценарии SQL не являются динамическими SQL.

Пример EDIT:

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'

Итак, в конце, чтобы подвести итог - согласованность важнее всего.

3 голосов
/ 29 марта 2011

Способ только верный и правильный для форматирования 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.

3 голосов
/ 28 марта 2011

Мне нравится использовать что-то вроде:

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
3 голосов
/ 28 марта 2011

В общем, я следую простому иерархическому набору правил форматирования.По сути, ключевые слова, такие как 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
    )
3 голосов
/ 28 марта 2011

Обычно люди разбивают строки на зарезервированные слова и делают отступы для любых подзапросов:

SELECT *
FROM tablename
WHERE value in
   (SELECT *
   FROM tablename2 
   WHERE condition)
ORDER BY column
2 голосов
/ 29 марта 2011

Ух ты, здесь много ответов, но я не видел во многих замечаний!Я склонен добавлять много комментариев, особенно с большими операторами SQL.Форматирование важно, но хорошо размещенные и значимые комментарии чрезвычайно важны не только для вас, но и для бедной души, которой необходимо поддерживать код;)

2 голосов
/ 28 марта 2011

Вечный вопрос с тысячей мнений, без единого правильного ответа и один из моих любимых.Вот мои два цента.

Что касается подзапросов, в последнее время мне стало проще следить за тем, что происходит с «экстремальным» отступом и добавляя комментарии, например, так:

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

Что касаетсядругой цент, я использую только верхний регистр в первом слове.Со страницами запросов при запуске становится легче выбирать, когда запускается новый.

Ваш пробег, конечно, будет разным.

2 голосов
/ 28 марта 2011

Отступы, конечно, но вы также можете разделить подзапросы комментариями, сделать имена псевдонимов действительно значимыми и указать, к какому подзапросу они относятся, например, innerCustomer, outerCustomer.

В некоторых случаях общие табличные выражения действительно могут помочьразбить запрос на значимые разделы.

...