Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Пересортировать строку с номерами  [new]
IFK
Member

Откуда: Гондурас
Сообщений: 1025
Уважаемый форум,

Необходимо реализовать решение задачи под сиквелом:
- дано: строка вида "54-150, 151-200, 1-45, 210-300, 46-53, 201-209" и т.д.
- требуется: отсортировать значения в строке по возрастанию, т.е. вышеприведенная строка должна быть преобразована в "1-45, 46-53, 54-150, 151-200, 201-209, 210-300"

Как бы это сделать поэффективнее, без кучи курсоров и т.д.?

Спасибо!
14 фев 19, 17:08    [21809712]     Ответить | Цитировать Сообщить модератору
 Re: Пересортировать строку с номерами  [new]
Руслан Дамирович
Member

Откуда: Резиновая нерезиновая
Сообщений: 940
IFK,
+ как-то так

DECLARE 
  @temp TABLE (
    [id] INT IDENTITY(1,1),
    [string] NVARCHAR(MAX),
    PRIMARY KEY ( [id] )
  )
;
INSERT
INTO
  @temp
VALUES
  ( '54-150, 151-200, 1-45, 210-300, 46-53, 201-209' ),
  ( '1-45, 46-53, 54-150, 151-200, 201-209, 210-300' )
;
WITH
tt0 AS (
  SELECT
    [id],
    [xml] = CONVERT( XML, N'<i>' + REPLACE( [string], N', ', N'</i><i>' ) + N'</i>' )
  FROM
    @temp
),
tt1 AS (
  SELECT
    tt0.[id],
    [value] = x.[v].[value]( N'.', N'NVARCHAR(255)' )
  FROM
    tt0
    CROSS APPLY tt0.[xml].[nodes]( N'i' ) x( [v] )
),
tt2 AS (
  SELECT
    tt1.[id],
    tt1.[value],
    [rn] = ROW_NUMBER() OVER ( PARTITION BY tt1.[id] ORDER BY TRY_PARSE( ss2.[value1] AS INT ), TRY_PARSE( ss2.[value2] AS INT ) )
  FROM
    tt1
    CROSS APPLY (
      SELECT
        [i] = CHARINDEX( '-', tt1.[value] )
    ) ss1
    CROSS APPLY (
      SELECT
        [value1] = CASE WHEN ss1.[i] > 1 THEN LEFT( tt1.[value], ss1.[i] - 1 ) ELSE tt1.[value] END,
        [value2] = CASE WHEN ss1.[i] > 1 THEN RIGHT( tt1.[value], LEN( tt1.[value] ) - ss1.[i] ) ELSE NULL END
    ) ss2
)
SELECT
  [id],
  [string],
  [new] = STUFF( CONVERT( VARCHAR(MAX), (
    SELECT [*] =  ', ' + [value] FROM tt2 WHERE tt2.[id] = tt0.[id] ORDER BY [rn] FOR XML PATH('') ) 
    ), 1, 2, '' )
FROM
  @temp tt0
;
14 фев 19, 17:33    [21809745]     Ответить | Цитировать Сообщить модератору
 Re: Пересортировать строку с номерами  [new]
IFK
Member

Откуда: Гондурас
Сообщений: 1025
Руслан Дамирович, огромное спасибо!
14 фев 19, 17:39    [21809756]     Ответить | Цитировать Сообщить модератору
 Re: Пересортировать строку с номерами  [new]
invm
Member

Откуда: Москва
Сообщений: 9343
IFK,

Проще и компактнее:
declare @t table(s varchar(max));

insert into @t
values
 ('54-150, 151-200, 1-45, 210-300, 46-53, 201-209');

select
 t.s, stuff(r.x.value('.', 'varchar(max)'), 1, 2, '')
from
 @t t cross apply
 (
  select
   ', ' + c.n1+ '-' + c.n2
  from
   (select cast('<i n1 = "' + replace(replace(t.s, '-', '" n2 = "'), ',', '"/><i n1 = "') + '"/>' as xml)) a(x) cross apply
   a.x.nodes('i') b(n) cross apply
   (
    select
     b.n.value('@n1', 'varchar(10)'),
     b.n.value('@n2', 'varchar(10)'),
     b.n.value('@n1', 'int')
   ) c(n1, n2, k)
  order by
   c.k
  for xml path(''), type
 ) r(x);
14 фев 19, 18:57    [21809869]     Ответить | Цитировать Сообщить модератору
 Re: Пересортировать строку с номерами  [new]
Руслан Дамирович
Member

