powered by simpleCommunicator - 2.0.59     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сортировка
5 сообщений из 5, страница 1 из 1
Сортировка
    #32004627
Andrew
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Уважаемые господа, тут возник вопрос, связанный с сортировкой.

Имеется две таблицы:
Главная - Документы:
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 Док.КодДокумента = Дв.КодДокумента

Посмотрел я на это дело и решил спросить у вас совета. Нельзя ли сделать это проще, без ограничений на значения столбцов, и вообще менее монстроидально.
...
Рейтинг: 0 / 0
Сортировка
    #32004638
Такой простенький вариант
Вот это все
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), Дв.КодДвижения)

на далее по аналогии

Удачи
...
Рейтинг: 0 / 0
Сортировка
    #32004639
Andrew
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо, Дмитрий. Про replicate() я как то не подумал.
Но уточню вопрос. Мне не нравится сам путь по которому я шел.
Он подразумевает изначально ограничения на данные в полях. Например НомерПП не может быть больше 1000 (в моем примере).
Конечно вряд ли и 1000 кому-либо понадобится. Но тем не менее.
Хотелось бы из этих четырех полей сотворить нечто вроде поля контрольной суммы. И по нему отбирать и сортировать.
...
Рейтинг: 0 / 0
Сортировка
    #32004641
Fompro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если у Вас достаточно жёстко определён вес полей, то почему бы не воспользоваться конструкцией вида:
WHEN CONVERT(char( 8 ),Документы.ДатаДокумента,102)+ STR(Движения.КодДокумента)+STR(Движения.НомерПП)+STR(Движения.КодДвижения) LIKE CONVERT(char( 8 ),@ДатаДокумента,102) + ...
В SQL2000 Вы можете создать индекс для представления. В других случаях Вам может понадобиться ввести избыточность в таблицу Движения за счёт внесения поля ДатаДокумента (кстати, если Вы используете именно Дату, а не ДатуВремя, то Вы можете попробовать использовать представление даты как INT, т.е. NDate=CONVERT(int,CONVERT(char( 8 ),Документы.ДатаДокумента,102))
...
Рейтинг: 0 / 0
Сортировка
    #32004643
Andrew
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Еще одно уточнение. Пример: запрос 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 Вы можете создать индекс для представления
Индекс создан. Но вопрос скорее не в скорости выборки, а в упрощении написания запросов к Документы_Движения.

В любом случае, Спасибо.
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сортировка
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]