объясните логику? [MSSQL]
От: Kaifa Россия  
Дата: 10.06.19 16:52
Оценка:
почему

select top 1 * from (
    select top 3 val 
    from #t
    order by val
) s
order by s.val desc


можно, а

select top 1 * from (
    select val 
    from #t
    order by val
) s
order by s.val desc


выдаст ошибку? какая ему разница?
Re: объясните логику? [MSSQL]
От: Джеффри  
Дата: 10.06.19 17:12
Оценка: 17 (4) +1
Здравствуйте, Kaifa, Вы писали:

K>выдаст ошибку? какая ему разница?


Во втором случае ORDER BY не нужен, т.к. не влияет на результат запроса никаким образом, в отличии от примера с ТОП. Но при обработке такой конструкции у engine-а будет такой выбор — проигнорировать ее (мне кажется, что так происходит в некоторых СУБД), тупо исполнить (что бессмысленно), выдать ошибку (как происходит в T-SQL).

Рискну предположить, что Майкрософт выбрала последний вариант для большей надежности, чтобы разработчики не оставляли ненужные строки (которые все равно не будут выполняться) и чтобы не было случайных ошибок (когда ORDER BY по ошибке прописали внутри подзапроса).

Кто-нибудь ведь напишет:

select top 1 * from (
    select val 
    from #t
    order by val
) s


А потом будет жаловаться, что случайная строка возвращается...
Отредактировано 10.06.2019 17:14 Джеффри . Предыдущая версия .
Re[2]: объясните логику? [MSSQL]
От: okon  
Дата: 10.06.19 17:19
Оценка:
Д>Кто-нибудь ведь напишет:

Д>
Д>select top 1 * from (
Д>    select val 
Д>    from #t
Д>    order by val
Д>) s
Д>


Д>А потом будет жаловаться, что случайная строка возвращается...


Не понятно почему должно вернуть случайную строку.
    select val 
    from #t
    order by val


допустим если оно возвращает случаную строку, то почему с top 3 не будет случайного поведения ?

    select top 3 val 
    from #t
    order by val
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[3]: объясните логику? [MSSQL]
От: vmpire Россия  
Дата: 10.06.19 17:27
Оценка:
Здравствуйте, okon, Вы писали:

O>Не понятно почему должно вернуть случайную строку.

O>
O>    select val 
O>    from #t
O>    order by val
O>


Потому, что val может не уникально идентифицировать строку


O>допустим если оно возвращает случаную строку, то почему с top 3 не будет случайного поведения ?


O>
O>    select top 3 val 
O>    from #t
O>    order by val
O>


Тоже будет случайное. Но это известная бага.
Которая часто применялась как лайфхак в ворме "select top 100%" (или как-то так), чтобы выбрать-таки случайную строку.
Re[3]: объясните логику? [MSSQL]
От: Джеффри  
Дата: 10.06.19 17:41
Оценка:
Здравствуйте, okon, Вы писали:

O>Не понятно почему должно вернуть случайную строку.

O>
O>    select val 
O>    from #t
O>    order by val
O>


SQL Server не гарантирует, какие строки будут возвращены для запросов с ТОП но без ORDER BY.

When you use TOP with the ORDER BY clause, the result set is limited to the first N number of ordered rows. Otherwise, TOP returns the first N number of rows in an undefined order.


Т.е. запрос SELECT TOP 3 * FROM Table, может вернуть любые 3 строки из таблицы. Тоже самое для запроса SELECT TOP 3 * FROM Subquery

Т.е. насколько я понимаю SQL Server просто не заморачивается о порядке сортировки в источнике данных и требует чтобы порядок был явно указан в ORDER BY, а иначе можно получить что угодно.

O>допустим если оно возвращает случаную строку, то почему с top 3 не будет случайного поведения ?


O>
O>    select top 3 val 
O>    from #t
O>    order by val
O>


В этом запросе нет неопределенности — SQL Server четко понимает, что ему нужно взять 3 строки с минимальным значением val, а потом еще раз одну строку с минимальным val из этих 3-х строк. Правда, если будет выбираться больше одного поля и могут быть повторяющиеся значения val, то снова могут возникнуть неопределенности, но не в данном примере.
Re[4]: объясните логику? [MSSQL]
От: okon  
Дата: 10.06.19 17:53
Оценка:
Д>SQL Server не гарантирует, какие строки будут возвращены для запросов с ТОП но без ORDER BY.
Д>

