Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > MS SQL Server > Сортировка строки как числа


Автор: Komatoz 28.2.2008, 10:22
Есть поле House (№дома) - текстовое..

Его надо отсортировать так, чтобы было попорядку, а не

1
10
100
100А
197
197А
19Б
2
20
200

Код

select distinct House from Tabl order by ???

Автор: Itsys 28.2.2008, 10:45
А как вариант дополнительной колонки (decimal) и повесить тригер, который определяет последний символ число или нет, и если нет - то меняет А на .1, Б на .2, в на .3 и т.д. и конвертирует в число и запихивает его в эту колонку, а, дальше сортировать по ней?

Автор: Akina 28.2.2008, 10:57
Если бы буквы хранились в отдельной колонке (HouseNumber-HouseDigit), то
Код

Order By Cast(HouseNumber As BigInt)

Однако при наличии буквы функция даст ошибку.
Полагаю наиболее разумным изменение структуры, а если это невозможно - написание хранимой функции конвертации. Скажем, по описанному Itsys алгоритму. 

Автор: Komatoz 28.2.2008, 11:00
Уже несколько тысяч записей - колонку не добавить, что такое тригер - не работал с ними..

Добавлено @ 11:02
В оракл есть вот такое:

Код

select some_column, decode(translate(some_column, '_0123456789', '_'), null, to_number(some_column)) as num
order by decode(translate(some_column, '_0123456789', '_'), null, to_number(some_column)), some_column


можно ли подобное сюда прикрутить?

Автор: Magnifico 28.2.2008, 11:07
Попробуй в таком духе, я не думаю что у дома может быть префикс       Щ ,Ч, Ю,Я
ну в случае чего добавишь

Код

declare @table table
(
house nvarchar(20)
)

insert @table
select '1'
union all
select '10'
union all
select '100'
union all
select '100А'
union all
select '197'
union all
select '197А'
union all
select '19Б'
union all
select '20'
union all
select '200'

select * from @table
order by 
case  when house like '%[А]%' then cast(replace(house ,'А','') as int)
 when house like '%[Б]%' then cast(replace(house ,'Б','') as int)
 when house like '%[В]%' then cast(replace(house ,'В','') as int)
when house like '%[Г]%' then cast(replace(house ,'Г','') as int)
when house like '%[Д]%' then cast(replace(house ,'Д','') as int)
else cast(house as int)   end

Автор: Komatoz 28.2.2008, 11:25
если делать 
Код

select distinct house from @table


то выдает ошибку..

можно ли не использовать like, а использовать регулярные выражения (как в PHP)?

Автор: Itsys 28.2.2008, 11:25
Magnifico, 
В этом случае у тебя не будут по порядку дома с индексами (А,Б....) т.е. может получиться, что дом с инексом Б будет раньше, чем А, тогда уж лучше так:
Код

select * from @table
order by 
case  when house like '%[А]' then cast(replace(house ,'А','.1') as float)
 when house like '%[Б]' then cast(replace(house ,'Б','.2') as float)
 when house like '%[В]' then cast(replace(house ,'В','.3') as float)
when house like '%[Г]' then cast(replace(house ,'Г','.4') as float)
when house like '%[Д]' then cast(replace(house ,'Д','.5') as float)
else cast(house as float)   end


Добавлено через 1 минуту и 37 секунд
Цитата(Komatoz @  28.2.2008,  11:25 Найти цитируемый пост)
то выдает ошибку..


Какую ошибку?

Автор: Magnifico 28.2.2008, 11:30
Itsys   да согласен!

Автор: Komatoz 29.2.2008, 01:54
А что если:

создать столбец и его как следует пронумеровать и при вызове селекта указывать сортировку по доп полю..

Автор: Itsys 29.2.2008, 02:07
Я тебе это в самом начале и советовал  smile - создай тригер (это тоже самое, что и хранимая процедура, только срабатывает автоматически при вставке, апдейте или удалении из таблицы)

Автор: Komatoz 29.2.2008, 03:11
Где про это почитать - я это ниразу не юзал..

Автор: Itsys 29.2.2008, 03:54
Во http://www.intuit.ru/department/database/sql/14/sql_14.html для тебя, мог бы сам поискать в гугле. smile 

Автор: Komatoz 29.2.2008, 05:32
Сенкс..
Вдруг я бы нетуда зашел..

Автор: SharedNoob 5.3.2008, 12:20
хм. 
Код

 select distinct House from Tabl order by right('                   '+ltrim(rtrim(House)),10)

Принцип сортировки строки таков
1
10
2
20
3
30
но если добавить пробелы впереди и сделать строку одинаковой длинны то выйдет так
'____1'
'____2'
'____3'
'___10'
'___20'
'___30'
собственно  order by right('                   '+ltrim(rtrim(House)),10)

Автор: nawok78 13.3.2008, 10:12
пример сортировки
Код

