Вы отметили это как [SSMS-2017]
. Этого недостаточно, чтобы быть уверенным в вашей СУБД, но я предполагаю, что вы используете SQL-Server 2016 или более позднюю версию ...
Прежде всего, я хотел бы заявить, что ваш самый важный вопрос: почему вы храните это в формате CSV? Это ломает 1.NF
... Если вы можете изменить макет таблицы, вы должны использовать связанный боковой стол.
Но - если вам нужно придерживаться этого - вы можете использовать трюк с JSON
:
DECLARE @mockup TABLE(ID VARCHAR(100),ChargeType VARCHAR(100),ChargeAmount VARCHAR(100));
INSERT INTO @mockup(ID,ChargeType,ChargeAmount) VALUES
('1000:1597','F^F^F','1000^500^250')
,('01000:6597','F^F^F^F^F','500^250^50^2000^1000')
,('00010:0001','F','70');
SELECT m.ID
,B.[key] AS Position
,B.[value] AS ChargeType
,JSON_VALUE(A.AmountAsJson,CONCAT('$[',B.[key],']') COLLATE Latin1_General_BIN2) AS ChargeAmount
FROM @mockup m
CROSS APPLY (SELECT JSON_QUERY('["' + REPLACE(m.ChargeAmount,'^','","') + '"]')) A(AmountAsJson)
CROSS APPLY OPENJSON('["' + REPLACE(m.ChargeType,'^','","') + '"]') B
ORDER BY m.ID
,Position;
Результат:
+------------+----------+------------+--------------+
| ID | Position | ChargeType | ChargeAmount |
+------------+----------+------------+--------------+
| 00010:0001 | 0 | F | 70 |
+------------+----------+------------+--------------+
| 01000:6597 | 0 | F | 500 |
+------------+----------+------------+--------------+
| 01000:6597 | 1 | F | 250 |
+------------+----------+------------+--------------+
| 01000:6597 | 2 | F | 50 |
+------------+----------+------------+--------------+
| 01000:6597 | 3 | F | 2000 |
+------------+----------+------------+--------------+
| 01000:6597 | 4 | F | 1000 |
+------------+----------+------------+--------------+
| 1000:1597 | 0 | F | 1000 |
+------------+----------+------------+--------------+
| 1000:1597 | 1 | F | 500 |
+------------+----------+------------+--------------+
| 1000:1597 | 2 | F | 250 |
+------------+----------+------------+--------------+
Идея вкратце:
Разделение строк - это боль в TSQL SQL-сервера. Были различные обходные пути с использованием циклов, рекурсивных CTE или XML (как вы делали выше).
С v2016 разработчики были очень довольны новой функцией STRING_SPLIT()
, но MS забыла указать позицию фрагмента. Это делает STRING_SPLIT()
довольно бесполезной функцией ...
Но - вместе с STRING_SPLIT
- появилась поддержка JSON. Чтение простого JSON-массива с OPENJSON
обеспечит положение фрагмента в столбце [key]
(внимание: начинается с нуля!).
Приведенный выше код сначала создаст макет-таблицу и заполнит ее вашими примерами данных.
Первый CROSS APPLY
преобразует ChargeAmount
в JSON-массив, ничего не делая с ним.
Второй CROSS APPLY
преобразует ChargeType
в JSON-массив и возвращает одну строку на фрагмент.
Затем выборка использует JSON_VALUE
, чтобы выбрать соответствующее значение из AmountAsJson
, используя [key]
(положение) в качестве пути JSON.
Надеюсь, это было ясно ...