使用选择列作为输入参数运行存储过程?

时间:2019-07-30 12:57:02

标签: tsql stored-procedures

我有一个选择查询,该查询返回一列包含“ n”个记录的数据集。我想将此列用作存储过程中的参数。下面是我的案例的简化示例。

查询:

SELECT code FROM rawproducts

数据集:

CODE
1
2
3

存储过程:

ALTER PROCEDURE [dbo].[MyInsertSP]
    (@code INT)
AS
BEGIN
    INSERT INTO PRODUCTS description, price, stock
        SELECT description, price, stock 
        FROM INVENTORY I
        WHERE I.icode = @code
END

我已经完成了实际的查询和存储过程;我只是不确定如何将它们放在一起。

在此感谢您的协助!谢谢!

PS:当然,存储过程并不像上面那样简单。我只是选择使用一个非常愚蠢的示例来缩小内容范围。 :)

2 个答案:

答案 0 :(得分:0)

有两种方法供您使用,一种是使用没有游标的循环:

DECLARE @code_list TABLE (code INT);
INSERT INTO @code_list SELECT code, ROW_NUMBER() OVER (ORDER BY code) AS row_id FROM rawproducts;
DECLARE @count INT;
SELECT @count = COUNT(*) FROM @code_list;
WHILE @count > 0
BEGIN
    DECLARE @code INT;
    SELECT @code = code FROM @code_list WHERE row_id = @count;
    EXEC MyInsertSP @code;
    DELETE FROM @code_list WHERE row_id = @count;
    SELECT @count = COUNT(*) FROM @code_list;
END;

通过将代码放入表变量中并为每行分配一个从1..n开始的数字来工作。然后我们一次遍历它们,一次删除它们,直到处理完为止,直到表变量中没有剩余。

但这是我认为更好的方法:

CREATE TYPE dbo.code_list AS TABLE (code INT);
GO
CREATE PROCEDURE MyInsertSP (
    @code_list dbo.code_list)
AS
BEGIN
    INSERT INTO PRODUCTS (
        [description], 
        price, 
        stock)
    SELECT 
        i.[description], 
        i.price, 
        i.stock 
    FROM 
        INVENTORY i
        INNER JOIN @code_list cl ON cl.code = i.code;
END;
GO
DECLARE @code_list dbo.code_list;
INSERT INTO @code_list SELECT code FROM rawproducts;
EXEC MyInsertSP @code_list = @code_list;

要使其工作,我创建了一个用户定义的表类型,然后使用该表类型将代码列表传递到存储过程中。这意味着稍微重写存储过程,但是完成工作的实际代码要小得多。

答案 1 :(得分:0)

  

(如何)使用选择列作为输入来运行存储过程   参数?

您要寻找的是APPLY APPLY是将列用作输入参数的方式。唯一不清楚的是输入列的填充方式/位置。让我们从示例数据开始:

IF OBJECT_ID('dbo.Products', 'U') IS NOT NULL DROP TABLE dbo.Products;
IF OBJECT_ID('dbo.Inventory','U') IS NOT NULL DROP TABLE dbo.Inventory;
IF OBJECT_ID('dbo.Code','U') IS NOT NULL      DROP TABLE dbo.Code;

CREATE TABLE dbo.Products
(
  [description] VARCHAR(1000) NULL,
  price         DECIMAL(10,2) NOT NULL, 
  stock         INT           NOT NULL
);

CREATE TABLE dbo.Inventory
(
  icode         INT           NOT NULL,
  [description] VARCHAR(1000) NULL,
  price         DECIMAL(10,2) NOT NULL, 
  stock         INT           NOT NULL
);

CREATE TABLE dbo.Code(icode INT NOT NULL);

INSERT dbo.Inventory 
VALUES (10,'',20.10,3),(11,'',40.10,3),(11,'',25.23,3),(11,'',55.23,3),(12,'',50.23,3),
       (15,'',33.10,3),(15,'',19.16,5),(18,'',75.00,3),(21,'',88.00,3),(21,'',100.99,3);

CREATE CLUSTERED INDEX uq_inventory ON dbo.Inventory(icode);

功能:

CREATE FUNCTION dbo.fnInventory(@code INT)
RETURNS TABLE AS RETURN
  SELECT i.[description], i.price, i.stock 
  FROM   dbo.Inventory I
  WHERE  I.icode = @code;

使用情况:

DECLARE @code TABLE (icode INT);
INSERT  @code VALUES (10),(11);

SELECT f.[description], f.price, f.stock 
FROM        @code                    AS c
CROSS APPLY dbo.fnInventory(c.icode) AS f;

结果:

 description    price    stock
 -------------- -------- -----------
                20.10    3
                40.10    3

更新后的程序(请注意我的评论):

ALTER PROC dbo.MyInsertSP -- (1) Lose the input param
AS
  -- (2) Code that populates the "code" table
  INSERT dbo.Code VALUES (10),(11);

  -- (3) Use CROSS APPLY to pass the values from dbo.code to your function
  INSERT dbo.Products ([description], price, stock)
    SELECT f.[description], f.price, f.stock 
    FROM        dbo.code               AS c
    CROSS APPLY dbo.fnInventory(c.icode) AS f;

这^^^是完成的方式。