当where子句与表值函数一起使用时会发生错误?

时间:2016-02-05 22:41:37

标签: sql sql-server user-defined-functions

我有下表值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中的参数字符串在游标中运行它。参数看起来像这样:“有些%20Param%20Name = Hello&amp; 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 Server中以复制此错误。仅当使用“first”列(where子句中的Parameter列)时才会出现此错误。使用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'

2 个答案:

答案 0 :(得分:0)

您可能希望考虑以下内容:

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。该网站还有其他方法。可能值得采用经过严格审查的解决方案(您也必须自己审核),而不是试图重新发明轮子并且不得不花费过多的时间来调试它。

答案 1 :(得分:0)

我放弃了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'