CREATE PROCEDURE NOTE_LIST (
    @ID_ARM NUMERIC=0,
    @ID_NOTE_TYPE TINYINT=NULL, 
    @DATE_FROM DATETIME=NULL,
    @DATE_TO DATETIME=NULL,
    @OUT NUMERIC=NULL,
    @IN NUMERIC=NULL,
    @ORDER_BY VARCHAR(255)=''
) AS
DECLARE 
    @NAME_IN VARCHAR(255),
    @NAME_OUT VARCHAR(255)

SELECT 
    ID_NOTE, D_DOC, ID_OUT, ID_IN, N_DOC, T1.ID_ARM,
    CASE WHEN @ID_ARM=T1.ID_ARM THEN T1.ACCEPT_MASTER
    WHEN T3.DIVISION=T1.ID_SLAVE THEN T1.ACCEPT_SLAVE 
     ELSE '' END AS ACCEPT,
    CASE 
        WHEN T2.CAN_WRITE=1 AND T2.ID_ARM=T1.ID_ARM THEN 1
        WHEN T2.CAN_WRITE=2 THEN 1
        ELSE 0 
    END AS CAN_WRITE , 
    CASE 
        WHEN T2.CAN_DEL=1 AND T2.ID_ARM=T1.ID_ARM THEN 1
        WHEN T2.CAN_DEL=2 THEN 1
        ELSE 0 
    END AS CAN_DEL ,
    CASE T1.TABLE_OUT
        WHEN 0 THEN (SELECT NAME FROM INSIDE WHERE ID=ID_OUT)
        WHEN 1 THEN (SELECT RTRIM(NAME) FROM LIM_BIN.dbo.UL WHERE ID_UL=ID_OUT)
        WHEN 2 THEN (SELECT NAME FROM ACT WHERE ID_ACT=ID_OUT)
    END AS NAME_OUT,
    CASE T1.TABLE_IN
        WHEN 0 THEN (SELECT NAME FROM INSIDE WHERE ID=ID_IN)
        WHEN 1 THEN (SELECT RTRIM(NAME) FROM LIM_BIN.dbo.UL WHERE ID_UL=ID_IN)
        WHEN 2 THEN (SELECT NAME FROM ACT WHERE ID_ACT=ID_IN)
    END AS NAME_IN,
--ДАЛЕЕ СОРТИРОВКА
    CASE 
    WHEN UPPER(@ORDER_BY) IN ('D', 'D_DOC') THEN CAST(D_DOC AS VARCHAR(255))
    WHEN UPPER(@ORDER_BY) IN ('N', 'N_DOC') THEN STR(N_DOC, 20,0)
    WHEN UPPER(@ORDER_BY) IN ('O', 'NAME_OUT')  THEN 
        CASE T1.TABLE_OUT
            WHEN 0 THEN (SELECT NAME FROM INSIDE WHERE ID=ID_OUT)
            WHEN 1 THEN (SELECT RTRIM(NAME) FROM LIM_BIN.dbo.UL WHERE ID_UL=ID_OUT)
            WHEN 2 THEN (SELECT NAME FROM ACT WHERE ID_ACT=ID_OUT)
        END
    WHEN UPPER(@ORDER_BY) IN ('I', 'NAME_IN') THEN 
        CASE T1.TABLE_IN
            WHEN 0 THEN (SELECT NAME FROM INSIDE WHERE ID=ID_IN)
            WHEN 1 THEN (SELECT RTRIM(NAME) FROM LIM_BIN.dbo.UL WHERE ID_UL=ID_IN)
            WHEN 2 THEN (SELECT NAME FROM ACT WHERE ID_ACT=ID_IN)
        END 
    WHEN UPPER(@ORDER_BY) IN ('A', 'ACCEPT') THEN 
        CASE 
            WHEN @ID_ARM=T1.ID_ARM THEN T1.ACCEPT_MASTER
            WHEN T3.DIVISION=T1.ID_SLAVE THEN T1.ACCEPT_SLAVE 
             ELSE '' 
        END 
    ELSE CAST(D_DOC AS VARCHAR(100))+STR(N_DOC, 20, 0)
    END AS ORDER_BY
FROM V_NOTE T1
LEFT JOIN NOTE_HAR T2 ON T2.ID_ARM=@ID_ARM AND T2.ID_NOTE_TYPE=T1.ID_NOTE_TYPE
LEFT JOIN ARM T3 ON T3.ID_ARM=@ID_ARM
WHERE (T2.CAN_READ = 2 OR (T2.CAN_READ=1 AND T3.DIVISION IN (T1.ID_OUT, T1.ID_IN)))
AND (@ID_NOTE_TYPE IS NULL OR @ID_NOTE_TYPE=T1.ID_NOTE_TYPE)
AND(@DATE_FROM IS NULL OR dbo.DATETIME_AS_DATE(@DATE_FROM)<=T1.D_DOC) 
AND (@DATE_TO IS NULL OR dbo.DATETIME_AS_DATE(@DATE_TO)>=T1.D_DOC)
AND (ISNULL(@OUT,0)<=0 OR ID_OUT=@OUT)
AND (ISNULL(@IN,0)<=0 OR ID_IN=@IN)
ORDER BY ORDER_BY
GO


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)