Д>When you use TOP with the ORDER BY clause, the result set is limited to the first N number of ordered rows. Otherwise, TOP returns the first N number of rows in an undefined order.

Д>Т.е. запрос SELECT TOP 3 * FROM Table, может вернуть любые 3 строки из таблицы. Тоже самое для запроса SELECT TOP 3 * FROM Subquery

Но в рассматриваемом примере есть order by в обоих случаях, т.е. должен быть определен порядок.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[5]: объясните логику? [MSSQL]
От: Джеффри  
Дата: 10.06.19 18:26
Оценка:
Здравствуйте, okon, Вы писали:

O>Но в рассматриваемом примере есть order by в обоих случаях, т.е. должен быть определен порядок.


Это зависит от того, как реализовать оператор ORDER BY в подзапросах. Если его проигнорировать, как я написал, т.к. он не имеет смысла (например, для запросов вида SELECT * FROM X WHERE ID IN (SELECT ID FROM Y ORDER BY ID))), то row set из подзапроса не будет отсортирован.

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

Представь еще, если я наверну конструцию вроде — гарантировать в этом случае порядок сортировки или нет?

select top 1 * from (
    select * from (select val 
    from #t
    order by val) a
) s



Все это усложнит engine — и ради чего? Проще разрешить ORDER BY там, где он необходим и его поведение четко определено...
Re: объясните логику? [MSSQL]
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 10.06.19 20:00
Оценка: 2 (1)
Здравствуйте, Kaifa, Вы писали:

K>почему


K>
K>select top 1 * from (
K>    select top 3 val 
K>    from #t
K>    order by val
K>) s
K>order by s.val desc
K>


K>можно, а


K>
K>select top 1 * from (
K>    select val 
K>    from #t
K>    order by val
K>) s
K>order by s.val desc
K>


K>выдаст ошибку? какая ему разница?


В подзапросах order by разрешен только для Top так как там реально отбираются количество записей по сортировке.
Во втором случае order by просто не нужен ибо сортировка указывается во внешнем запросе.
А раз он не нужен, то не стоит и указывать.
и солнце б утром не вставало, когда бы не было меня
Re: объясните логику? [MSSQL]
От: _ABC_  
Дата: 11.06.19 06:07
Оценка:
Здравствуйте, Kaifa, Вы писали:

K>выдаст ошибку? какая ему разница?

Чисто ИМХО — исторически сложилось. По умолчанию, order by вообще не был обязан поддерживаться "голым" ANSI SQL нигде, кроме как в курсорах. "Select top" вообще нет в ANSI SQL.

Так что оба конструкта в своё время вводились чисто как расширение T-SQL. Это уже позже, в версии стандарта 2008 ввели опциональные фичи, в том числе по order by в подзапросе, в селекте верхнего уровня, во вью и т.д. До этого они были чисто T-SQL (ну и в каких-то других диалектах тоже). При этом order by в подзапросах в T-SQL вводили исключительно как производную от select top, чтобы можно было выбрать нужные версии этого самого top, а не как самостоятельный конструкт. Именно поэтому order by дает ошибку без top.

Это чистое ИМХО, основанное на логике.
Re: объясните логику? [MSSQL]
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.06.19 09:24
Оценка: 2 (1)
Здравствуйте, Kaifa, Вы писали:

K>почему


K>
K>select top 1 * from (
K>    select top 3 val 
K>    from #t
K>    order by val
K>) s
K>order by s.val desc
K>


K>можно,

Потому что у этого запроса есть понятная семантика. "верни мне первый-с-конца среди первых-трёх-сначала", т.е. возвращается строчка №3 при сортировке t# по возрастанию val.
Все части запроса тут обязательны, каждая играет свою роль.

K>
K>select top 1 * from (
K>    select val 
K>    from #t
K>    order by val
K>) s
K>order by s.val desc
K>

K>выдаст ошибку?
Потому что здесь внутренний order by гарантированно избыточен. Скорее всего, это признак того, что разработчик хотел написать что-то другое. Например, он забыл сделать top N во внутреннем запросе.
Если разработчик точно не хотел этого делать, то пусть уберёт бессмысленный order by.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.