T-SQL——将字符串转为单列

时间:2023-02-25 08:07:38

shanzm-2023年2月22日

0. 背景

代码中执行存储过程,参数是多个且不确定数量,期望SQL查询时使用该参数作为IN的筛选条件

比如说,具体参数@Ids="1,2,3,4",

期望在存储过程中,实现 select * from Table where id In @Ids

直接这样写会报错

(当然可以使用动态sql 进行拼接,但不需要这么做),而是将传递的参数分裂为单列的行记录!



1. 使用STRING_SPLIT函数

  • Sql Server在2016版本中支持使用STRING_SPLIT函数

    • 可以将字符串按照分隔符,切割成一个数据表
  • 若是低版本数据使用提示对象名 'STRING_SPLIT' 无效。

SELECT * FROM STRING_SPLIT('1,2,3,4,5', ',');

--结果:
value
-------------
1
2
3
4
5


2. 自定义分裂函数

  • 实现方式1:基于字符串操作

    • 将目标字符串末尾拼接上一个分隔符
    • 从字符串第一个位置开始查询分隔符在字符串中第一次出现的位置索引
    • 从左截取(第一个分隔符索引-1)长度的字符串,此外分裂出的第一个结果
    • 将目标字符串从第一个分隔符之前的替换为空
    • 循环上述2~4步骤
-- ======================================================
-- Author:		shanzm
-- Create date: 2021年6月30日 15:52:02
-- Description:	将指定字符串按照指定的分裂符分裂为单列表            
-- ======================================================
ALTER FUNCTION [dbo].[funGetSplitStr]
(
    @Str VARCHAR(8000),       --目标字符串,形如"a,b,c"
    @StrSeprate VARCHAR(1)    --分隔符,形如","
)
RETURNS @temp TABLE           --返回表值变量,只有一列F1
(
    F1 VARCHAR(100)
)
AS
BEGIN
    DECLARE @ch AS VARCHAR(100);
    SET @Str = @Str + @StrSeprate;
    WHILE (@Str <> '')
    BEGIN
        SET @ch = LEFT(@Str, CHARINDEX(@StrSeprate, @Str, 1) - 1);
        INSERT @temp
        VALUES
        (@ch);
        SET @Str = STUFF(@Str, 1, CHARINDEX(@StrSeprate, @Str, 1), '');
    END;
    RETURN;
END;


  • 实现方式2:基于XML
-- ======================================================
-- Author:		shanzm
-- Create date: 2021年6月30日 15:52:02
-- Description:	将指定字符串按照指定的分裂符分裂为单列表            
-- ======================================================
CREATE FUNCTION dbo.funGetSplitStr2
(
    @str varchar(1000),
    @strSperate varchar(10)
)
RETURNS @tableVar TABLE
(
    F1 VARCHAR(100)
)
AS
BEGIN
    DECLARE @xmlstr XML;
    --SET ARITHABORT ON;
    SET @xmlstr = CONVERT(XML, '<root><v>' + REPLACE(@str, @strSperate, '</v><v>') + '</v></root>');
    --SELECT @xmlstr;

    INSERT INTO @tableVar
    SELECT F1 = N.v.value('.', 'varchar(100)') FROM @xmlstr.nodes('/root/v') N(v);
	RETURN;
END;
GO


--测试
SELECT * FROM  funGetSpliterStr2('1.2.3','.')

--结果

F1
---------
1
2
3

(3 行受影响)


3. 使用示例

代码中传递的参数@Ids="1,2,3,4",执行存储过程作为筛选条件

这里任意使用一个测试表Company,该表有一个Id字段,存储过程简单的演示了Ids字符串进行查询

  • 创建测试存储过程
CREATE PROCEDURE [dbo].[proTest]
@Ids VARCHAR(500)
AS
BEGIN
    SELECT *
    FROM dbo.Company
    WHERE Id IN
          (
              SELECT F1 FROM dbo.funGetSplitStr(@Ids, ',')
          );
END;


EXEC dbo.proTest @Ids = '1,3';