T-SQL:将列转换为行并且 insert/update 另一个 table

T-SQL: convert columns to rows and insert/update another table

正在寻找适合初级开发人员的简单、易于调试的解决方案... 在 SQL Server 2008 R2 中,我必须以所需格式将数据从 #data table 更新为 #tests table。我不确定如何使用 T-SQL 查询来存档结果?

注意:temp tables 只有 3 列仅用于示例目的,但真正的 table 每组有超过 50 列。

这是我的 table 的样子:

IF OBJECT_ID('tempdb..#tests') IS NOT NULL 
    DROP TABLE #tests
GO

CREATE TABLE #tests
(
    id int,
    FirstName varchar(100),
    LastName varchar(100),
    UniueNumber varchar(100)
)

IF OBJECT_ID('tempdb..#data') IS NOT NULL 
    DROP TABLE #data
GO

CREATE TABLE #data
(
    id int,
    FirstName1 varchar(100),
    LastName1 varchar(100),
    UniueNumber1 varchar(100),
    FirstName2 varchar(100),
    LastName2 varchar(100),
    UniueNumber2 varchar(100),
    FirstName3 varchar(100),
    LastName3 varchar(100),
    UniueNumber3 varchar(100),
    FirstName4 varchar(100),
    LastName4 varchar(100),
    UniueNumber4 varchar(100),
    FirstName5 varchar(100),
    LastName5 varchar(100),
    UniueNumber5 varchar(100),
    FirstName6 varchar(100),
    LastName6 varchar(100),
    UniueNumber6 varchar(100),
    FirstName7 varchar(100),
    LastName7 varchar(100),
    UniueNumber7 varchar(100)
)

INSERT INTO #data 
VALUES (111, 'Tom', 'M', '12345', 'Sam', 'M', '65432', 'Chris', 'PATT', '54656', 'Sean', 'Meyer', '865554', 'Mike', 'Max', '999999', 'Tee', 'itc', '656546444', 'Mickey', 'Mul', '65443231')

INSERT INTO #data  
VALUES (222, 'Kurr', 'P', '22222', 'Yammy', 'G', '33333', 'Saras', 'pi', '55555', 'Man', 'Shey', '666666', 'Max', 'Dopit', '66666678', '', '', '', '', '', '')

INSERT INTO #data 
VALUES (333, 'Mia', 'K', '625344', 'Tee', 'TE', '777766', 'david', 'mot', '4444444', 'Jeff', 'August', '5666666', 'Mylee', 'Max', '0000000', '', '', '', 'Amy', 'Marr', '55543444')

SELECT * 
FROM #data

我想从#data table insert/update 数据到#tests table。 如果 #data table 中不存在 id 和 UniqueNumber 组合,则将数据插入 #tests table。如果存在组合,则将数据从#data table

更新到#tests table

这是#tests 中所需的输出 table

一种方法是分别查询每组列并UNION结果

SELECT 
    id int,
    FirstName1 as FirstName,
    LastName1 as LastName,
    UniueNumber1 AS SSN
FROM #data
UNION 
SELECT 
    id int,
    FirstName2 as FirstName,
    LastName2 as LastName,
    UniueNumber2 AS SSN
FROM #data
UNION 
...

没有一种方法可以干净地“循环遍历”7 组列 - 与仅仅复制和粘贴查询 6 次并更改数字相比,您将花费更多时间构建循环以动态创建查询。

当然,如果可能的话,现在最好避免#data中的结构类型。

这是一个选项,可以在不使用动态 SQL

的情况下动态反透视您的数据

明确一点: UNPIVOT 会更高效,但您不必枚举 50 列。

这是假设您的列以数字结尾,即 FirstName##

例子

Select ID
      ,FirstName
      ,LastName
      ,UniueNumber  -- You could use SSN = UniueNumber  
 From  (
        SELECT A.ID
              ,Grp
              ,Col = replace([Key],Grp,'')
              ,Value
        FROM #data A
        Cross Apply (
                        Select [Key]
                              ,Value
                              ,Grp = substring([Key],patindex('%[0-9]%',[Key]),25)
                         From OpenJson( (Select A.* For JSON Path,Without_Array_Wrapper  ) ) 
                    ) B
       ) src
 Pivot ( max(Value) for Col in ([FirstName],[LastName],[UniueNumber]) ) pvt
 Order By ID,Grp

结果

更新XML版本

Select ID
      ,FirstName
      ,LastName
      ,UniueNumber
 From  (
        SELECT A.ID
              ,Grp  = substring(Item,patindex('%[0-9]%',Item),50)
              ,Col  = replace(Item,substring(Item,patindex('%[0-9]%',Item),50),'')
              ,Value
        FROM #data A
        Cross Apply ( values (convert(xml,(Select A.* for XML RAW)))) B(XData)
        Cross Apply (
                        Select Item  = xAttr.value('local-name(.)', 'varchar(100)')
                              ,Value = xAttr.value('.','varchar(max)')
                         From  B.XData.nodes('//@*') xNode(xAttr)
                    ) C
        Where Item not in ('ID')
       ) src
 Pivot ( max(Value) for Col in (FirstName,LastName,UniueNumber) ) pvt
 Order By ID,Grp