【问题标题】:Insert new row into a table for each value in the comma separated list of values passed to a stored procedure为传递给存储过程的逗号分隔值列表中的每个值插入新行
【发布时间】:2021-06-10 10:31:07
【问题描述】:

我有一个如下所示的表格,Id 是标识列。

Id | StudentId | DepartmentId | Comments | Date

我需要创建一个存储过程,它接受一个由逗号分隔的 StudentId 列表,并为逗号分隔列表中的每个 StudentId 插入一个新行。

我尝试了以下方式,但这不是正确的方式

CREATE PROC usp_UpdateStudentAttendance
@StudentIds VARCHAR(max),
@DepartmentId INT
AS
BEGIN
INSERT INTO [dbo].[StudentAttendance] ([StudentId], [DepartmentId], [Comments], [Date])
SELECT CAST(Items AS INT), @DepartmentId, 'Attended', GETDATE() FROM dbo.splitstring(@StudentIds, ',')
END

我收到错误“无效的对象名称 'STRING_SPLIT'”

看起来我的数据库版本不兼容使用 STRING_SPLIT ,我们还有其他选择吗?

尝试使用以下功能。

CREATE FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) )
RETURNS
 @returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN

 DECLARE @name NVARCHAR(255)
 DECLARE @pos INT

 WHILE CHARINDEX(',', @stringToSplit) > 0
 BEGIN
  SELECT @pos  = CHARINDEX(',', @stringToSplit)  
  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
 END

 INSERT INTO @returnList
 SELECT @stringToSplit

 RETURN
END

【问题讨论】:

  • “我尝试了下面的方法,但那不是正确的方法” 为什么不是?我们没有dbo.Split 的定义,因此我们无法运行您的代码。为什么不使用内置函数 STRING_SPLIT 呢?或者修改您的过程以接受表类型参数。
  • “不是正确的方式”没有任何意义。如果您有错误,请发布它,如果它没有达到您的预期,请解释它
  • @Larnu 我厌倦了 STRING_SPLIT 并更新了我的帖子..
  • 我猜你使用的是旧版本的 SQL Server,@user187,因为STRING_SPLIT 在每个受支持的 SQL Server 版本中。要么发布你的函数定义,dbo.Split,使用不同的(例如DelimitedSplit8K_LEAD,或 XML 拆分器)或使用表类型参数,然后你根本不需要拆分器。
  • 这能回答你的问题吗? SQL Server split CSV into multiple rows

标签: sql sql-server tsql stored-procedures


【解决方案1】:

您可以尝试使用 XML 来完成此任务。举个例子:

DECLARE @DepartmentId INT = 123;
DECLARE @str NVARCHAR(100) = 'Student1, Student2, Student3';

DECLARE @t TABLE(xstr XML);
INSERT INTO @t VALUES (CAST('<students><student>' + REPLACE(@str, ', ', '</student><student>') + '</student></students>' AS XML))

SELECT T.r.value('.','varchar(100)') as student, @DepartmentId AS DepartmentId, 'Attended' AS Comments, GETDATE() AS [Date]
FROM @t
OUTER APPLY
xstr.nodes('/students/student') t(r)

【讨论】:

    【解决方案2】:

    最好使用表格类型参数

    CREATE TYPE dbo.IntList AS TABLE (val int);
    
    GO
    
    CREATE OR ALTER PROC usp_UpdateStudentAttendance
      @StudentIds dbo.IntList,
      @DepartmentId int
    AS
    
    INSERT INTO [dbo].[StudentAttendance]
        ([StudentId], [DepartmentId], [Comments], [Date])
    SELECT val, @DepartmentId, 'Attended', GETDATE()
    FROM @StudentIds;
    
    GO
    

    我通常会使用一些标准的单列表类型。

    【讨论】:

      【解决方案3】:
      CREATE OR ALTER FUNCTION [dbo].[udf_EC_SplitString]
          (
            @ipString VARCHAR(8000),
            @ipDelimiter CHAR(1)
          )
      RETURNS @myTable TABLE
          (
            STRING_VALUE VARCHAR(8000)
          )
      AS 
      BEGIN        
          DECLARE @lvDelimeterIndex INT        
          DECLARE @lvCurrentStringValue VARCHAR(8000)        
             
          SELECT  @lvDelimeterIndex = 1        
          IF LEN(@ipString) < 1
              OR @ipString IS NULL 
              RETURN        
             
          WHILE @lvDelimeterIndex != 0        
              BEGIN   
                  -- Find Delimiter Location     
                  SET @lvDelimeterIndex = CHARINDEX(@ipDelimiter, @ipString)        
                  -- Check Index Value
                  IF @lvDelimeterIndex != 0 
                  BEGIN
                      -- If Delimeter Found then Find Current STRING_VALUE 
                      SET @lvCurrentStringValue = LEFT(@ipString, @lvDelimeterIndex - 1)        
                  END
                  ELSE 
                  BEGIN
                      -- If Delimeter Not Found then remaining string is current STRING_VALUE
                      SET @lvCurrentStringValue = @ipString        
                  END           
                  IF ( LEN(@lvCurrentStringValue) > 0 ) 
                      INSERT  INTO @myTable VALUES  ( @lvCurrentStringValue )        
                  -- Find Remaining String
                  SET @ipString = RIGHT(@ipString, LEN(@ipString) - @lvDelimeterIndex)        
                  -- Exit if Remaining String is Completed
                  IF LEN(@ipString) = 0 
                      BREAK        
              END    
          RETURN        
      END  
      

      上面的函数有两个参数,第一个是用分隔符分隔的字符串,另一个是分隔符。正如我们正在讨论逗号分隔的字符串,所以下面的调用将在没有任何问题的情况下正常工作。请尝试

      select * from [dbo].[udf_EC_SplitString]('India,USA,Canada',',')
      

      【讨论】:

        猜你喜欢
        • 2016-02-07
        • 1970-01-01
        • 2016-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多