Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Предлагаю начать составлять FAQ форума общими усилиями по следующим принципам - 1 вопрос FAQ - 1 топик - именовать каждый топик в виде FAQ. Наименование топика , для облегчения поиска и ссылок - в самом топике предлагать решение(я) , а обсуждение/споры вида "что есть более лучший способ решения данной проблемы" выносить в другие топики, за исключением указания явных ошибок, допущенных кем-либо из авторов.(это в равной мере касается и самой предложенной мной идеи о сотавлении FAQ) - внутри топика вести нумерацию способов решения в виде Способ No. - указывать версию сервера Попробую сделать это на наиболее часто задаваемом по моему мнению вопросе "Нумерация строк в запросе в MS SQL" Способ 1. С использованием временной таблицы - исходная таблица mytable должна иметь первичный ключ id CREATE TABLE #temp(new_id int identity, org_id int) INSERT INTO #temp(orig_id) SELECT id FROM mytable WHERE .... SELECT #temp.new_id, fields from original table FROM #temp INNER JOIN mytable ON #temp.orig_id = mytable.id Примечания. - если первичный ключ id в таблице mytable имеет опцию identity, то заполнение временной таблицы должно выглядеть так INSERT INTO #temp(orig_id) SELECT CAST(id AS int) AS id FROM mytable WHERE .... Плюсы - IMHO на больших таблицах наиболее быстрый способ Минусы - по сути дела один и тот же запрос выполняется 2 раза - временная таблица требует дополнительных ресурсов Версии сервера 2000, 7, (наверное и 6.5, но проверить не могу) Способ 2. - исходная таблица mytable должна иметь первичный ключ id SELECT (Select Sum(1) From mytable t1 Where t1.id <= t2.id) AS mynr, t2.* FROM mytable AS t2 Плюсы - один запрос Минусы - IMHO только для небольших таблиц Версии сервера 2000, 7, (наверное и 6.5, но проверить не могу) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.12.2001, 15:24 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Извини, Glory, при всем моем к тебе уважении, но у тебя написано и сумбурно, и кое-где неправильно. Впрочем, это IMHO. Вот моя статейка на эту тему, которую я по некоторым соображениям собирался пустить позже, но видно не судьба. ========================================================================================== В MSSQL не существует понятия «номер строки». Тем не менее, иногда возникает задача в получаемой выборке пронумеровать строки по порядку. Обычно это требуется в отчетах. Конечно, это обычно без труда реализуемо клиентскими средствами построения отчетов, однако номер по порядку можно реализовать и средствами T-SQL. Существует несколько способов пронумеровать строки по порядку в выборке. Все они имеют свои ограничения применения, достоинства и недостатки. Вариант 1 «Классический». Используется, когда в запросе, формирующем выборку, имеется сортировка по уникальному (в пределах выбираемых данных) полю. Имеем запрос: SELECT CityName, NumberOfPeople FROM Cities WHERE NumberOfPeople>100000 AND Country=’Russia’ ORDER BY CityName Номер строки добавляется подзапросом, подсчитывающим количество записей при тех же критериях и добавочному условию, что значение поля, по которому производится сортировка в главном запросе, в подзапросе меньше или равно значению поля в главном запросе. Получаем: SELECT (SELECT COUNT(*) FROM Cities C1 WHERE NumberOfPeople>100000 AND Country=’Russia’ AND CityName<=c.CityName) NumRow, CityName, NumberOfPeople FROM Cities c WHERE NumberOfPeople>100000 AND Country=’Russia’ ORDER BY CityName Важно в подзапросе повторить в точности критерии главного запроса, в данном случае «NumberOfPeople>100000 AND Country=’Russia’» и добавить условие «CityName<=с.CityName». Чтобы различать поля «CityName» главного запроса и подзапроса, необходимо табличке Cities задать псевдоним в подзапросе или в главном запросе. В данном случае псевдоним «c» задан в главном запросе. Главный недостаток этого метода в наличии подзапроса, который будет выполняться для каждой строки главного запроса. При выборке большого количества записей это может вылиться в плохую производительность. Другой недостаток в условии уникальности поля сортировки. Требование наличия предложения «ORDER BY» в запросе недостатком не является по той простой причине, что запросы для отчетов практически не бывают без этого предложения. Достоинство метода в его универсальности, академичности. Он не требует специфики T-SQL, этот метод можно применить практически на любом SQL-сервере. Вариант 2 «Эффективный, специфический для T-SQL». Этот вариант применим практически в любом случае, то есть не имеет ограничений и существенных недостатков. Идея такова: выборка производится во временную таблицу и добавляется поле с функцией «IDENTITY(INT,1,1)», а затем производится выборка уже из временной таблицы с сортировкой по этому новому полю. Функцию «IDENTITY(INT,1,1)» не путайте с выражением «IDENTITY(1,1)», это разные вещи. Вот так будет выглядеть запрос из предыдущего варианта с использованием «IDENTITY(INT,1,1)»: SELECT IDENTITY(INT,1,1) RowNum, CityName, NumberOfPeople INTO #tmp FROM Cities WHERE NumberOfPeople>100000 AND Country=’Russia’ ORDER BY CityName SELECT * FROM #tmp ORDER BY RowNum DROP TABLE #tmp Этот вариант очень удобно использовать внутри хранимой процедуры с предваряющей установкой «SET NOCOUNT ON». Начинающих разработчиков запросов на Transact-SQL обычно пугает необходимость использования временных таблиц. Они считают, что это существенные дополнительные накладные расходы. Однако, здесь это не так. Дело в том, что выборка с сортировкой перед отдачей клиенту все равно будет в большинстве случаев считана во временную табличку для произведения сортировки. Получается, что здесь мы явно лишь описали то, что сервер сделал бы неявно. Но явное описание считывания данных во временную табличку дало нам возможность дополнительно задать новое поле нумерации. При применении этого варианта необходимо учесть один момент. Если, среди полей выборки есть поле с признаком «IDENTITY», то такое поле необходимо «завернуть» в функцию «CONVERT», иначе будет сообщение об ошибке. Например, в данном запросе необходимо еще вывести поле City_Id, имеющее признак «IDENTITY». Тогда запрос будет выглядеть так: SELECT IDENTITY(INT,1,1) RowNum, CONVERT(int,City_Id) City_Id, CityName, NumberOfPeople INTO #tmp FROM Cities WHERE NumberOfPeople>100000 AND Country=’Russia’ ORDER BY CityName SELECT * FROM #tmp ORDER BY RowNum DROP TABLE #tmp Другие варианты. «Экзотические». Если выборка формируется построчно циклом внутри хранимой процедуры, то не составит труда добавить номер строки, просто увеличивая значение переменной на единичку с каждой итерацией цикла. Этот метод удобен только в том случае, если такой цикл, перебирающий все записи, уже присутствует. Специально организовывать цикл для задания номера строки крайне неэффективно. В MSSQL работает странная конструкция: «UPDATE … SET @VAR=SomeField=<expression>» Это можно использовать при необходимости пронумеровать сразу все строки в таблицы. Для этого само поле в таблице необходимо создать (в нижеприведенном примере необходимо наличие целочисленного поля RowNum в таблице Cities). А заполнить уникальными номерами по порядку можно так: DECLARE @var int UPDATE Cities SET @var=RowNum=IsNull(@var,0)+1 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.12.2001, 08:39 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Со своей стороны, обязуюсь отслеживать все такие темы и по мере их готовности (т.е. достижения консенсуса между автором(ами) и критически настроенной аудиторией) оформлять их в виде привычного глазу FAQ. Если посчитаете это полезным, могу размещать окончательные варианты тем в рассылке. Ваше мнение? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.12.2001, 10:21 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Да не сочтут уважаемые гуру за чрезмерное нахальство высказывание весьма и весьма начинающего! FAQ по-моему очень нужны (зачем, вы знаете лучше меня). Но пока его (FAQ) нет, как я узнаю степень банальности своего вопроса? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.12.2001, 11:12 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Где же FAQи?? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.02.2002, 12:19 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
А я жду мнения... как только дадите добро, сразу опубликую. Могу даже завтра, у меня как раз времени в обрез... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.02.2002, 15:29 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Время идёт, поправок и дополнений к этому FAQ нет... Может быть пора опубликовать в рассылке и на сайте? Я готов сделать редакторскую работу и после согласования с Глебом Уфимцевым и Glory опубликовать в виде статьи... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.04.2002, 10:24 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
За основу надо все-таки взять топик Глеба Уфимцева. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.04.2002, 06:33 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Я прошу прощения, но во втором способе возможно допущена синтаксическая ошибка: вместо SELECT IDENTITY(INT,1,1) RowNum, CityName, NumberOfPeople надо писать SELECT IDENTITY(INT,1,1) <strong>AS </strong>RowNum, CityName, NumberOfPeople Because this function creates a column in a table, a name for the column must be specified in the select list in one of these ways ("BOL") Или нет? От версии сервера это вряд ли зависит. По крайней мере мой SQL 7.0 ругнулся на первый вариант. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2003, 13:07 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Вот еще непонятность. Записи во временную таблицу вставляются без учета раздела ORDER BY выбираемых данных из оригинальной таблицы, что уничтожает всю ценность метода. Почему? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2003, 13:31 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
2 Axl Записи во временную таблицу вставляются без учета раздела ORDER BY выбираемых данных из оригинальной таблицы, что уничтожает всю ценность метода. ЧТо-то не верится. Приведите код, который дает такие результаты. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2003, 13:39 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Или нет? От версии сервера это вряд ли зависит. По крайней мере мой SQL 7.0 ругнулся на первый вариант. В SQL2000 работает без проблем. Да и согласно BOL Код: plaintext 1. 2. 3. 4. 5. 6. 7. наличие AS не обязательно ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2003, 13:43 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Порылся в форуме, вижу тема старая и так не решенная до конца. И главная загвоздка в том что для SQL 2000 порядке сортировка-вставка #tmp_table , а для 7.0 - вставка-сортировка . Glory предложил метод: Код: plaintext 1. 2. 3. 4. но у меня в разделе SELECT выбирается куча полей из связанных таблиц, и пока что у меня этод метод не работает. Вот текст процедуры: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2003, 14:32 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Ну а почему вариант Glory то у вас не работает? Перепишите свой запрос с использованием вложенного. Или создайте временную таблицу явно, вставьте туда записи с помощью INSERT...SELECT...ORDER BY... Во всяком случаи следующий вариант работает на ура: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.06.2003, 14:53 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Всё разобрался наконец-то... Guru Glory рекомендует к использованию запрос использующий так называемые derived table (динамические таблицы), формируемые в результате выполнения подзапроса в разделе FROM. Derived table входит в раздел FROM под alias(псевдоним), а поля этой таблицы входят в список полей основного раздела SELECT с указанием (или без указания) псевдонима динамической таблицы. Далее создается временная таблица при помощи INTO и т.д. Кроме того если в полях соединяемых таблиц присутствует NULL значения, то их нельзя вставить во временную таблицу, так как нарушается ограничение целостности NULL для полей временной таблицы, для которых не указано явно хранение NULL значений. Я попытался установить в процедуре хранение NULL, вызовом SET ANSI_NULL_DFLT_ON ON , но почему-то это не срабатывает. Поэтому я просто преобразовал NULL в 0 используя конструкцию CASE...WHEN..ELSE Что касается второго варианта то он безусловно выполним, только для каждой выборки нужно поднимать и описывать домены атрибутов, что создает дополнительные трудности, если проект был плохо документирован и создается "на коленке". И последнее. Я не знаю как там с точки зрения семантики, но всё же мне кажется указание alias при помощи ключевого слова AS , делает запрос более понятным. По крайней мере мне было трудно догадаться что означает (SELECT * FROM tbl) S пока я не залез в описание параметра derived table в BOL. На всякий случай привожу финальный код своего запроса Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.06.2003, 10:27 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Кроме того если в полях соединяемых таблиц присутствует NULL значения, то их нельзя вставить во временную таблицу, так как нарушается ограничение целостности NULL для полей временной таблицы, для которых не указано явно хранение NULL значений. Вот насчет этого не понял. Кроме того, по-моему тащить все поля из оригинальной таблицы во временную нецелесообразно. Достаточно будет и первичного ключа (могут конечно быть и исключения). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.06.2003, 10:50 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Вот насчет этого не понял. Я и сам не во всем разобрался, почему создаваемая временная таблица не принимает ограничения целостности полей выборки. Но факт есть факт - если в перетаскиваемом поле есть записи с NULL значениями, то запрос не выполняется и выбрасывает ошибку: <!-- Cannot insert the value NULL into column 'PhotoId', table 'tempdb.dbo.#tmp _________00010000020B'; column does not allow nulls. INSERT fails. --!> Кроме того, по-моему тащить все поля из оригинальной таблицы во временную нецелесообразно. А вот здесь я не понял. Как результат выполнения запроса необходима нумерованная выборка из связанных таблиц, а не просто последовательность в которой эти строки могли выдаются. Или выгоднее будет перетащить во временную таблицу только первичный ключ, потом сделать ещё одну выборку в которой будет дополнительная связь с временной таблицей? Кстати Query Analyzer ведь автоматически нумерует строки в Grides... Как он с этим справляется? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.06.2003, 06:53 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
если в перетаскиваемом поле есть записи с NULL значениями, то запрос не выполняется и выбрасывает ошибку: Вы имеете ввиду запрос такого типа ???? SELECT IDENTITY(INT,1,1) RowNum, CityName, NumberOfPeople INTO #tmp FROM Cities WHERE NumberOfPeople>100000 AND Country=’Russia’ ORDER BY CityName Или вы заранее создате таблицу #tmp ?? выгоднее будет перетащить во временную таблицу только первичный ключ, потом сделать ещё одну выборку в которой будет дополнительная связь с временной таблицей? Думаю именно так. Особено при многочисленных коннектах. Да и проще будет при изменении структуры основной таблицы. Хотя, как я сказал выше, решать нужно исходя из результатов кокретных тестов. Кстати Query Analyzer ведь автоматически нумерует строки в Grides... Как он с этим справляется? Я думаю нумерует уже на стороне клиента. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.06.2003, 10:34 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Как вписать в новосоздаваемую таблицу, в поле ID(которое уже существует), значение которое должно быть просто уникальным числом, например номером строки, притом осталные поля копируются из другой таблицы при помощи insert tab1(a,b,c,d) select from tab2(e,f,g,h) Нужно чтобы номера вставлялись во время копирования, т.к. ID не может быть NULL. КАК ЭТО СДЕЛАТЬ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.06.2003, 14:25 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
create tab1(x int identity, a int, b int, c int, d int) go insert tab1(a,b,c,d) select from tab2(e,f,g,h) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 05.06.2003, 16:50 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Извеняюсь немного не там написал, создал тему в /topic/508546&pg=-1 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.12.2007, 09:43 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Glory Примечания.- если первичный ключ id в таблице mytable имеет опцию identity, то заполнение временной таблицы должно выглядеть так INSERT INTO #temp(orig_id) SELECT CAST(id AS int) AS id FROM mytable WHERE .... Не могу понять сокровенный смысл CAST(id AS int) AS id . Имхо надо или требовать идентичности #temp.orig_id с mytable.id или (например для #temp.orig_id bigint) все равно CAST не поможет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.12.2007, 10:27 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
>Автор: KGP >Не могу понять сокровенный смысл CAST(id AS int) AS id. >... и всего-то шесть лет с тех пор прошло Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.12.2007, 10:36 |
|
||
|
FAQ.Нумерация записей в запросе
|
|||
|---|---|---|---|
|
#18+
Glory, Пример реализации с помощью ROW_NUMBER в MS SQL Server 2005+: drop table #temp create table #temp ( name varchar(50) ) insert into #temp values('берёзка') insert into #temp values('ясень') insert into #temp values('осина') SELECT ROW_NUMBER() OVER(ORDER BY [name] ASC) AS Row ,[name] from #temp Читать про ROW_NUMBER здесь ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2012, 14:45 |
|
||
|
|

start [/forum/topic.php?fid=46&tid=1700791]: |
0ms |
get settings: |
10ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
39ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
57ms |
get tp. blocked users: |
1ms |
| others: | 15ms |
| total: | 156ms |

| 0 / 0 |
