Как сделать сложные запросы SQL проще для написания? [закрыто]

42

Мне очень трудно писать сложные запросы SQL, включающие объединения по многим (как минимум 3-4) таблицам и включающие несколько вложенных условий. Запросы, которые меня просят написать, легко описываются несколькими предложениями, но для их завершения может потребоваться вводящее в заблуждение количество кода. Я часто использую временные представления для написания этих запросов, которые кажутся чем-то вроде опоры. Какие советы вы можете дать, чтобы я мог упростить эти сложные запросы? Более конкретно, как мне разбить эти запросы на шаги, которые мне нужно использовать, чтобы фактически написать код SQL?

Обратите внимание, что я SQL, который меня просят написать, является частью домашних заданий для курса по базе данных, поэтому я не хочу, чтобы программное обеспечение выполняло эту работу за меня. Я хочу понять код, который я пишу.

Более технические детали:

  • База данных размещается на сервере PostgreSQL, работающем на локальной машине.
  • База данных очень мала: не более семи таблиц, а самая большая таблица содержит менее 50 строк.
  • Запросы SQL передаются на сервер без изменений через LibreOffice Base.
bwDraco
источник
Временные представления на самом деле весьма полезны, так как вы можете что-то делать с такой таблицей (например, с явными сложными индексами), которую очень трудно намекнуть анализатору SQL.
Лично мне проще обмануть с помощью графического интерфейса пользователя (например, LibreOffice Base «Создать запрос в режиме конструктора» или Office Access «Создать»> «Дизайн запроса»), а затем просмотреть полученный SQL. Иногда необходимо изменить SQL, заданный дизайнером GUI, но это дает хорошую отправную точку
kurdtpage

Ответы:

49

Я основываю большую часть этого на попытках получить «правильный» ответ, чтобы вы могли обнаружить, что есть некоторые проблемы с производительностью. Нет смысла ускорять неправильный запрос.

Поймите отношения таблицы - большинство будет один ко многим. Знать таблицу «многие». Определите поля, необходимые для ваших объединений.

Подумайте о сценариях ЛЕВОГО присоединения - выберите всех сотрудников и их зарплату с прошлого месяца. Что если они не получили зарплату в прошлом месяце?

Знайте набор результатов: 1) В электронной таблице вручную введите хотя бы одну правильную запись для вашего запроса. 2) Напишите запрос в достаточно простой форме, чтобы определить, сколько записей должно быть возвращено. Используйте оба из них, чтобы проверить ваш запрос, чтобы убедиться, что присоединение к новой таблице не изменит результат.

Разбейте ваш запрос на управляемые части - вам не нужно писать все сразу. Сложные запросы иногда могут быть просто набором простых запросов.

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

Знайте, когда объединяться Иногда легче разделить подгруппы на свои собственные операторы выбора. Если у вас есть таблица, смешанная с менеджерами и другими сотрудниками, и в каждом столбце вы должны делать операторы Case, основанные на членстве в одной из этих групп, может быть проще написать запрос Manager и объединить его с запросом Employee. Каждый из них будет содержать свою собственную логику. Необходимость включать элементы из разных таблиц в разные строки - очевидное применение.

Сложные / вложенные формулы - Старайтесь последовательно делать отступы и не бойтесь использовать несколько строк. «Дело, когда дело, когда дело, когда» сводит вас с ума. Потратьте время, чтобы обдумать это. Сохраните сложные кальки для последнего. Получите правильные записи, выбранные в первую очередь. Затем вы атакуете сложные формулы, зная, что работаете с правильными значениями. Просмотр значений, используемых в формулах, поможет вам определить области, в которых необходимо учитывать значения NULL, и где обрабатывать ошибку деления на ноль.

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

