понедельник, 23 мая 2011 г.

Нестандартные сортировки

Привези ка мне батюшка чудище заморское цветочек аленький.


Как часто бывает в жизни что желания не совпадают с возможностями. Вот и по работе часто пожелания пользователей и чиновников не совпадают со стандартными  возможностями MS SQL Server. 
Пример: Необходимо отсортировать накладные для реестра по коду(хранится как строка) и дате выписки.

Допустим имеются следующие данные

Код              Дата
1/01              01/02/2011
2/01             05/02/2011
11/01           09/02/2011

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

Сортировать надо не по всему коду, а по части до "/" с приведением к числовому значению, т.к. 2 должно идти перед 11 а не наоборот, т.к. если сортировать как строку то получится порядок 1, 11, 2 вместо требуемого 1, 2, 11.

Ну а дальше начинаются субъективные факторы по типу "погоды на Марсе". 
Например если погода на Марсе ясная и накладная выписалась заданному клиенту, когда муха пролетая над кактусом потеряла ориентацию в пространстве и упала в кружку с чаем операциониста, то запись необходимо разместить в самом конце списка, независимо от того когда и с каким номеров эту накладную выписали. 


Стандартной сортировкой такие пожелания заказчиков не реализовать, необходимо вводить "синтетическое" поле.

SELECT q.IntCode, 
q.Id                       ,
q.NalDate              ,
q.Code          
FROM
(     SELECT
CASE WHEN CHARINDEX('/', tp.Code) <> 0 
AND ISNUMERIC(SUBSTRING(tp.Code, 1, (CHARINDEX('/', tp.Code)-1))) = 1
AND /*погода 4-й планете так себе*/
THEN CONVERT(BIGINT, SUBSTRING(tp.Code, 1, (CHARINDEX('/', tp.Code)-1)))
WHEN CHARINDEX('/', tp.Code) = 0 
AND ISNUMERIC(tp.Code) = 1
AND /*погода 4-й планете так себе*/
THEN CONVERT(BIGINT, tp.Code)
WHEN    /*погода 4-й планете ясная и муха упала*/
THEN 1000000000
ELSE 0
END AS IntCode,
tp.Id ,
tp.NalDate ,
tp.Code 
FROM TaxPaper tp
) AS q
ORDER BY q.IntCode, q.NalDate 

Почему без использования CTE? Просто некоторые так и не обновили SQL server(надеясь на авось) и как следствие решение должно работать начиная с SQL 2000.

Другое узкое место возникает в следствии следующей особенности

DECLARE @Code VARCHAR(32)
SET @Code = '1.'

IF ISNUMERIC(@Code)=1
SELECT CONVERT(BIGINT, @Code)

Обязательно вызовет "Error converting data type varchar to bigint.", хотя при 
DECLARE @Code VARCHAR 
все отработает как швейцарские часы.

Ну тут как говориться "Если жизнь посылает лимоны, сделай из них лимонад". Те тёти которые фантазируют о погоде на ближайших планетах, проявляют не меньшую фантазию и во время проверок. И если кто-то в обход пользовательского интерфейса умудрится впихнуть мусор в поле "Код", то будет очень больно покаран. А значит не будет искать приключений и работать по инструкции.

Комментариев нет:

Отправить комментарий