如何分离变量和值,然后在表中插入?

时间:2019-02-01 15:37:14

标签: sql-server loops tsql sql-server-2016 dynamic-sql

问题

存储过程正在接收变量和值以及定界符的列表。此存储过程需要将它们插入表中。

--Example table
create table #tempo
(
    Variable1 int,
    Variable2 int,
    Variable3 int
)

这些是存储过程的参数:

declare @variableList varchar(100)
declare @valueList varchar(100)
declare @separator char(1)

set @variableList = 'Variable1#Variable2#Variable3'
set @valueList = '1111#2222#3333'
set @separator = '#'

结果

我想实现的是这样:

select * from #tempo

+---------+---------+---------+
|Variable1|Variable2|Variable3|
+---------+---------+---------+
|1111     |2222     |3333     |
+---------+---------+---------+

一种实现方式

我可以使用循环并构建动态SQL,但我想避免这种情况。除了不使用动态SQL的明显原因外,循环结构难以维护,解释和测试也可能成为问题。

理想方式

我想一个更优雅的方式来做到这一点,例如使用string_splitcoalesce等,但不能想出一个办法,而不使用动态SQL或循环。

2 个答案:

答案 0 :(得分:1)

如果您始终具有相同的列名集,则很容易进行透视操作,但是如果列正在更改,则可以使用具有动态调整的变量列表的同一脚本(作为参数或直接从中读取)临时表:

INSERT INTO #tempo SELECT *
FROM (
    SELECT [value], rv = 'Variable' + CAST(Row_Number() OVER ( ORDER BY (SELECT 1)) as VARCHAR)
    FROM STRING_SPLIT(@valueList,@separator)
) AS src
PIVOT (MAX([value]) FOR rv IN (Variable1,Variable2,Variable3)) AS pvt;

答案 1 :(得分:1)

您始终可以尝试透视数据。这只是选择,但可以很容易地将插入物包裹在其中。

我们使用具有行ID的拆分字符串来允许两个拆分数据集的匹配。功能是:

CREATE FUNCTION [dbo].[Split] (@RowData NVARCHAR(MAX), @SplitOn NVARCHAR(5))
    RETURNS @RtnValue TABLE (Id INT IDENTITY(1, 1), Data NVARCHAR(100))
    AS
        BEGIN
            DECLARE @Cnt INT;

            SET @Cnt = 1;

            WHILE (CHARINDEX(@SplitOn, @RowData) > 0)
                BEGIN
                    INSERT INTO @RtnValue (Data)
                    SELECT  Data = LTRIM(RTRIM(SUBSTRING(@RowData, 1, CHARINDEX(@SplitOn, @RowData) - 1)));

                    SET @RowData = SUBSTRING(@RowData, CHARINDEX(@SplitOn, @RowData) + 1, LEN(@RowData));
                    SET @Cnt = @Cnt + 1;
                END;

            INSERT INTO @RtnValue (Data)
            SELECT  Data = LTRIM(RTRIM(@RowData));

            RETURN;
        END;

然后,您可以将这两个集合结合在一起以提供一些键值对,然后从中透视出数据以提供所需的格式。如果将最后一个选择替换为先前任何一个CTE的选择,那么您将了解逻辑的展开方式。

DECLARE @variableList VARCHAR(100);
DECLARE @valueList VARCHAR(100);
DECLARE @separator CHAR(1);

SET @variableList = 'Variable1,Variable2,Variable3';
SET @valueList = '1111, 2222, 3333';
SET @separator = ',';

WITH cteVar AS (SELECT  Id, Data FROM   dbo.Split(@variableList, @separator) )
,    cteVal AS (SELECT  Id, Data FROM   dbo.Split(@valueList, @separator) )
,    cteData AS
    (SELECT cteVar.Data VariableData
     ,      cteVal.Data ValueData
       FROM cteVar
       JOIN cteVal ON cteVal.Id = cteVar.Id)
,    ctePivot AS
    (SELECT *
       FROM cteData
         PIVOT (   MAX(ValueData)
                   FOR VariableData IN ([Variable1], [Variable2], [Variable3])) AS PivotTable)
SELECT  *
  FROM  ctePivot;

这是一个很长的解决方法,但希望它能很好地帮助您理解所涉及的步骤。无论如何,值得一看的是Pivot函数,它有据可查。