JeffO
источник
1
Действительно отличный материал. Я хочу еще раз подчеркнуть точку зрения Джеффа на поиск левых соединений и разбиение сложных запросов на более мелкие, более управляемые и последующее их объединение. Я пишу большие запросы в больших базах данных почти каждый день, и эти две вещи, в частности, возникают постоянно. Всегда выполняйте свои запросы и подзапросы как можно скорее, чтобы убедиться, что вы получаете данные, которые ожидаете увидеть на каждом этапе.
CodexArcanum
@CodexArcanum - и когда вы запускаете запросы к большим данным, использование TOP не мешает;)
JeffO
Я согласен на каждое утверждение вашего предложения
Алессандро Росси
28
  1. Отступ будет первым делом, если вы еще этого не делаете. Он не только полезен даже для простых запросов, но и важен, когда речь идет о соединениях и запросах, которые немного сложнее, чем a select top 1 [ColumnName] from [TableName].

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

    Обратите внимание, что более длинные запросы (включая запросы с комментариями) означают более широкое использование полосы пропускания между сервером приложений и сервером базы данных. Также обратите внимание, что если вы не работаете с продуктом масштаба Google с огромным количеством запросов в секунду, требующим исключительной производительности и использования ресурсов, размер, добавленный комментариями, может ничего не изменить для вас с точки зрения производительности.

  3. Применение одного и того же стиля к таблицам, столбцам и т. Д. Также значительно улучшает читабельность. Когда наследство база данных таблиц PRODUCT, users, USERS_ObsoleteDONT_USE, PR_SHIPMENTSи HRhbYd_UU, кто - то делает что - то очень неправильно.

  4. Применение одного стиля к запросам также важно. Например, если вы пишете запросы для Microsoft SQL Server и решили использовать [TableName]вместо TableName, придерживайтесь его. Если после a вы переходите на новую строку select, делайте это не только в половине запросов, но во всех.

  5. Не используйте* , если нет веских причин для этого (например, if exists(select * from [TableName] where ...)в Microsoft SQL Server). Это не только *отрицательно влияет на производительность в некоторых (если не в большинстве) базах данных, но также не помогает разработчику, использующему ваш запрос. Таким же образом, разработчик должен получить доступ к значениям по имени, а не по индексу.

  6. Наконец, для выбора нет ничего плохого в предоставлении представления . Для чего-то еще, хранимые процедуры могут также использоваться в зависимости от проекта и людей, с которыми вы работаете.


People Некоторые люди ненавидят хранимые процедуры. Другим они не нравятся по нескольким (вполне обоснованным, по крайней мере для них) причинам.

² Ваши коллеги, другие ученики, ваш учитель и т. Д.

Арсений Мурзенко
источник
9

Немного в темноте, но если вы пишете много временных представлений, возможно, вы еще не осознали, что в большинстве мест вы можете поместить таблицу в оператор SQL, эту таблицу можно заменить запросом.

Таким образом, вместо присоединения таблицы A к временному представлению B вы можете присоединить таблицу A к запросу, который вы использовали в качестве временного представления B. Например:

    SELECT A.Col1, A.Col2, B.Col1,B.Col2
      FROM (SELECT RealTableZ.Col1, RealTableY.Col2, RealTableY.ID as ID
              FROM RealTableZ 
   LEFT OUTER JOIN RealTableY
                ON RealTableZ.ForeignKeyY=RealTableY.ID
             WHERE RealTableY.Col11>14
            ) As B
        INNER JOIN A
                ON A.ForeignKeyY=B.ID

Этот пример довольно бессмысленный, но должен объяснить синтаксис.

Для представлений, которые не являются «специальными» (проиндексированными, секционированными), это должно привести к тому же плану запросов, как если бы вы использовали представление.

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

Приношу свои извинения, если это уже старая шляпа для вас.

PSR
источник
3
Я довольно хорошо разбираюсь в SQL и действительно ненавижу этот отступ: он может выглядеть красиво, но совершенно бесполезно «по моему мнению». Две причины: я не могу четко понять, является ли это левое внешнее объединение частью основного запроса или частью подзапроса, ему нужен код, улучшающий код, и каждый раз, когда вы хотите добавить несколько строк, вам нужно заново украшать весь текст. , Отступ плана, который просто нуждается в TABS, гораздо более гибок. Я не опроверг ваш ответ, но я действительно отговариваю всех, кто использует этот стиль ... особенно, когда им нужна моя помощь.
Алессандро Росси
7

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

user281377
источник
1
Если вы используете cte, имейте в виду, что запрос сохраняется только до следующего запроса, поэтому в некоторых случаях, когда вы используете cte в нескольких запросах, для производительности лучше использовать временную таблицу.
Рэйчел
3
  1. Познакомьтесь с теорией множеств, если вы еще этого не сделали. SQL основан на теории множеств, и более глубокое понимание множеств поможет вам лучше понять, как работает SQL.
  2. Практикуйтесь больше в SQl: если вы только изучаете SQL, потребуется время, чтобы понять, как все делать, а некоторые просто займут время, прежде чем вы по-настоящему поймете их, объединения - отличный пример, чем больше вы их используете, тем лучше вы к нему подходите.
  3. Убедитесь, что запрашиваемые вами таблицы правильно оформлены
  4. Не бойтесь использовать представления для запросов на выборку, особенно если у вас есть общий набор, который нужно уточнять несколькими различными способами.
Ryathal
источник
1

Как и все остальное, вы хотите разбить проблему на управляемые части.

Кстати, именно так вы решаете сложные проблемы.

Итак: вы хотите проверить подзапрос, чтобы увидеть, что он действительно возвращает то, что вы хотите, прежде чем выполнять внешний запрос к нему. Вы хотите попробовать минимальное объединение каждой таблицы, в которую вы входите, чтобы убедиться, что вы действительно продумали все правильно. Такие вещи. Надеяться набрать все это и получить именно то, что вы хотите одним ударом, просто нереально.

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

Дэн Рэй
источник