将 SELECT 语句结果传递给 StoredProc 以进行临时表连接

Posted

技术标签:

【中文标题】将 SELECT 语句结果传递给 StoredProc 以进行临时表连接【英文标题】:Passing a SELECT-Statement result to a StoredProc for Temp-Table Join 【发布时间】:2020-06-26 14:52:12 【问题描述】:

我正在尝试从 DB-Server-1 中的一个表中获取数据,并将其传递给正在 DB-SERVER-2 上执行的 StoredProcedure(连接到来自 DB-Server-1 的数据)。

所以, 我在不同的服务器上有 2 个表:

    DB-Server-1 : tblItem

    -------------------
    item_id | item_qty 
    -------------------
     1231   | 2
     1232   | 4
    -------------------
    

    DB-Server-2 : tblItemDetails

    ----------------------------------------
    item_detail_id | item_id | item_data
    ----------------------------------------
     1             | 1231    |  TEST_DATA_1
     2             | 1232    |  TEST_DATA_2
    ----------------------------------------
    

现在我想从 DB-Server-1 获取数据(基本选择查询)

SELECT item_id, item_qty
FROM tblItem
WHERE item_id IN (1231, 1232);

并将其传递给存储过程:spSetItemQuantityInItemDetails

CREATE PROCEDURE [dbo].[spUpdatePOCartons]
(
 @valueList VARCHAR(MAX)
)
.
.
-- Now trying to split string and create a temp table
-- This temp table will later be used in the SP to join with tblItemDetails to set item_qty

DECLARE @temp TABLE (
item_id int,
item_qty int
);

DECLARE @pos1 INT
DECLARE @len1 INT
DECLARE @value1 varchar(8000)

DECLARE @pos2 INT
DECLARE @len2 INT
DECLARE @value2 varchar(8000)

SET @valueList = '1,4;2,5;3,14;';

set @pos1 = 0
set @len1 = 0

WHILE CHARINDEX(';', @valueList, @pos1+1)>0
    BEGIN
        set @len1 = CHARINDEX(';', @valueList, @pos1+1) - @pos1
        set @value1 = SUBSTRING(@valueList, @pos1, @len1)
        --SELECT @pos, @len, @value /*this is here for debugging*/

        PRINT @value1;
        -----------

            set @pos2 = 0
            set @len2 = 0

            WHILE CHARINDEX(',', @value1, @pos2+1)>0
                BEGIN
                    set @len2 = CHARINDEX(',', @value1, @pos2+1) - @pos2
                    set @value2 = SUBSTRING(@value1, @pos2, @len2)
                    --SELECT @pos, @len, @value /*this is here for debugging*/

                    PRINT @value2;
                    set @pos2 = CHARINDEX(',', @value1, @pos2+@len2) +1
                END

        ------------
        set @pos1 = CHARINDEX(';', @valueList, @pos1+@len1) +1
    END

问题

我试图了解上述解决方案是否最接近可行的解决方案(目前它不会拆分不以 ; 或 , 结尾的字符串的最后一个值) 或者有没有更好的方法

【问题讨论】:

您不能将结果集“传递”到存储过程。如果需要传递数据集,则需要使用表类型参数。 您是否可以控制 SQL Server 对象(您可以更改存储过程),还是只是从您的客户端应用程序中使用它们? 我可以更改存储过程 @GordonLinoff 感谢您的意见。更新一样 仅供参考,有 far 比使用WHILE 在 SQL 中拆分字符串更好的方法。 精心设计的 iTVF(即delimitedsplit8k_LEAD)、XML 拆分器、内置的STRING_SPLIT(如果您使用受支持的 SQL Server 版本)或 CLR 函数都会好得多方法。 【参考方案1】:

我认为更好的方法可能是将表变量直接传递给存储过程。为此,您必须创建一个为输入表创建结构的类型。我在下面重新创建了这个场景。让我知道您是否可以使用它来实现您的目标。

--Create test tables
CREATE TABLE dbo.tblItem (item_id int, item_qty int);
CREATE TABLE dbo.tblItem2 (item_detail_id int, item_id int, item_details varchar(50));
GO

--Create the type that can be used as input
CREATE TYPE TableForInput as TABLE
(
    Item_Id int,
    Item_Qty int
);

GO 

--Create/alter the stored procedure
CREATE PROCEDURE dbo.usp_GetCardData
@Input TableForInput READONLY
AS
BEGIN 
    SELECT * FROM dbo.tblItem2 as t2 INNER JOIN @Input as i ON t2.Item_id = i.Item_id
END

GO

--Insert dummy data into the test tables
INSERT INTO dbo.tblItem values (1231, 2), (1232, 4);
INSERT INTO dbo.tblItem2 VALUES (1, 1231, 'TEST_1'), (2, 1232, 'TEST2')

-- The below would mimic the client side.
-- Declare a local temporary table, select data into it
--      And then pass this as a parameter to the stored proc
DECLARE @Data TableForInput;

INSERT INTO @Data
SELECT * FROM dbo.tblItem;


exec dbo.usp_GetCardData @Data

【讨论】:

非常感谢您的努力。这提供了一个很好的见解。但是,在我的情况下,我首先从 php-DAO 查询 DB-Server-1,然后获取 tblItem 的数据,然后基本上查询到 Server-2 上的另一个外部 StoredProcedure 以更新 DB-Server-2 上的表(使用不同的数据库处理程序)。因此,这些将是 2 个不同的执行查询 因此我正在尝试更新 SProc 以将第一个表数据作为参数,然后从 SProc 内的该数据创建一个临时表,然后与临时表正常联接【参考方案2】:

非常感谢大家。您的见解确实有助于找到解决方案。 我能够通过以下方式获得预期的行为:

IF OBJECT_ID('tempdb..#tval') IS NOT NULL DROP TABLE #tval;
CREATE TABLE #tval (val1 INT, val2 INT);

declare @s varchar(1000)
set @s = '1,11;2,22'

;WITH cte AS (
  select value
  from string_split(@s, ';')
)

INSERT INTO #tval
    SELECT
       MAX(CASE WHEN ord=1 THEN v END),
       MAX(CASE WHEN ord=2 THEN v END)
    FROM cte
    CROSS APPLY (SELECT value AS v, ROW_NUMBER() OVER(ORDER BY 1/0) AS ord
    FROM  STRING_SPLIT([value], ',')) s
    GROUP BY value;

SELECT * from #tval

【讨论】:

以上是关于将 SELECT 语句结果传递给 StoredProc 以进行临时表连接的主要内容,如果未能解决你的问题,请参考以下文章

将字符串传递给 PHP 文件以查询 SELECT 语句

PL/SQL:, 如何将变量传递给 SELECT 语句并返回所有结果行

如何将 DataTable.Select() 结果传递给新的 DataTable?

将表传递给 postgreSQL 函数,执行 select 语句,返回表

如何将select的结果分配到sqlplus变量中

如何将 select 语句的 IN 子句中的参数作为具有多个值的参数传递?