У меня есть следующая таблица со следующими данными как
Tab1
FutureMISBoundaryVersion CurrentMISBoundaryVersion FutureHAMBoundaryVersion CurrentHAMBoundaryVersion
2:21,5:50,4:55,7:80,9:33 2:12,5:40,4:35,7:60,9:87 2:52,5:90,4:75,7:30,9:57 2:42,5:60,4:95,7:70,9:37
Эта пара значений ключа должна быть разделена, и значение каждого ключа должно быть вставлено в другую таблицу следующим образом.
FutureMIS-OAKVersion |FutureMIS-HAMVersion |FutureMIS-DURVersion | FutureMIS-BURVersion| FutureMIS-YRTVersion |DeviceMIS-OAKVersion|DeviceMIS-HAMVersion |DeviceMIS-DURVersion| DeviceMIS-BURVersion| DeviceMIS-YRTVersion
33 | 80 | 21 | 55 | 50 | 87 | 60 |12 |35 | 40
i, e: когда он находит столбец «FutureMISBoundaryVersion» на вкладке 1, тогда его значение '2:21,5:50,4:55,7:80,9:33' будет разделен и его значение вставлено таким образом, что соответствующее значение ключа 2 i,e:21 будет вставлено в FutureMIS -DURVersion столбец.
Точно так же значение 50 ключа 5 будет вставлено в столбец FutureMIS-BURVersion и так далее для других ключей.
когда он находит столбец «CurrentMISBoundaryVersion», тогда
'2:12,5:40,4:35,7:60,9:87' будет разделен и его значение вставлено таким образом, что соответствующее значение ключа 2 i,e:12 будет вставлено в CurrentMIS Столбец -DURVersion аналогично ключу 5 со значением 40 будет вставлен в столбец DeviceMIS-YRTVersion и так далее для других столбцов исходной таблицы.
Структура таблицы может расширяться, так как я показал только 4 столбца исходной таблицы, но логика для всех столбцов остается неизменной.
Нет, бывает по-разному @ Гордон Линофф


