【问题标题】:Sending same parameter twice in exec在 exec 中两次发送相同的参数
【发布时间】:2018-09-20 22:31:50
【问题描述】:

我有一个像这样的简单存储过程:

[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 上做这样的事情吗?解决这个问题的唯一方法是向存储过程添加另一个参数?

更新

正如下面提到的cmets,我试过这个:

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 引入子查询时,选择列表中只能指定一个表达式。

【问题讨论】:

  • 你的 sql-server 版本是多少?
  • SQL 管理 2017 @D-Shih
  • 为什么要发送两次@Extended?你的 SP 有什么逻辑吗?
  • 只是因为我想要在扩展列@D-Shih 上有 title1 和 title2 的值

标签: sql sql-server tsql parameters


【解决方案1】:

您可以让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

【讨论】:

  • 但这在 exec 子句中是不可能的
  • 为什么在exec 上不可能?这是一个可以工作的示例dbfiddle.uk/…
  • 哦,但是 string_split 只能用于 from 子句?我想在我的商店中使用:WHERE [Extended] = STRING_SPLIT (@Extended, ',') 但我得到“string_split 无法识别内置函数名”
  • @Pepe 这是另一个示例dbfiddle.uk/…,您可以使用@parameter1@parameter2 作为您的参数。
  • 我试试你说的但我得到Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.,我用当前代码更新了我的问题
【解决方案2】:

这个方法:

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

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

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

因此,您将在 @Extended 中以逗号分隔值传递值,并且从存储过程中您将使用 IN()NOT IN() 而不是 =&lt;&gt; 这将扩展它以具有要比较的值更多,而不是一个值。

然后您可以使用 XML 来拆分值并将它们转换为行。

所以我们将使用这个:

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)

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

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)
)

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

[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

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

@Extended = 'title1, title2, title3'
@Exclude  = 'title5, title8'

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-09
    • 2016-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-02
    • 2021-01-09
    • 2019-10-14
    相关资源
    最近更新 更多