Как развернуть значения, разделенные запятыми, в отдельные строки, используя SQL Server 2005? - PullRequest
1 голос
/ 01 апреля 2009

У меня есть таблица, которая выглядит так:

ProductId, Color
"1", "red, blue, green"
"2", null
"3", "purple, green"

И я хочу расширить это до:

ProductId, Color
1, red
1, blue
1, green
2, null
3, purple
3, green

Какой самый простой способ сделать это? Это возможно без цикла в процедуре?

Ответы [ 6 ]

9 голосов
/ 01 апреля 2009

Посмотрите на эту функцию. Я проделал аналогичные трюки для разделения и переноса данных в Oracle. Зацикливайте данные, вставляя декодированные значения во временную таблицу. Традиционно, MS позволит вам делать это на лету, в то время как Oracle требует явной временной таблицы.

Функция разделения MS SQL
Лучшая функция разделения

Редактировать по автору: Это сработало отлично. Конечный код выглядел так (после создания функции split):

select pv.productid, colortable.items as color
from product p 
    cross apply split(p.color, ',') as colortable
5 голосов
/ 01 апреля 2009

на основе ваших таблиц:

create table test_table
(
     ProductId  int
    ,Color      varchar(100)
)

insert into test_table values (1, 'red, blue, green')
insert into test_table values (2, null)
insert into test_table values (3, 'purple, green')

создайте новую таблицу следующим образом:

CREATE TABLE Numbers
(
    Number  int   not null primary key
)

, в котором есть строки, содержащие значения от 1 до 8000 или около того.

это вернет то, что вы хотите:

EDIT
Вот гораздо лучший запрос, немного измененный по сравнению с замечательным ответом @Christopher Klein:

Я добавил «LTRIM ()», чтобы пространства в списке цветов обрабатывались правильно: «красный, синий, зеленый». Его решение не требует пробелов "красный, синий, зеленый". Кроме того, я предпочитаю использовать свою собственную таблицу номеров и не использовать master.dbo.spt_values, это также позволяет удалить одну производную таблицу.

SELECT
    ProductId, LEFT(PartialColor, CHARINDEX(',', PartialColor + ',')-1) as SplitColor
    FROM (SELECT 
              t.ProductId, LTRIM(SUBSTRING(t.Color, n.Number, 200)) AS PartialColor
              FROM test_table             t
                  LEFT OUTER JOIN Numbers n ON n.Number<=LEN(t.Color) AND SUBSTRING(',' + t.Color, n.Number, 1) = ','
         ) t

РЕДАКТИРОВАТЬ КОНЕЦ

SELECT
    ProductId, Color --,number
    FROM (SELECT
              ProductId
                  ,CASE
                       WHEN LEN(List2)>0 THEN LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(',', List2, number+1)-number - 1)))
                       ELSE NULL
                   END AS Color
                  ,Number
              FROM (
                       SELECT ProductId,',' + Color + ',' AS List2
                           FROM test_table
                   ) AS dt
                  LEFT OUTER JOIN Numbers n ON (n.Number < LEN(dt.List2)) OR (n.Number=1 AND dt.List2 IS NULL)
              WHERE SUBSTRING(List2, number, 1) = ',' OR List2 IS NULL
         ) dt2
    ORDER BY ProductId, Number, Color

вот мой набор результатов:

ProductId   Color
----------- --------------
1           red
1           blue
1           green
2           NULL
3           purple
3           green

(6 row(s) affected)

это тот же порядок, который вы хотите ...

4 голосов
/ 01 апреля 2009

Вы можете попробовать это, не требуя каких-либо дополнительных функций:

declare @t table (col1 varchar(10), col2 varchar(200))
insert @t
          select '1', 'red,blue,green'
union all select '2', NULL
union all select '3', 'green,purple'


select col1, left(d, charindex(',', d + ',')-1) as e from (
    select *, substring(col2, number, 200) as d from @t col1 left join
        (select distinct number from master.dbo.spt_values where number between 1 and 200) col2
        on substring(',' + col2, number, 1) = ',') t
0 голосов
/ 09 октября 2017

Просто конвертируйте ваши столбцы в xml и запрашивайте их. Вот пример.

select 
    a.value('.', 'varchar(42)') c
from (select cast('<r><a>' + replace(@CSV, ',', '</a><a>') + '</a></r>' as xml) x) t1
cross apply x.nodes('//r/a') t2(a)
0 голосов
/ 01 апреля 2009

Я бы создал для этого функцию таблицы CLR:

http://msdn.microsoft.com/en-us/library/ms254508(VS.80).aspx

Причина этого в том, что код CLR будет намного лучше разбирать строки (вычислительная работа) и может передавать эту информацию обратно в виде набора, в чем SQL Server действительно хорош (управление наборами).

Функция CLR будет возвращать серию записей на основе проанализированных значений (и входного значения идентификатора).

Затем вы будете использовать CROSS APPLY для каждого элемента в вашей таблице.

0 голосов
/ 01 апреля 2009

Исправьте вашу базу данных, если это вообще возможно. Списки с разделителями-запятыми в ячейках базы данных указывают на некорректную схему в 99% случаев или более.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...