Откуда: Резиновая нерезиновая
Сообщений: 940
invm,

cool!
15 фев 19, 10:01    [21810226]     Ответить | Цитировать Сообщить модератору
 Re: Пересортировать строку с номерами  [new]
iap
Member

Откуда: Москва
Сообщений: 46977
invm
IFK,

Проще и компактнее:
declare @t table(s varchar(max));

insert into @t
values
 ('54-150, 151-200, 1-45, 210-300, 46-53, 201-209');

select
 t.s, stuff(r.x.value('.', 'varchar(max)'), 1, 2, '')
from
 @t t cross apply
 (
  select
   ', ' + c.n1+ '-' + c.n2
  from
   (select cast('<i n1 = "' + replace(replace(t.s, '-', '" n2 = "'), ',', '"/><i n1 = "') + '"/>' as xml)) a(x) cross apply
   a.x.nodes('i') b(n) cross apply
   (
    select
     b.n.value('@n1', 'varchar(10)'),
     b.n.value('@n2', 'varchar(10)'),
     b.n.value('@n1', 'int')
   ) c(n1, n2, k)
  order by
   c.k
  for xml path(''), type
 ) r(x);
Чего-то это слишком просто!
15 фев 19, 10:12    [21810243]     Ответить | Цитировать Сообщить модератору
 Re: Пересортировать строку с номерами  [new]
court
Member

Откуда:
Сообщений: 2013
iap
Чего-то это слишком просто! Картинка с другого сайта.

на 16-ом/17-ом уопще "шара" :)

DECLARE 
  @temp TABLE (
    [id] INT IDENTITY(1,1),
    [string] NVARCHAR(MAX),
    PRIMARY KEY ( [id] )
  )
;
INSERT
INTO
  @temp
VALUES
  ( '54-150, 151-200, 1-45, 210-300, 46-53, 201-209' ),
  ( '1-45, 46-53, 54-150, 151-200, 201-209, 210-300' )
;

--	**************************************************************************************
;with cte as (
	select a.id, b.value from @temp a
	cross apply (select rtrim(ltrim(value)) as value from STRING_SPLIT([string],',') t) b
)
select
	id
	,substring((select ','+b.value from cte b where a.id=b.id order by cast(replace(b.value,'-','.') as float) for xml path('')),2,100500) as xz
from @temp a

idxz
11-45,46-53,54-150,151-200,201-209,210-300
21-45,46-53,54-150,151-200,201-209,210-300
15 фев 19, 10:36    [21810280]     Ответить | Цитировать Сообщить модератору
 Re: Пересортировать строку с номерами  [new]
Руслан Дамирович
Member

Откуда: Резиновая нерезиновая
Сообщений: 940
court,
Там вообще интервалы записаны, так что можно сортировать по числу до "-".
Меня больше беспокоит, что эта задача решается post, а не ante.

P.S. Я тут вспомнил, что у меня 2016, а я все еще через XML делаю по привычке.
15 фев 19, 10:45    [21810295]     Ответить | Цитировать Сообщить модератору
 Re: Пересортировать строку с номерами  [new]
invm
Member

Откуда: Москва
Сообщений: 9343
Тогда уж чисто для 2017-го :)
select
 a.string, b.string
from
 @temp a cross apply
 (
  select
   string_agg(trim(value), ', ') within group (order by try_cast(replace(value, '-', '.') as float))
  from
   string_split(a.string, ',')
 ) b(string);
15 фев 19, 11:06    [21810330]     Ответить | Цитировать Сообщить модератору
 Re: Пересортировать строку с номерами  [new]
IFK
Member

Откуда: Гондурас
Сообщений: 1025
Пардон, забыл сообщить, что у меня 2012, так что STRING_SPLIT не прокатит. Остается вариант через xml. Всем большое спасибо - пойду разбираться, как это работает. :)
15 фев 19, 17:20    [21811035]     Ответить | Цитировать Сообщить модератору
 Re: Пересортировать строку с номерами  [new]
uaggster
Member

Откуда:
Сообщений: 826
Руслан Дамирович
court,
Там вообще интервалы записаны, так что можно сортировать по числу до "-".
Меня больше беспокоит, что эта задача решается post, а не ante.

P.S. Я тут вспомнил, что у меня 2016, а я все еще через XML делаю по привычке.

Да всё еще проще :-)))
Т.к. сортируем, фактически, по первому значению, то делаем replace '-' на '.', делаем TRY_convert в numeric, и по этому нумерику - сортируем.
:-))))
15 фев 19, 17:28    [21811051]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить