如何在SQL Server数据库中使用函数/存储过程实现以下目标

时间:2019-05-27 02:00:20

标签: sql sql-server sql-function

我有下表,其中以下数据为

                                            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:当它在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列,对于源表的其他列,依此类推。

表结构可能会扩展,因为我只显示了4个源表列,但所有列的逻辑都保持不变

3 个答案:

答案 0 :(得分:0)

以下查询将逗号分隔的字符串2:21,5:50,4:55,7:80,9:33解析为单独的分量2:215:30等。从那里您可以使用类似的方法从{{ 1}}。

由于键值对的格式为bb,因此您可以使用aa:bbaa:bb提取datepart(hour, 'aa:bb')datepart(minute, 'aa:bb')

aa

答案 1 :(得分:0)

说实话非常时髦的要求。 请注意,以下解决方案仅在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
;

答案 2 :(得分:0)

这在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;

Here是db <>小提琴。