当 where 子句与 table 值函数一起使用时会发生错误?
Error occurs when a where clause is used with a table valued function?
我有以下 table 值的 UDF:
CREATE FUNCTION [dbo].[funParseRestParams](
@Params NVARCHAR(MAX),
@Delim VARCHAR(100))
RETURNS TABLE
AS
RETURN (
SELECT
LTRIM(RTRIM(SUBSTRING([Argument], 1, CHARINDEX('=', [Argument], 1) - 1))) Parameter,
LTRIM(RTRIM(SUBSTRING([Argument], CHARINDEX('=', [Argument], 1) + 1, LEN([Argument]) - CHARINDEX('=', [Argument], 1)))) Value
FROM (
SELECT
LTRIM(RTRIM(SUBSTRING(@Params, [Number], CHARINDEX(@Delim, @Params + @Delim, [Number]) - [Number]))) [Argument]
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY name) [Number]
FROM sys.all_objects) AS x
WHERE Number <= LEN(@Params) AND SUBSTRING(@Delim + @Params, [Number], LEN(@Delim)) = @Delim) AS y);
GO
我正在 运行 使用来自 ReportServer.dbo.ExecutionLogStorage
的参数字符串在游标中进行此操作。参数看起来像这样:"Some%20Param%20Name=Hello&Some%20Other%20Param=NoLuck"
当我 运行 游标中的函数是这样的:
SELECT * FROM Reports.dbo.funParseRestParams(@Param, '&')
一切都很好,但是当我添加一个 where 子句时:
SELECT * FROM Reports.dbo.funParseRestParams(@Param, '&') R
WHERE R.[Parameter] = 'AccessType'
我每次都收到以下错误消息:
Msg 537, Level 16, State 3, Line 13
Invalid length parameter passed to the LEFT or SUBSTRING function.
那么为什么我的 where 子句会终止函数?
编辑:添加一些额外的东西。您可以将下面的代码粘贴到 SQL 服务器以复制此错误。该错误仅在使用 "first" 列(where 子句中的参数列)时发生。在 where 子句中使用 "second" 值列不会导致错误。您可以删除下面的评论以查看实际效果:
DECLARE @Params NVARCHAR(MAX)
DECLARE @Delim VARCHAR(1)
SET @Params = 'Greeting=Hello&Name=George&Dessert=Jello'
SET @Delim = '&'
SELECT * FROM (
SELECT
LTRIM(RTRIM(SUBSTRING([Argument], 1, CHARINDEX('=', [Argument], 1) - 1))) Parameter,
LTRIM(RTRIM(SUBSTRING([Argument], CHARINDEX('=', [Argument], 1) + 1, LEN([Argument]) - CHARINDEX('=', [Argument], 1)))) Value
FROM (
SELECT
LTRIM(RTRIM(SUBSTRING(@Params, [Number], CHARINDEX(@Delim, @Params + @Delim, [Number]) - [Number]))) [Argument]
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY name) [Number]
FROM sys.all_objects) AS x
WHERE [Number] <= LEN(@Params) AND SUBSTRING(@Delim + @Params, [Number], LEN(@Delim)) = @Delim) AS y
) R
--WHERE R.Parameter = 'AccessType'
--WHERE R.Parameter = 'Greeting'
--WHERE R.Value = 'Bananas'
--WHERE R.Value = 'Jello'
您不妨考虑以下内容:
CREATE FUNCTION dbo.SplitStrings_Moden
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
WITH E1(N) AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
E2(N) AS (SELECT 1 FROM E1 a, E1 b),
E4(N) AS (SELECT 1 FROM E2 a, E2 b),
E42(N) AS (SELECT 1 FROM E4 a, E2 b),
cteTally(N) AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1)))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0))
SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000))
FROM cteStart s;
此代码归功于 Jeff Moden here。该站点还有其他方法。可能值得采用经过充分审查的解决方案(您也必须自己审查),而不是试图重新发明轮子并且不得不花费过多的时间来调试它。
我访问了 MSDN 以搜索答案,我得到了一个。我仍在查看细节,但出于某种原因,以下作品在原始作品中没有。第一个子查询的第二行被改变:
DECLARE @Params NVARCHAR(MAX)
DECLARE @Delim VARCHAR(1)
SET @Params = 'Greeting=Hello&Name=George&Dessert=Jello'
SET @Delim = '&'
SELECT * FROM (
SELECT
LTRIM(RTRIM(SUBSTRING([Argument], 0, CHARINDEX('=', [Argument], 1) ))) Parameter,
LTRIM(RTRIM(SUBSTRING([Argument], CHARINDEX('=', [Argument], 1) + 1, LEN([Argument]) - CHARINDEX('=', [Argument], 1)))) Value
FROM (
SELECT
LTRIM(RTRIM(SUBSTRING(@Params, [Number], CHARINDEX(@Delim, @Params + @Delim, [Number]) - [Number]))) [Argument]
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY name) [Number]
FROM sys.all_objects) AS x
WHERE [Number] <= LEN(@Params) AND SUBSTRING(@Delim + @Params, [Number], LEN(@Delim)) = @Delim) AS y
) R
--WHERE R.Parameter = 'AccessType'
WHERE R.Parameter = 'Greeting'
--WHERE R.Value = 'Bananas'
--WHERE R.Value = 'Jello'
我有以下 table 值的 UDF:
CREATE FUNCTION [dbo].[funParseRestParams](
@Params NVARCHAR(MAX),
@Delim VARCHAR(100))
RETURNS TABLE
AS
RETURN (
SELECT
LTRIM(RTRIM(SUBSTRING([Argument], 1, CHARINDEX('=', [Argument], 1) - 1))) Parameter,
LTRIM(RTRIM(SUBSTRING([Argument], CHARINDEX('=', [Argument], 1) + 1, LEN([Argument]) - CHARINDEX('=', [Argument], 1)))) Value
FROM (
SELECT
LTRIM(RTRIM(SUBSTRING(@Params, [Number], CHARINDEX(@Delim, @Params + @Delim, [Number]) - [Number]))) [Argument]
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY name) [Number]
FROM sys.all_objects) AS x
WHERE Number <= LEN(@Params) AND SUBSTRING(@Delim + @Params, [Number], LEN(@Delim)) = @Delim) AS y);
GO
我正在 运行 使用来自 ReportServer.dbo.ExecutionLogStorage
的参数字符串在游标中进行此操作。参数看起来像这样:"Some%20Param%20Name=Hello&Some%20Other%20Param=NoLuck"
当我 运行 游标中的函数是这样的:
SELECT * FROM Reports.dbo.funParseRestParams(@Param, '&')
一切都很好,但是当我添加一个 where 子句时:
SELECT * FROM Reports.dbo.funParseRestParams(@Param, '&') R
WHERE R.[Parameter] = 'AccessType'
我每次都收到以下错误消息:
Msg 537, Level 16, State 3, Line 13
Invalid length parameter passed to the LEFT or SUBSTRING function.
那么为什么我的 where 子句会终止函数?
编辑:添加一些额外的东西。您可以将下面的代码粘贴到 SQL 服务器以复制此错误。该错误仅在使用 "first" 列(where 子句中的参数列)时发生。在 where 子句中使用 "second" 值列不会导致错误。您可以删除下面的评论以查看实际效果:
DECLARE @Params NVARCHAR(MAX)
DECLARE @Delim VARCHAR(1)
SET @Params = 'Greeting=Hello&Name=George&Dessert=Jello'
SET @Delim = '&'
SELECT * FROM (
SELECT
LTRIM(RTRIM(SUBSTRING([Argument], 1, CHARINDEX('=', [Argument], 1) - 1))) Parameter,
LTRIM(RTRIM(SUBSTRING([Argument], CHARINDEX('=', [Argument], 1) + 1, LEN([Argument]) - CHARINDEX('=', [Argument], 1)))) Value
FROM (
SELECT
LTRIM(RTRIM(SUBSTRING(@Params, [Number], CHARINDEX(@Delim, @Params + @Delim, [Number]) - [Number]))) [Argument]
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY name) [Number]
FROM sys.all_objects) AS x
WHERE [Number] <= LEN(@Params) AND SUBSTRING(@Delim + @Params, [Number], LEN(@Delim)) = @Delim) AS y
) R
--WHERE R.Parameter = 'AccessType'
--WHERE R.Parameter = 'Greeting'
--WHERE R.Value = 'Bananas'
--WHERE R.Value = 'Jello'
您不妨考虑以下内容:
CREATE FUNCTION dbo.SplitStrings_Moden
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
WITH E1(N) AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
E2(N) AS (SELECT 1 FROM E1 a, E1 b),
E4(N) AS (SELECT 1 FROM E2 a, E2 b),
E42(N) AS (SELECT 1 FROM E4 a, E2 b),
cteTally(N) AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1)))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0))
SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000))
FROM cteStart s;
此代码归功于 Jeff Moden here。该站点还有其他方法。可能值得采用经过充分审查的解决方案(您也必须自己审查),而不是试图重新发明轮子并且不得不花费过多的时间来调试它。
我访问了 MSDN 以搜索答案,我得到了一个。我仍在查看细节,但出于某种原因,以下作品在原始作品中没有。第一个子查询的第二行被改变:
DECLARE @Params NVARCHAR(MAX)
DECLARE @Delim VARCHAR(1)
SET @Params = 'Greeting=Hello&Name=George&Dessert=Jello'
SET @Delim = '&'
SELECT * FROM (
SELECT
LTRIM(RTRIM(SUBSTRING([Argument], 0, CHARINDEX('=', [Argument], 1) ))) Parameter,
LTRIM(RTRIM(SUBSTRING([Argument], CHARINDEX('=', [Argument], 1) + 1, LEN([Argument]) - CHARINDEX('=', [Argument], 1)))) Value
FROM (
SELECT
LTRIM(RTRIM(SUBSTRING(@Params, [Number], CHARINDEX(@Delim, @Params + @Delim, [Number]) - [Number]))) [Argument]
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY name) [Number]
FROM sys.all_objects) AS x
WHERE [Number] <= LEN(@Params) AND SUBSTRING(@Delim + @Params, [Number], LEN(@Delim)) = @Delim) AS y
) R
--WHERE R.Parameter = 'AccessType'
WHERE R.Parameter = 'Greeting'
--WHERE R.Value = 'Bananas'
--WHERE R.Value = 'Jello'