在exec中发送两次相同的参数

时间:2018-09-20 22:31:50

标签: sql sql-server tsql parameters

我有一个简单的存储过程,如下所示:

[dbo].[getStatusList]
    @Extended NVARCHAR(255) = 'Project Status',
    @Exclude NVARCHAR(255) = '',
    @All BIT = 0
AS
    SET NOCOUNT ON

    IF (@All = 0)
    BEGIN
        SELECT
            [GeneralKey],
            [Label]
        FROM 
            [General]
        WHERE 
            [Extended] = @Extended
            AND [Label] <> @Exclude
        ORDER BY
            [OrderID];
    END
    ELSE
    BEGIN
        IF (@All = 1)
        BEGIN
            SELECT
                0 AS [GeneralKey],
                'Any' AS [Label],
                0 AS [OrderID]
            UNION ALL
            SELECT
                [GeneralKey],
                [Label],
                [OrderID]
            FROM 
                [General]
            WHERE 
                [Extended] = @Extended
                AND [Label] <> @Exclude
            ORDER BY
                [OrderID];
        END
    END

我想做的是执行此存储过程,发送两次@Extended参数,例如:

exec getStatusList @Extended = 'title1' AND @Extended = 'title2'

不可能在exec上做类似的事情吗?解决此问题的唯一方法是在存储过程中添加另一个参数?

更新

正如下面提到的评论,我尝试过:

CREATE OR ALTER PROCEDURE usp_Get_StatusListByDesignType
    -- Add the parameters for the stored procedure here
    @Extended NVARCHAR(MAX),
    @Exclude NVARCHAR(255) = '',
    @All BIT = 0
AS
    SET NOCOUNT ON

    IF (@All = 0)
    BEGIN
        DECLARE  @Parameter1 VARCHAR(50) 
        DECLARE  @Parameter2 VARCHAR(50) 

        ;WITH CTE AS 
        (
             SELECT 
                 *,
                 ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) rn
             FROM 
                 STRING_SPLIT (@Extended,',')
        ) 
        SELECT  
            @Parameter1 = MAX(CASE WHEN rn = 1 THEN VALUE END),
            @Parameter2 = MAX(CASE WHEN rn = 2 THEN VALUE END)
        FROM 
            CTE

        SELECT
            [GeneralKey], [Label]
        FROM 
            [General]
        WHERE 
            [Extended] IN (SELECT @Parameter1, @Parameter2)
            AND [Label] <> @Exclude
        ORDER BY
            [OrderID];
    END
    ELSE
    BEGIN
        IF (@All = 1)
        BEGIN
            SELECT
                0 AS [GeneralKey],
                'Any' AS [Label],
                0 AS [OrderID]
            UNION ALL
            SELECT
                [GeneralKey],
                [Label],
                [OrderID]
            FROM 
                [General]
            WHERE 
                [Extended]  IN (SELECT @Parameter1, @Parameter2)
                AND [Label] <> @Exclude
            ORDER BY
                [OrderID];
        END
        RETURN;

但是我得到这个错误:

  

当未使用EXISTS引入子查询时,只能在选择列表中指定一个表达式。

2 个答案:

答案 0 :(得分:2)

您可以传递与para1Val1,para1Val2...逗号连接的,之类的参数。

然后使用STRING_SPLIT函数将其与,逗号分开,然后获取参数。

DECLARE @Extended varchar(max)='title1,titl2'

这很简单

DECLARE @Extended varchar(max)='title1,titl2'

select *,row_number() over(order by (select NULL)) rn
from STRING_SPLIT (@Extended,',')

然后您可以在SP中设置参数。

声明参数变量,然后使用row_number设置参数行号。

下一步使用条件聚合函数select子句中设置参数。

 declare  @parameter1 varchar(50) 
 declare  @parameter2 varchar(50) 
 ;with cte as (
   select *,row_number() over(order by (select NULL)) rn
   from STRING_SPLIT (@Extended,',')
 ) 
 select @parameter1 = MAX(case when rn = 1 then value end),
        @parameter2 = MAX(case when rn = 2 then value end)
 from cte

sqlfiddle

答案 1 :(得分:0)

此方法:

exec getStatusList @Extended='title1' AND @Extended = 'title2'

它根本不起作用,因为参数或变量通常只能容纳一个值,仅此而已。因此,除非执行两次存储过程并在每个存储过程上指定参数,否则您将无法执行此操作。或者,您可以使用循环来做到这一点。但是我不喜欢循环,我总是建议尽可能避免循环。

我认为适合您情况的方法是对存储过程本身进行了一些修改的TVP。

因此,您将在@Extended中以逗号分隔的值传递值,并从存储过程中使用IN()NOT IN()而不是=和{ {1}}会将其扩展为具有更多要比较的值,而不是一个值。

然后,您可以使用XML拆分值并将它们变成行。

所以我们将使用它:

<>

您可以通过修改我上面提到的运算符将其直接注入到存储过程中,并且可以正常工作。但为了代码重用,我们将其用作TVP。

SELECT LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)')))
FROM (
    SELECT CAST('<XMLRoot><RowData>' + REPLACE(@Extended,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) Extended
) D
CROSS APPLY Extended.nodes('/XMLRoot/RowData')m(n)

现在,您可以将存储过程修改为以下内容:

CREATE FUNCTION SplitToRows 
(   
    @Extended   VARCHAR(MAX)
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) Extended
    FROM (
        SELECT CAST('<XMLRoot><RowData>' + REPLACE(@Extended,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) Extended
    ) D
    CROSS APPLY Extended.nodes('/XMLRoot/RowData')m(n)
)

现在,您可以像这样同时在@Extended和@Exclude中传递多个单独的值:

[dbo].[getStatusList]
                     @Extended NVARCHAR(255) = 'Project Status'
                    , @Exclude  NVARCHAR(255) = ''
                    , @All      BIT           = 0
AS
        SET NOCOUNT ON
        IF(@All = 0)
        BEGIN
            SELECT
                 [GeneralKey]
                , [Label]
                 FROM [General]
                 WHERE 
                     [Extended] IN( SELECT * FROM dbo.SplitToRows(@Extended) )
                 AND [Label] NOT IN( SELECT * FROM dbo.SplitToRows(@Exclude) ) 
                 ORDER BY
                        [OrderID];
        END
            ELSE
        BEGIN
            IF(@All = 1)
            BEGIN
               SELECT
                    0 AS [GeneralKey]
                   , 'Any' AS [Label]
                   , 0 AS [OrderID]
               UNION ALL
               SELECT
                    [GeneralKey]
                   , [Label]
                   , [OrderID]
                    FROM [General]
                    WHERE
                         [Extended] IN( SELECT * FROM dbo.SplitToRows(@Extended) )
                     AND [Label] NOT IN( SELECT * FROM dbo.SplitToRows(@Exclude) ) 
                    ORDER BY
                            [OrderID];
            END
        END

所以两个参数将使用相同的方法。