Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Сортировка
|
|||
|---|---|---|---|
|
#18+
Уважаемые господа, тут возник вопрос, связанный с сортировкой. Имеется две таблицы: Главная - Документы: CREATE TABLE Документы (КодДокумента int IDENTITY (1, 1) NOT NULL, ДатаДокумента date time NOT NULL, ТипДокумента int NULL) Подчиненная - Движения: CREATE TABLE Движения ( КодДвижения int IDENTITY (1, 1) NOT NULL , КодДокумента int NULL , НомерПП int NULL ,КодОбъекта int NULL , Количество numeric(19, 3) NULL) Таблицы связаны по полю КодДокумента. Отношение 1-N. Для последующей работы создано представление: CREATE VIEW Документы_Движения AS SELECT TOP 100 PERCENT Документы.ТипДокумента, Документы.ДатаДокумента, Движения.КодДокумента, Движения.НомерПП, Движения.КодДвижения, Движения.КодОбъекта, Движения.Количество FROM Документы INNER JOIN Движения ON Документы.КодДокумента = Движения.КодДокумента ORDER BY Документы.ДатаДокумента, Движения.КодДокумента, Движения.НомерПП, Движения.КодДвижения Наличие четырех полей, определяющих порядок движений крайне затрудняет работу с представлением. Например, в каждом запросе, производящем отбор движений необходимо использовать условие типа: WHERE ((ДатаДокумента < @ДатаДокумента) OR ((ДатаДокумента = @ДатаДокумента) AND (КодДокумента < @КодДокумента)) OR ((ДатаДокумента = @ДатаДокумента) AND (КодДокумента = @КодДокумента) AND (НомерПП < @НомерПП)) OR ((ДатаДокумента = @ДатаДокумента) AND (КодДокумента = @КодДокумента) AND (НомерПП = @НомерПП) AND (КодДвижения < @КодДвижения))). А то и несколько подобных условий Задача: каким образом превратить эту совокупность полей в одно поле, по которому производить сортировку и отбор по условию? При первом рассмотрении возникла идея изменить предыдущее представление таким образом (некоторые поля опущены): SELECT TOP 100 PERCENT Док.ТипДокумента, Док.ДатаДокумента, Дв.КодДокумента, Дв.НомерПП, Дв.КодДвижения, convert (varchar(10), convert(bigint, convert(numeric(10, 5), Док.ДатаДокумента) * 100000)) + case when Дв.КодДокумента>=1 And Дв.КодДокумента<10 then '00000'+convert(varchar(6),Дв.КодДокумента) when Дв.КодДокумента>=10 And Дв.КодДокумента<100 then '0000'+convert(varchar(6),Дв.КодДокумента) when Дв.КодДокумента>=100 And Дв.КодДокумента<1000 then '000'+convert(varchar(6),Дв.КодДокумента) when Дв.КодДокумента>=1000 And Дв.КодДокумента<10000 then '00'+convert(varchar(6),Дв.КодДокумента) when Дв.КодДокумента>=10000 And Дв.КодДокумента<100000 then '0'+convert(varchar(6),Дв.КодДокумента) when Дв.КодДокумента>=100000 And Дв.КодДокумента<1000000 then convert(varchar(6),Дв.КодДокумента) end + case when Дв.НомерПП>=1 And Дв.НомерПП<10 then '00'+convert(varchar(3),Дв.НомерПП) when Дв.НомерПП>=10 And Дв.НомерПП<100 then '0'+convert(varchar(3),Дв.НомерПП) when Дв.НомерПП>=100 And Дв.НомерПП<1000 then convert(varchar(3),Дв.НомерПП) end + case when Дв.КодДвижения>=1 And Дв.КодДвижения<10 then '00000000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=10 And Дв.КодДвижения<100 then '0000000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=100 And Дв.КодДвижения<1000 then '000000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=1000 And Дв.КодДвижения<10000 then '00000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=10000 And Дв.КодДвижения<100000 then '0000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=100000 And Дв.КодДвижения<1000000 then '000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=1000000 And Дв.КодДвижения<10000000 then '00'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=10000000 And Дв.КодДвижения<100000000 then '0'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=100000000 And Дв.КодДвижения<1000000000 then convert(varchar(9),Дв.КодДвижения) end AS Сортировка FROM dbo.Документы Док INNER JOIN dbo.Движения Дв ON Док.КодДокумента = Дв.КодДокумента Посмотрел я на это дело и решил спросить у вас совета. Нельзя ли сделать это проще, без ограничений на значения столбцов, и вообще менее монстроидально. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.04.2001, 04:30 |
|
||
|
Сортировка
|
|||
|---|---|---|---|
|
#18+
Такой простенький вариант Вот это все when Дв.КодДвижения>=1 And Дв.КодДвижения<10 then '00000000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=10 And Дв.КодДвижения<100 then '0000000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=100 And Дв.КодДвижения<1000 then '000000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=1000 And Дв.КодДвижения<10000 then '00000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=10000 And Дв.КодДвижения<100000 then '0000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=100000 And Дв.КодДвижения<1000000 then '000'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=1000000 And Дв.КодДвижения<10000000 then '00'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=10000000 And Дв.КодДвижения<100000000 then '0'+convert(varchar(9),Дв.КодДвижения) when Дв.КодДвижения>=100000000 And Дв.КодДвижения<1000000000 then convert(varchar(9),Дв.КодДвижения) заменить на replicate ( '0' , 9 - len( convert( varchar(9), Дв.КодДвижения ) ) ) + convert(varchar(9), Дв.КодДвижения) на далее по аналогии Удачи ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.04.2001, 17:57 |
|
||
|
Сортировка
|
|||
|---|---|---|---|
|
#18+
Спасибо, Дмитрий. Про replicate() я как то не подумал. Но уточню вопрос. Мне не нравится сам путь по которому я шел. Он подразумевает изначально ограничения на данные в полях. Например НомерПП не может быть больше 1000 (в моем примере). Конечно вряд ли и 1000 кому-либо понадобится. Но тем не менее. Хотелось бы из этих четырех полей сотворить нечто вроде поля контрольной суммы. И по нему отбирать и сортировать. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.04.2001, 19:15 |
|
||
|
Сортировка
|
|||
|---|---|---|---|
|
#18+
Если у Вас достаточно жёстко определён вес полей, то почему бы не воспользоваться конструкцией вида: WHEN CONVERT(char( 8 ),Документы.ДатаДокумента,102)+ STR(Движения.КодДокумента)+STR(Движения.НомерПП)+STR(Движения.КодДвижения) LIKE CONVERT(char( 8 ),@ДатаДокумента,102) + ... В SQL2000 Вы можете создать индекс для представления. В других случаях Вам может понадобиться ввести избыточность в таблицу Движения за счёт внесения поля ДатаДокумента (кстати, если Вы используете именно Дату, а не ДатуВремя, то Вы можете попробовать использовать представление даты как INT, т.е. NDate=CONVERT(int,CONVERT(char( 8 ),Документы.ДатаДокумента,102)) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.04.2001, 20:11 |
|
||
|
Сортировка
|
|||
|---|---|---|---|
|
#18+
Еще одно уточнение. Пример: запрос c целью получения всех движений, произошедших до конкретного движения. set @ДатаДокумента=(select ДатаДокумента from Документы_Движения where КодДвижения=@КодДвижения) set @КодДокумента =(select КодДокумента from Документы_Движения where КодДвижения=@КодДвижения) set @НомерПП =(select НомерПП from Документы_Движения where КодДвижения=@КодДвижения) SELECT * FROM Документы_Движения WHERE ((ДатаДокумента < @ДатаДокумента) OR ((ДатаДокумента = @ДатаДокумента) AND (КодДокумента < @КодДокумента)) OR ((ДатаДокумента = @ДатаДокумента) AND (КодДокумента = @КодДокумента) AND (НомерПП < @НомерПП)) OR ((ДатаДокумента = @ДатаДокумента) AND (КодДокумента = @КодДокумента) AND (НомерПП = @НомерПП) AND (КодДвижения < @КодДвижения))). Используя поле Сортировка: set @Сортировка=(select Сортировка from Документы_Движения where КодДвижения=@КодДвижения) SELECT * FROM Документы_Движения WHERE Сортировка < @Сортировка Т.е много проще. НО поле Сортировка у меня получилось путем конкатенации 4 полей, преобразованых в varchar. И способ этого преобразования подразумевает наложение ограничений на поля КодДокумента, НомерПП и КодДвижения. Что мне здорово не нравится. А хотелось бы получить поле Сортировка путем неких <b>математических преобразований</b>, что сняло бы все ограничения на поля и кроме того ускорило бы сортировку (особенно, если не выходить за рамки bigint) 2Fompro: >если Вы используете именно Дату, а не ДатуВремя Поле ДатаДокумента у меня datetime, потому и использую для преобразования в varchar convert (varchar(10), convert(bigint, convert(numeric(10, 5), Док.ДатаДокумента) * 100000)) >WHEN CONVERT(char( 8 ),Документы.ДатаДокумента,102)+ STR(Движения.КодДокумента)+STR(Движения.НомерПП)+STR(Движения.КодДвижения) LIKE CONVERT(char( 8 ),@ДатаДокумента,102) + ... Если честно, не понял. >В SQL2000 Вы можете создать индекс для представления Индекс создан. Но вопрос скорее не в скорости выборки, а в упрощении написания запросов к Документы_Движения. В любом случае, Спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.04.2001, 22:50 |
|
||
|
|

start [/forum/topic.php?fid=46&msg=32004638&tid=1826943]: |
0ms |
get settings: |
12ms |
get forum list: |
15ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
25ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
47ms |
get tp. blocked users: |
1ms |
| others: | 256ms |
| total: | 373ms |

| 0 / 0 |
