Подтвердить что ты не робот

ANSI присоединяется к "where clause"

Я развиваюсь против баз данных Oracle. Когда мне нужно писать вручную (не использовать ORM, например, спящий режим), я помещаю утверждения объединения в разделы предложения where.

например (это упрощает только для иллюстрации стиля):

Select *
from customers c, invoices i, shipment_info si
where c.customer_id = i.customer_id
    and i.amount > 999.99 
    and i.invoice_id = si.invoice_id(+)  -- added to show how outer joins can be supported in this style
order by i.amount, c.name

Я изучил этот стиль из OLD Oracle DBA. С тех пор я узнал, что это не стандартный синтаксис SQL. Помимо нестандартных и гораздо менее портативных баз данных, есть ли какие-либо другие последствия для использования этого формата?

Спасибо, Джей

4b9b3361

Ответ 1

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

Ответ 2

Мне не нравится стиль, потому что это затрудняет определение того, какие предложения WHERE предназначены для имитации JOINs, а какие для реальных фильтров, и мне не нравится код, который делает излишне трудным определить первоначальное намерение программиста.

Ответ 3

Самая большая проблема, с которой я столкнулся с этим форматом, - это тенденция забыть о каком-то соединении с предложением WHERE, что приводит к декартовому продукту. Это особенно часто (для меня, по крайней мере) при добавлении новой таблицы в запрос. Например, предположим, что таблица ADDRESSES бросается в микс, и ваш ум немного забывчив:

SELECT *
  FROM customers c, invoices i, addresses a
 WHERE c.customer_id = i.customer_id
   AND i.amount > 999.99
 ORDER BY i.amount, c.name

Boom! Декартово произведение!:)

Ответ 4

В некоторых случаях объединение старого стиля ошибочно (внешние соединения являются виновниками). Хотя они более или менее эквивалентны при использовании внутренних объединений, они могут генерировать неверные результаты с внешними соединениями, особенно если столбцы на внешней стороне могут быть нулевыми. Это связано с тем, что при использовании более старого синтаксиса условия соединения не логически оцениваются до тех пор, пока не будет создан весь результирующий набор, просто невозможно выразить условие для столбца с внешней стороны соединения, которое будет фильтровать записи, когда столбец может быть нулевым, потому что нет соответствующей записи.

В качестве примера:

Выберите все Клиенты и сумму продаж Виджеты на всех своих счетах в месяце Август, где был обработан Счет (Invoice.ProcessDate Не > Null)

с использованием нового синтаксиса соединения ANSI-92

 Select c.name, Sum(d.Amount)
 From customer c
    Left Join Invoice I 
        On i.custId = c.custId
            And i.SalesDate Between '8/1/2009' 
                      and '8/31/2009 23:59:59'
            And i.ProcessDate Is Not Null
    Left Join InvoiceDetails d 
        On d.InvoiceId = i.InvoiceId
            And d.Product = 'widget'
 Group By c.Name

Попробуйте сделать это со старым синтаксисом... Поскольку при использовании синтаксиса старого стиля все условия в предложении where оцениваются/применяются до того, как добавляются "внешние" строки, все строки UnProcessed Invoice будут добавлены вернуться к окончательному набору результатов... Таким образом, это невозможно при использовании старого синтаксиса - все, что пытается отфильтровать счета-фактуры с нулевыми обработанными датами, устранит клиентов... единственной альтернативой является использование коррелированного подзапроса.

Ответ 5

С тех пор я узнал, что это не стандартный синтаксис SQL.

Это не совсем так. Синтаксис "a,b where" соответствует стандарту ansi-89, синтаксис "a join b on" - ansi-92. Однако синтаксис 89 устарел, а это значит, что вы не должны использовать его для новых запросов.

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

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

Ответ 6

Это стандартный синтаксис SQL, более старый стандарт, чем JOIN. Там причина, по которой синтаксис развился, и вы должны использовать новый синтаксис JOIN, потому что:

  • Это более выразительно, четко указывая, какие таблицы JOINED, порядок JOIN, какие условия применимы к JOIN и отделяют условия фильтрации WHERE от условий JOIN.

  • Он поддерживает LEFT, RIGHT и FULL OUTER JOINs, которые синтаксис WHERE не поддерживает.

Я не думаю, что вы найдете JOIN типа WHERE существенно менее портативным, чем синтаксис JOIN.

Ответ 7

Пока вы не используете функцию естественного соединения ANSI, я в порядке с ней.

Я нашел эту цитату - ScottCher, я полностью согласен:

Я нахожу синтаксис WHERE более легким для чтения, чем INNER JOIN - я думаю, это похоже на Vegemite. Большинство людей в мире, вероятно, считают это отвратительным, но дети воспитывают его, любят его.

Ответ 8

Это действительно зависит от привычек, но я всегда считаю, что синтаксис с разделителями запятой Oracle более естественный. Первая причина в том, что я думаю, что использование (INNER) JOIN уменьшает читаемость. Вторая - гибкость. В конце концов, объединение является декартовым произведением по определению. Вам не обязательно ограничивать результаты на основе идентификаторов обеих таблиц. Хотя очень редко, может потребоваться декартово произведение двух таблиц. Ограничение их на основе идентификаторов - это очень разумная практика, но НЕ ПРАВИЛО. Однако, если вы используете ключевое слово JOIN, например. SQL Server, он не позволит вам опустить ключевое слово ВКЛ. Предположим, вы хотите создать список комбинаций. Вы должны сделать вот так:

SELECT *
FROM numbers
JOIN letters
ON 1=1

Кроме того, я считаю, что синтаксис (+) Oracle также очень разумен. Это хороший способ сказать: "Добавьте эту запись в результирующий набор, даже если он равен нулю". Это лучше, чем синтаксис RIGHT/LEFT JOIN, потому что на самом деле нет ни левого, ни правого! Если вы хотите присоединиться к 10 таблицам с несколькими различными типами внешних соединений, это путает, какая таблица находится на "левой стороне", а какая - справа.

Кстати, как более общий комментарий, я не думаю, что переносимость SQL существует в практическом мире. Стандартный SQL настолько низок, и столь часто требуется выразительность различного синтаксиса СУБД, я не думаю, что 100% -ый переносимый SQL-код является достижимой целью. Наиболее очевидным свидетельством моего наблюдения является старая строка проблема. Просто найдите любой форум для " номер строки sql, включая SO, и вы увидите сотни сообщений о том, как это можно достичь в конкретной СУБД. Аналогично и, следовательно, ограничивает количество возвращенных строк, например..

Ответ 9

Это синтаксис Transact SQL, и я не совсем уверен, что это "unportable" - это основной синтаксис, используемый в Sybase (например, Sybase поддерживает синтаксис ANSI), а также многие другие базы данных (if не все).

Основными преимуществами синтаксиса ANSI являются то, что он позволяет вам писать некоторые довольно сложные соединения, которые T-SQL запрещает

Ответ 10

Собственно, этот синтаксис более переносимый, чем JOIN, потому что он будет работать практически с любой базой данных, в то время как не все поддерживают синтаксис JOIN (например, Oracle Lite, например [если это не изменилось в последнее время]).