动态 SQL Split 函数从逗号分隔的字符串中添加条件不起作用
DynamicSQL Split function to add criteria from comma delimited string not working
我正在尝试使用拆分函数将一系列值添加到查询中。我也想 'OR' 将这些值放在一起,但首先要做的是。我正在按照我在一个使用 split 函数的更大查询中找到的示例进行操作,因此我进行了一个小查询以尝试弄清楚它是如何工作的。不过到目前为止,我得到的只是错误 *"The name 'Select * from Country As sp WHERE (sp.CountryID in (SELECT [Value] FROM dbo.Split('2,22,', ',')))' is not a valid identifier."* 我知道 DynamicSQL 并且我不太确定这个拆分函数应该如何工作。
DECLARE @Countries varchar(MAX);
DECLARE @FiltersOn bit;
DECLARE @Country int;
DECLARE @Query varchar(MAX);
Set @FiltersOn = 0;
Set @Query = 'Select * from Country As sp ';
Set @Countries ='2,22,'
IF ( @Countries IS NOT NULL )
BEGIN
IF ( @FiltersOn = 1 )
BEGIN
SET @Query = @Query + ' AND '
END
ELSE
BEGIN
SET @Query = @Query + ' WHERE '
SET @FiltersOn = 1
END
SET @Query = @Query
+ '(sp.CountryID in (SELECT [Value] FROM dbo.Split('''
+ @Countries + ''', '','')))'
END
EXEC @Query
这是国家/地区的定义table:
CREATE TABLE [dbo].[Country](
[CountryID] [int] IDENTITY(1,1) NOT NULL,
[AgentID] [int] NULL,
[Name] [varchar](50) NULL,
[CountryLookupID] [int] NOT NULL
这是拆分函数代码:
CREATE FUNCTION [dbo].[Split]
(
@String varchar(8000),
@Delimiter varchar(10)
)
RETURNS @ValueTable table ([Value] varchar(255))
BEGIN
DECLARE @NextString varchar(4000)
DECLARE @Pos int
DECLARE @NextPos int
DECLARE @DelimiterCheck varchar(1)
-- initialise
SET @NextString = ''
SET @DelimiterCheck = RIGHT(@String, 1)
-- add trailing delimiter
IF (@DelimiterCheck <> @Delimiter)
SET @String = @String + @Delimiter
-- find position of first delimiter
SET @Pos = CHARINDEX(@Delimiter, @String)
SET @NextPos = 1
-- loop while there is a delimiter in the string
WHILE (@Pos <> 0)
BEGIN
SET @NextString = SUBSTRING(@String, 1, @Pos - 1)
INSERT INTO @ValueTable ([Value]) VALUES (@NextString)
SET @String = SUBSTRING(@String, @Pos + 1, LEN(@String))
SET @NextPos = @Pos
SET @Pos = CHARINDEX(@Delimiter, @String)
END
RETURN
END
您没有正确编写 EXEC
语句。
使用EXEC (@Query)
代替EXEC @Query
这不是您问题的直接答案,但我可以推荐通读一些内容,因为我已经看到这些解决方案以前在系统中造成问题。
我建议不要使用使用 WHILE 循环的解决方案。 While 循环不断产生性能问题,因为 SQL 服务器不具备优化循环的能力,例如 C# 引擎。
也不确定为什么要使用动态 SQL。如果你想确保没有 SQL 注入,请使用 sp_executesql 代替,因为它会检查有害代码,但我会避免使用动态 sql 除非我们不知道结构我们的基础数据(因此需要动态 sql)。
刚刚编写了一个函数,用于使用 cte 进行字符串拆分以保持性能。
CREATE SCHEMA Util;
GO
CREATE FUNCTION Util.String_Split (
@Text varchar(MAX),
@SplitChar char
)
RETURNS TABLE
AS
RETURN(
WITH cte AS
(
SELECT
1 AS [RowNumber],
X.Text,
X.RemainingText
FROM
(
SELECT
SUBSTRING(@Text, 1, CHARINDEX(';', @Text) - 1) AS [Text],
SUBSTRING(@Text, CHARINDEX(';', @Text) + 1, LEN(@Text) - CHARINDEX(';', @Text)) AS [RemainingText]
) X
UNION ALL
SELECT
cte.RowNumber + 1,
X.Text,
X.RemainingText
FROM
cte
CROSS APPLY (
SELECT
SUBSTRING(cte.RemainingText, 1, ISNULL(NULLIF(CHARINDEX(';', cte.RemainingText) - 1, -1), LEN(cte.RemainingText))) AS [Text],
CASE
WHEN CHARINDEX(';', cte.RemainingText) = 0 THEN
''
ELSE
SUBSTRING(cte.RemainingText, CHARINDEX(';', cte.RemainingText) + 1, LEN(cte.RemainingText))
END AS [RemainingText]
) X
WHERE
X.Text ''
)
SELECT
cte.Text
FROM
cte
WHERE
cte.Text IS NOT NULL
);
然后您可以使用此调用在没有动态部分的情况下进行查询:
SELECT
*
FROM
Country sp
WHERE
@Countries IS NULL
OR
sp.CountryId IN (
SELECT * FROM Util.String_Split(@Countries, ',')
)
我正在尝试使用拆分函数将一系列值添加到查询中。我也想 'OR' 将这些值放在一起,但首先要做的是。我正在按照我在一个使用 split 函数的更大查询中找到的示例进行操作,因此我进行了一个小查询以尝试弄清楚它是如何工作的。不过到目前为止,我得到的只是错误 *"The name 'Select * from Country As sp WHERE (sp.CountryID in (SELECT [Value] FROM dbo.Split('2,22,', ',')))' is not a valid identifier."* 我知道 DynamicSQL 并且我不太确定这个拆分函数应该如何工作。
DECLARE @Countries varchar(MAX);
DECLARE @FiltersOn bit;
DECLARE @Country int;
DECLARE @Query varchar(MAX);
Set @FiltersOn = 0;
Set @Query = 'Select * from Country As sp ';
Set @Countries ='2,22,'
IF ( @Countries IS NOT NULL )
BEGIN
IF ( @FiltersOn = 1 )
BEGIN
SET @Query = @Query + ' AND '
END
ELSE
BEGIN
SET @Query = @Query + ' WHERE '
SET @FiltersOn = 1
END
SET @Query = @Query
+ '(sp.CountryID in (SELECT [Value] FROM dbo.Split('''
+ @Countries + ''', '','')))'
END
EXEC @Query
这是国家/地区的定义table:
CREATE TABLE [dbo].[Country](
[CountryID] [int] IDENTITY(1,1) NOT NULL,
[AgentID] [int] NULL,
[Name] [varchar](50) NULL,
[CountryLookupID] [int] NOT NULL
这是拆分函数代码:
CREATE FUNCTION [dbo].[Split]
(
@String varchar(8000),
@Delimiter varchar(10)
)
RETURNS @ValueTable table ([Value] varchar(255))
BEGIN
DECLARE @NextString varchar(4000)
DECLARE @Pos int
DECLARE @NextPos int
DECLARE @DelimiterCheck varchar(1)
-- initialise
SET @NextString = ''
SET @DelimiterCheck = RIGHT(@String, 1)
-- add trailing delimiter
IF (@DelimiterCheck <> @Delimiter)
SET @String = @String + @Delimiter
-- find position of first delimiter
SET @Pos = CHARINDEX(@Delimiter, @String)
SET @NextPos = 1
-- loop while there is a delimiter in the string
WHILE (@Pos <> 0)
BEGIN
SET @NextString = SUBSTRING(@String, 1, @Pos - 1)
INSERT INTO @ValueTable ([Value]) VALUES (@NextString)
SET @String = SUBSTRING(@String, @Pos + 1, LEN(@String))
SET @NextPos = @Pos
SET @Pos = CHARINDEX(@Delimiter, @String)
END
RETURN
END
您没有正确编写 EXEC
语句。
使用EXEC (@Query)
代替EXEC @Query
这不是您问题的直接答案,但我可以推荐通读一些内容,因为我已经看到这些解决方案以前在系统中造成问题。
我建议不要使用使用 WHILE 循环的解决方案。 While 循环不断产生性能问题,因为 SQL 服务器不具备优化循环的能力,例如 C# 引擎。
也不确定为什么要使用动态 SQL。如果你想确保没有 SQL 注入,请使用 sp_executesql 代替,因为它会检查有害代码,但我会避免使用动态 sql 除非我们不知道结构我们的基础数据(因此需要动态 sql)。
刚刚编写了一个函数,用于使用 cte 进行字符串拆分以保持性能。
CREATE SCHEMA Util;
GO
CREATE FUNCTION Util.String_Split (
@Text varchar(MAX),
@SplitChar char
)
RETURNS TABLE
AS
RETURN(
WITH cte AS
(
SELECT
1 AS [RowNumber],
X.Text,
X.RemainingText
FROM
(
SELECT
SUBSTRING(@Text, 1, CHARINDEX(';', @Text) - 1) AS [Text],
SUBSTRING(@Text, CHARINDEX(';', @Text) + 1, LEN(@Text) - CHARINDEX(';', @Text)) AS [RemainingText]
) X
UNION ALL
SELECT
cte.RowNumber + 1,
X.Text,
X.RemainingText
FROM
cte
CROSS APPLY (
SELECT
SUBSTRING(cte.RemainingText, 1, ISNULL(NULLIF(CHARINDEX(';', cte.RemainingText) - 1, -1), LEN(cte.RemainingText))) AS [Text],
CASE
WHEN CHARINDEX(';', cte.RemainingText) = 0 THEN
''
ELSE
SUBSTRING(cte.RemainingText, CHARINDEX(';', cte.RemainingText) + 1, LEN(cte.RemainingText))
END AS [RemainingText]
) X
WHERE
X.Text ''
)
SELECT
cte.Text
FROM
cte
WHERE
cte.Text IS NOT NULL
);
然后您可以使用此调用在没有动态部分的情况下进行查询:
SELECT
*
FROM
Country sp
WHERE
@Countries IS NULL
OR
sp.CountryId IN (
SELECT * FROM Util.String_Split(@Countries, ',')
)