循环并在 SQL 中插入多个逗号分隔的列表

Loop and insert more than one comma separated List in SQL

我希望遍历两个逗号分隔值并执行插入

举个例子让我们考虑两个变量

Declare   @Qid= 1,4,6,7,8   @Answers = 4,4,3,2,3

set @pos = 0
set @len = 0

WHILE CHARINDEX(',', @Answers, @pos+1)>0
BEGIN
    set @len = CHARINDEX(',', @Answers, @pos+1) - @pos
    set @value = SUBSTRING(@Answers, @pos, @len)

insert into table values(@fdid,@Qid,@fusid, @value)  -- i need Qid also

set @pos = CHARINDEX(',', @Answers, @pos+@len) +1
END

使用这个循环我可以提取 @Answers 并可以执行插入。但我希望提取 @Qid 并插入循环中。

编辑 为了更清楚,它是一个反馈模块。我的结果 table 有 Qid 和 Answer 字段。答案是评分(1 到 5)。我们在变量@Qid 和@Answers 中获得的值是连续的。这意味着第一个答案将针对第一个问题,依此类推。

编辑

根据 Shnugo 的回答

Declare @Qid varchar(100)= '1,4,6,7,8',   @Answers varchar(100)= '4,4,3,2,3'
DECLARE @tbl TABLE(ID INT IDENTITY, Questions VARCHAR(100),Answers VARCHAR(100));
INSERT INTO @tbl VALUES(@Qid,@Answers)


 INSERT INTO table(FeedbackId,QuestionId,FeedbackUserId,Answer)
 SELECT  1,
  A.qXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS QuestionNumber,3
      ,A.aXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS AnwerNumber
FROM @tbl t
CROSS APPLY(SELECT CAST('<x>' + REPLACE(@Qid,',','</x><x>') + '</x>' AS XML)
                  ,CAST('<x>' + REPLACE(@Answers,',','</x><x>') + '</x>' AS XML)) A(qXml,aXml)
CROSS APPLY(SELECT TOP(A.qXml.value('count(/x)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) B(QuestionCount)

如果您使用 SQL Server 2016 或更高版本,您可以尝试使用下一个基于 JSON 的方法来根据输入字符串中的位置映射问题和答案。您需要将输入字符串转换为有效的 JSON 数组,然后使用具有默认模式的 OPENJSON() 来解析这些数组。结果是 table,包含 keyvaluetype 列,key 列包含指定数组中元素的索引。

请注意,STRING_SPLIT() 函数不保证行的顺序,输出行可能是任何顺序。

声明:

DECLARE @Qid nvarchar(max) = N'1,4,6,7,8'
DECLARE @Answers nvarchar(max) = N'4,4,3,2,3'

-- Build your INSERT statement as you expect
-- INSERT INTO Table ...
SELECT j1.[value] AS Qid, j2.[value] AS Answers  
FROM OPENJSON(CONCAT(N'[', @Qid, N']')) j1
JOIN OPENJSON(CONCAT(N'[', @Answers, N']')) j2 ON j1.[key] = j2.[key]

SELECT 语句的结果:

Qid Answers
1   4
4   4
6   3
7   2
8   3

您没有描述问题与答案的关系。我觉得是一对一的关系,为此,我给出了答案。

declare @Qid varchar(200)= '1,4,6,7,8' , @Answers varchar(200) = '4,4,3,2,3'

;with cte
as(
    select id, data qid from dbo.Split (@qid, ',') 
),
cte1 as
(
select id, data ansid from dbo.Split (@answers, ',') 
)


--insert into tablename 
select
qid, ansid from cte join cte1 on cte.id = cte1.id

结果将是:

qid ansid
1    4
4    4
6    3
7    2
8    3

查看更高版本的 sqlserver 的其他选项:Split function equivalent in T-SQL?

我更喜欢 (需要 v2016+)。

如果您使用 2016 年以下的 SQL-服务器,您可能会使用这个位置安全的基于 XML 的解决方案:

一个 模型 table 用两个不同的行来模拟您的问题。

DECLARE @tbl TABLE(ID INT IDENTITY, Questions VARCHAR(100),Answers VARCHAR(100));
INSERT INTO @tbl VALUES('1,4,6,7,8','4,4,3,2,3')
                      ,('1,2,3','4,5,6');

--查询

SELECT t.*
      ,A.qXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS QuestionNumber
      ,A.aXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS AnwerNumber
FROM @tbl t
CROSS APPLY(SELECT CAST('<x>' + REPLACE(t.Questions,',','</x><x>') + '</x>' AS XML)
                  ,CAST('<x>' + REPLACE(t.Answers,',','</x><x>') + '</x>' AS XML)) A(qXml,aXml)
CROSS APPLY(SELECT TOP(A.qXml.value('count(/x)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) B(QuestionCount);

简而言之:

我们需要 CROSS APPLY 和一些字符串方法来将 1,2,3 之类的内容转换为 xml 之类的 <x>1</x><x>2</x><x>3</x>.
现在我们可以使用 value() 和 XQuery count() 来查找问题的实际数量。
我们还需要一个带有计算 TOP() 子句的 CROSS APPLY 来获得一组从 1 到 n 的 运行 数字,n=countOfQuestions。我这样做反对 master..spt_values。这只是一个填充良好的标准 table...我们不需要值,只需要任何集合来创建计数器...
最后,我们可以将 .value()sql:column() 结合使用,以便按位置获取问题和相应的答案。

更新:非表格数据

如果您没有将这些 CSV 参数作为 table 获取,您可以使用:

Declare @Qid varchar(100)= '1,4,6,7,8',   @Answers varchar(100)= '4,4,3,2,3'

--INSERT INTO table(FeedbackId,QuestionId,FeedbackUserId,Answer)
SELECT  1
       ,A.qXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS QuestionNumber
       ,3
       ,A.aXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS AnwerNumber
FROM (SELECT CAST('<x>' + REPLACE(@Qid,',','</x><x>') + '</x>' AS XML)
            ,CAST('<x>' + REPLACE(@Answers,',','</x><x>') + '</x>' AS XML)) A(qXml,aXml)
CROSS APPLY(SELECT TOP(A.qXml.value('count(/x)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) B(QuestionCount);