Создать двоичную матрицу из серии строк CSV в SQL Server (2012)? - PullRequest
0 голосов
/ 14 июня 2019

Есть таблица вида

pk items
--------
1  a,b,c,...
2  d,e,f,...
3  g,h,i,...
4  j,k,l,...
.
.
.

где значения столбцов элементов имеют переменную длину (могут быть пустыми) csv-строки (чьи элементы не обязательно должны быть уникальными), скажем, продуктовых предметов (просто используя здесь буквы для удобства чтения).

Исходя из этого, вы хотите иметь возможность генерировать двоичную матрицу, которая представляет элементы, которые содержит любой данный pk, например.

pk a b c d e f g ...
--------------------
1  1 1 1 0 0 0 0 ...
2  0 0 0 1 1 1 0 ...
3  0 0 0 0 0 0 0 ...
.
.
.

Обратите внимание, что у меня также есть доступ к таблице, которая представляет весь домен возможных значений для любого элемента в списках csv, например.

item
------
a
b
c
.
.
.

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

1 Ответ

2 голосов
/ 14 июня 2019

Я полностью согласен с сделанными комментариями, и это далеко не идеальный способ хранения данных.Ваша таблица Form должна быть нормализована, и на самом деле вы должны использовать свой уровень представления для этого.Я написал ниже, используя STRING_SPLIT, однако вы также можете использовать DelimitedSplit8k_LEAD для достижения этой цели.(Исправление вам понадобится, поскольку вы используете SQL Server 2012.)

Это не материал начального уровня, поэтому, пожалуйста, спросите, если не понимаете:

--Create the table with all the items
CREATE TABLE dbo.Item (ItemID int IDENTITY (1,1),
                       ItemName varchar(2));

INSERT INTO dbo.Item(ItemName)
VALUES('a'),
      ('b'),
      ('c'),
      ('d'),
      ('e'),
      ('f'),
      ('g'),
      ('h'),
      ('i'),
      ('j'),
      ('k'),
      ('l'),
      ('m'),
      ('n'),
      ('o'),
      ('p'),
      ('q');
GO

--And now your sample data
CREATE TABLE dbo.Form (Pk int IDENTITY (1,1),
                       Items varchar(100)); --Really you shouldn't be storing delimited data

INSERT INTO dbo.Form (Items)
VALUES ('a,b,c'),
       ('d,e,f'),
       ('g,h,i'),
       ('j,k,l');

GO

--Declare the SQL variable to store the dynamic SQL
DECLARE @SQL nvarchar(MAX);

--Build the SQL. Use FOR XML PATH to create the delimited list of columns,
--STRING_SPLIT in the dynamic SQL to split the data
--and a cross tab to pivot the data
--YUCK (sorry)
SET @SQL = N'SELECT F.Pk,' + NCHAR(13) + NCHAR(10) + 
           STUFF((SELECT N',' + NCHAR(13) + NCHAR(10) + 
                         N'       CASE WHEN COUNT(CASE WHEN SS.[value] = ' + QUOTENAME(I.ItemName,'''') + N'THEN 1 END) = 0 THEN 0 ELSE 1 END AS ' + QUOTENAME(I.ItemName)
                  FROM dbo.Item I
                  ORDER BY I.ItemName ASC
                  FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,3,N'') + NCHAR(13) + NCHAR(10) + 
           N'FROM dbo.Form F' + NCHAR(13) + NCHAR(10) + 
           N'     CROSS APPLY STRING_SPLIT(F.Items,'','') SS' + NCHAR(13) + NCHAR(10) + 
           N'GROUP BY Pk;';
PRINT @SQL; --Your best friend for debugging
EXEC sp_executesql @SQL;

GO
DROP TABLE dbo.Form;
DROP TABLE dbo.Item;
**

1011 дб <> скрипка

...