Следующий запрос разберет строку 2:21,5:50,4:55,7:80,9:33, разделенную запятыми, на отдельные компоненты 2:21, 5:30 и т. д. Оттуда вы можете использовать аналогичный метод для извлечения bb из aa:bb.
Поскольку пара ключ-значение имеет формат aa:bb, вы можете использовать datepart(hour, 'aa:bb') и datepart(minute, 'aa:bb') для извлечения aa и bb.
; with
Tab1 as
(
select val = '2:21,5:50,4:55,7:80,9:33'
)
select t.*, k1.k, k2.k, k3.k, k4.k, k5.k
from Tab1 t
cross apply
(
select i = charindex(',', t.val),
k = substring(t.val, 1, charindex(',', t.val + ',', 1) - 1)
) k1
cross apply
(
select i = charindex(',', t.val, k1.i + 1),
k = substring(t.val, k1.i + 1, charindex(',', t.val + ',', k1.i + 1) - k1.i - 1)
) k2
cross apply
(
select i = charindex(',', t.val, k2.i + 1),
k = substring(t.val, k2.i + 1, charindex(',', t.val + ',', k2.i + 1) - k2.i - 1)
) k3
cross apply
(
select i = charindex(',', t.val, k3.i + 1),
k = substring(t.val, k3.i + 1, charindex(',', t.val + ',', k3.i + 1) - k3.i - 1)
) k4
cross apply
(
select i = charindex(',', t.val, k4.i + 1),
k = substring(t.val, k4.i + 1, charindex(',', t.val + ',', k4.i + 1) - k4.i - 1)
) k5
@ Squirrel: если какой-либо ключ не найден в паре ключ-значение, выдает неожиданный o/p из вашей логики, например: вместо этого «2: 21, 5: 50, 4: 55, 7: 80, 9: 33» скажем, предположим, что у нас есть '5:50,4:55,7:80,9:33', тогда весь синтаксический анализ испортится
как узнать какого ключа не хватает?
Вы говорите, что первый ключ всегда 2, второй всегда 5?
это не должно быть!! порядок также может измениться, то есть: дело в том, что он может содержать максимум все ключи 2,5,4,7,9, присутствующие в нем '2:21,5:50,4:55,7:80,9:33 ' или может быть '2:21,5:50,4:55', но ключ будет из подмножества (2,5,4,7,9). Если какой-либо ключ не найден, соответствующий столбец должен быть пустой строкой.
в любом случае, вы можете использовать аналогичный метод, например charindex(), substring(), чтобы извлечь ключ и значение, которые вам нужны.
Очень странные требования, если честно. Обратите внимание, что приведенное ниже решение будет работать только в SQL Server 2016+, поскольку я использую JSON для анализа данных. Однако вы можете написать свой парсер, в этом случае код будет работать почти во всех версиях SQL Server.
Функция разбора:
CREATE FUNCTION dbo.ParseIt(@Type NVARCHAR(255),@Value NVARCHAR(MAX))
RETURNS @Parsed TABLE (Code NVARCHAR(255),Value NVARCHAR(255))
AS
BEGIN
INSERT INTO @Parsed(Code,Value)
SELECT @Type + '-' + m.Code + 'Version' AS [Code],p.[1] AS [Value]
FROM (
SELECT j.[key] AS [ID],i.[key],i.value
FROM OPENJSON('["' + REPLACE(@Value,',','","') + '"]') j
CROSS APPLY OPENJSON('[' + REPLACE(j.[value],':',',') + ']') i
) a
PIVOT(MAX(a.value) FOR a.[key] IN ([0],[1])) p
INNER JOIN ( VALUES
(2,'DUR')
,(4,'BUR')
,(5,'YRT')
,(7,'HAM')
,(9,'OAK')
) m(ID, Code) ON m.ID = p.[0]
;
RETURN;
END
Исходные данные:
DECLARE @Table TABLE (FutureMISBoundaryVersion NVARCHAR(MAX), CurrentMISBoundaryVersion NVARCHAR(MAX),FutureHAMBoundaryVersion NVARCHAR(MAX),CurrentHAMBoundaryVersion NVARCHAR(MAX));
INSERT INTO @Table(FutureMISBoundaryVersion,CurrentMISBoundaryVersion,FutureHAMBoundaryVersion,CurrentHAMBoundaryVersion)VALUES
('2:21,5:50,4:55,7:80,9:33','2:12,5:40,4:35,7:60,9:87','2:52,5:90,4:75,7:30,9:57','2:42,5:60,4:95,7:70,9:37')
;
Код:
SELECT COALESCE(p.[FutureMIS-OAKVersion],'') AS [FutureMIS-OAKVersion]
,COALESCE(p.[FutureMIS-HAMVersion],'') AS [FutureMIS-HAMVersion]
,COALESCE(p.[FutureMIS-DURVersion],'') AS [FutureMIS-DURVersion]
,COALESCE(p.[FutureMIS-BURVersion],'') AS [FutureMIS-BURVersion]
,COALESCE(p.[FutureMIS-YRTVersion],'') AS [FutureMIS-YRTVersion]
,COALESCE(p.[DeviceMIS-OAKVersion],'') AS [DeviceMIS-OAKVersion]
,COALESCE(p.[DeviceMIS-HAMVersion],'') AS [DeviceMIS-HAMVersion]
,COALESCE(p.[DeviceMIS-DURVersion],'') AS [DeviceMIS-DURVersion]
,COALESCE(p.[DeviceMIS-BURVersion],'') AS [DeviceMIS-BURVersion]
,COALESCE(p.[DeviceMIS-YRTVersion],'') AS [DeviceMIS-YRTVersion]
FROM (
SELECT f.Code,f.Value FROM @Table t CROSS APPLY dbo.ParseIt('FutureMIS',t.FutureMISBoundaryVersion) f
UNION ALL
SELECT f.Code,f.Value FROM @Table t CROSS APPLY dbo.ParseIt('DeviceMIS',t.CurrentMISBoundaryVersion) f
) a
PIVOT(MAX(a.Value) FOR a.Code IN ([DeviceMIS-BURVersion],[DeviceMIS-DURVersion],[DeviceMIS-HAMVersion],[DeviceMIS-OAKVersion]
,[DeviceMIS-YRTVersion],[FutureMIS-BURVersion],[FutureMIS-DURVersion],[FutureMIS-HAMVersion],[FutureMIS-OAKVersion]
,[FutureMIS-YRTVersion])) p
;
@ Виталий Борисов: отличная попытка ... но если какой-либо ключ отсутствует, он вставляет нулевые значения в столбец назначения, но я хочу, чтобы это была пустая строка
Я обновил ответ в соответствии с требованием, но настоятельно рекомендую везде использовать правильные типы (int) вместо строк.
@ Виталий Борисов: я просто пытался расширить то же самое для своего требования, как DeviceCurrentMISCRECrossBoundaryBURVersion вместо [DeviceMIS-BURVersion], DeviceFutureMISCRECrossBoundaryBURVersion вместо [FutureMIS-BURVersion] и так далее в качестве выходного столбца. Любая помощь в этом
Просто замените на AS [anyNameYouNeed] в операторе выбора
@ Виталий Борисов: что, если у нас есть формат даты, например: '2:21/06/2017, 3:11/02/2014' Попытался нажать, но получил: Спасибо за отзыв! Голоса, отданные теми, у кого репутация менее 15, записываются, но не изменяют публично отображаемый результат публикации.
У вас недостаточно баллов для голосования, но вы можете принять ответ
@ Виталий Борисов: Готово!! А что, если у меня есть формат даты i, e: «2:21/06/2017,3:11/02/2014» или «2:21.06.2017,3:11.02.2014» вместо «2:21,3». :50'
В функции замены Cross применяются к этому: CROSS APPLY OPENJSON('["' + REPLACE(j.[value],':','","') + '"]') i
Можем ли мы одновременно обрабатывать как строку, так и вышеупомянутый формат даты в одной функции?
Да, просто замените в соответствии с моим предыдущим комментарием
OPENJSON, используемая в приведенной выше функции, несовместима с SQL 2014, но работает в 2016 году, есть ли альтернатива?
Напишите функцию парсера, используя строковые функции вместо OpenJson
Это боль в SQL Server. Вы можете сделать это с помощью рекурсивных CTE:
with cte as (
select convert(varchar(max), left(FutureMISBoundaryVersion, charindex(',', FutureMISBoundaryVersion) - 1)) as FutureMISBoundaryVersion,
convert(varchar(max), left(CurrentMISBoundaryVersion, charindex(',', CurrentMISBoundaryVersion) - 1)) as CurrentMISBoundaryVersion,
convert(varchar(max), left(FutureHAMBoundaryVersion, charindex(',', FutureHAMBoundaryVersion) - 1)) as FutureHAMBoundaryVersion,
convert(varchar(max), left(CurrentHAMBoundaryVersion, charindex(',', FutureMISBoundaryVersion) - 1)) as CurrentHAMBoundaryVersion,
stuff(FutureMISBoundaryVersion, 1, charindex(',', FutureMISBoundaryVersion), '') + ',' as FutureMISBoundaryVersion_rest,
stuff(CurrentMISBoundaryVersion, 1, charindex(',', CurrentMISBoundaryVersion), '') + ',' as CurrentMISBoundaryVersion_rest,
stuff(FutureHAMBoundaryVersion, 1, charindex(',', FutureHAMBoundaryVersion), '') + ',' as FutureHAMBoundaryVersion_rest,
stuff(CurrentHAMBoundaryVersion, 1, charindex(',', CurrentHAMBoundaryVersion), '') + ',' as CurrentHAMBoundaryVersion_rest,
1 as lev
from t
union all
select convert(varchar(max), left(FutureMISBoundaryVersion_rest, charindex(',', FutureMISBoundaryVersion_rest) - 1)) as FutureMISBoundaryVersion,
convert(varchar(max), left(CurrentMISBoundaryVersion_rest, charindex(',', CurrentMISBoundaryVersion_rest) - 1)) as CurrentMISBoundaryVersion,
convert(varchar(max), left(FutureHAMBoundaryVersion_rest, charindex(',', FutureHAMBoundaryVersion_rest) - 1)) as FutureHAMBoundaryVersion,
convert(varchar(max), left(CurrentHAMBoundaryVersion_rest, charindex(',', CurrentHAMBoundaryVersion_rest) - 1)) as CurrentHAMBoundaryVersion,
stuff(FutureMISBoundaryVersion_rest, 1, charindex(',', FutureMISBoundaryVersion_rest), '') as FutureMISBoundaryVersion_rest,
stuff(CurrentMISBoundaryVersion_rest, 1, charindex(',', CurrentMISBoundaryVersion_rest), '') as CurrentMISBoundaryVersion_rest,
stuff(FutureHAMBoundaryVersion_rest, 1, charindex(',', FutureHAMBoundaryVersion_rest), '') as FutureHAMBoundaryVersion_rest,
stuff(CurrentHAMBoundaryVersion_rest, 1, charindex(',', CurrentHAMBoundaryVersion_rest), '') as CurrentHAMBoundaryVersion_rest,
lev + 1
from cte
where FutureMISBoundaryVersion_rest like '%,%'
)
select FutureMISBoundaryVersion, CurrentMISBoundaryVersion, FutureHAMBoundaryVersion, CurrentHAMBoundaryVersion, lev
from cte;
Здесь — это рабочий пример db<>.
Одинаковы ли длины всех значений в каждом столбце?