Использование STRING_SPLIT для 2 столбцов в одной таблице - PullRequest
0 голосов
/ 29 апреля 2020

Я начал с такой таблицы

ID | City                               | Sales
1  | London,New York,Paris,Berlin,Madrid| 20,30,,50
2  | Istanbul,Tokyo,Brussels            | 4,5,6

Может быть неограниченное количество городов и / или продаж.

Мне нужно, чтобы каждый город и их продажи составляли их собственная запись. Таким образом, мой результат должен выглядеть примерно так:

ID | City                               | Sales
1  | London                             | 20
1  | New York                           | 30
1  | Paris                              | 
1  | Berlin                             | 50
1  | Madrid                             | 
2  | Istanbul                           | 4 
2  | Tokyo                              | 5
2  | Brussels                           | 6  

То, что я до сих пор получил, это

SELECT ID, splitC.Value, splitS.Value
FROM Table
CROSS APLLY STRING_SPLIT(Table.City,',') splitC
CROSS APLLY STRING_SPLIT(Table.Sales,',') splitS

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

Что будет вариант решить эту проблему? STRING_SPLIT не обязателен, просто я начал с него.

Ответы [ 2 ]

1 голос
/ 29 апреля 2020

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

Но вы можете попробовать использовать подход, основанный на JSON, используя OPEN JSON () и преобразование строки (значения через запятую преобразуются в действительный массив JSON - London,New York,Paris,Berlin,Madrid в ["London","New York","Paris","Berlin","Madrid"]). Результатом OPENJSON() со схемой по умолчанию является таблица со столбцами key, value и type, а столбец key представляет собой индекс на основе 0 для каждого элемента в этом массиве:

Таблица:

CREATE TABLE Data (
   ID int,
   City varchar(1000),
   Sales varchar(1000)
)
INSERT INTO Data 
   (ID, City, Sales)
VALUES   
   (1, 'London,New York,Paris,Berlin,Madrid', '20,30,,50'),
   (2, 'Istanbul,Tokyo,Brussels',             '4,5,6')

Заявление:

SELECT d.ID, a.City, a.Sales
FROM Data d
CROSS APPLY (
   SELECT c.[value] AS City, s.[value] AS Sales
   FROM OPENJSON(CONCAT('["', REPLACE(d.City, ',', '","'), '"]')) c
   LEFT OUTER JOIN OPENJSON(CONCAT('["', REPLACE(d.Sales, ',', '","'), '"]')) s 
      ON c.[key] = s.[key]
) a 

Результат:

ID  City     Sales
1   London   20
1   New York 30
1   Paris   
1   Berlin   50
1   Madrid   NULL
2   Istanbul 4
2   Tokyo    5
2   Brussels 6
1 голос
/ 29 апреля 2020

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

Порядок вывода может отличаться, поскольку порядок не гарантированно соответствует порядку подстроки во входной строке.

В результате вам нужно использовать что-то, что знает о таких базовых c вещах, таких как DelimitedSplit8k_LEAD.

Тогда вы можете сделать что-то вроде этого:

WITH Cities AS(
    SELECT ID,
           DSc.Item,
           DSc.ItemNumber
    FROM dbo.YourTable YT
         CROSS APPLY dbo.DelimitedSplit8k_LEAD(YT.City,',') DSc)
Sales AS(
    SELECT ID,
           DSs.Item,
           DSs.ItemNumber
    FROM dbo.YourTable YT
         CROSS APPLY dbo.DelimitedSplit8k_LEAD(YT.Sales,',') DSs)
SELECT ISNULL(C.ID,S.ID) AS ID,
       C.Item AS City,
       S.Item AS Sale
FROM Cities C
     FULL OUTER JOIN Sales S ON C.ItemNumber = S.ItemNumber;

Конечно, решение real , конечно, исправит ваш дизайн. Этот тип дизайна будет вызывать у вас только сотни проблем в будущем. Исправьте это сейчас, а не позже; вы получите так много наград раньше, чем раньше.

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