如何在 SQL 服务器数据库中使用 functions/stored 过程实现以下目标
How to achieve the following using functions/stored procedure in SQL Server database
我有以下 table 以及以下数据
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
这个键值对必须被拆分成并且每个键的值必须按以下方式插入另一个table
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:当它在 tab1 中找到列 'FutureMISBoundaryVersion' 时,它的值
'2:21,5:50,4:55,7:80,9:33' 将被拆分,其值的插入方式是将键 2 i,e:21 的相应值插入到 FutureMIS 中-DURVersion 列。
类似地,键 5 的值 50 将被插入到 FutureMIS-BURVersion 列中,其他键依此类推
当它找到列 'CurrentMISBoundaryVersion' 时
'2:12,5:40,4:35,7:60,9:87' 将被拆分,其值将以键 2 i,e:12 的相应值插入到 CurrentMIS 中的方式插入-DURVersion 列类似地,键 5 的 40 值将被插入到 DeviceMIS-YRTVersion 列中,对于源 table 的其他列,依此类推。
table 结构可能会扩展,因为我只显示了 4 个源 table 列,但所有列的逻辑保持不变
以下查询会将逗号分隔的字符串 2:21,5:50,4:55,7:80,9:33
解析为单独的组件 2:21
、5:30
等。从那里您可以使用类似的方法从中提取 bb
aa:bb
.
由于 key-value 对的格式为 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
老实说,这些要求非常古怪。
请注意以下解决方案仅适用于 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
;
这是 SQL 服务器的一个痛点。您可以使用递归 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;
Here 是一个 db<>fiddle.
我有以下 table 以及以下数据
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
这个键值对必须被拆分成并且每个键的值必须按以下方式插入另一个table
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:当它在 tab1 中找到列 'FutureMISBoundaryVersion' 时,它的值 '2:21,5:50,4:55,7:80,9:33' 将被拆分,其值的插入方式是将键 2 i,e:21 的相应值插入到 FutureMIS 中-DURVersion 列。
类似地,键 5 的值 50 将被插入到 FutureMIS-BURVersion 列中,其他键依此类推
当它找到列 'CurrentMISBoundaryVersion' 时
'2:12,5:40,4:35,7:60,9:87' 将被拆分,其值将以键 2 i,e:12 的相应值插入到 CurrentMIS 中的方式插入-DURVersion 列类似地,键 5 的 40 值将被插入到 DeviceMIS-YRTVersion 列中,对于源 table 的其他列,依此类推。
table 结构可能会扩展,因为我只显示了 4 个源 table 列,但所有列的逻辑保持不变
以下查询会将逗号分隔的字符串 2:21,5:50,4:55,7:80,9:33
解析为单独的组件 2:21
、5:30
等。从那里您可以使用类似的方法从中提取 bb
aa:bb
.
由于 key-value 对的格式为 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
老实说,这些要求非常古怪。 请注意以下解决方案仅适用于 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
;
这是 SQL 服务器的一个痛点。您可以使用递归 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;
Here 是一个 db<>fiddle.