如何将值的“数组”传递给我的存储过程?

Posted

技术标签:

【中文标题】如何将值的“数组”传递给我的存储过程?【英文标题】:How can I pass an "array" of values to my stored procedure? 【发布时间】:2010-09-29 03:06:47 【问题描述】:

我希望能够将值的“数组”传递给我的存储过程,而不是连续调用“添加值”过程。

任何人都可以建议一种方法吗?我在这里遗漏了什么吗?

编辑:我将使用 PostgreSQL / mysql,我还没有决定。

【问题讨论】:

【参考方案1】:

正如 Chris 所指出的,在 PostgreSQL 中这没有问题 - 任何基本类型(如 int、text)都有自己的数组子类型,您还可以创建自定义类型,包括复合类型。例如:

CREATE TYPE test as (
    n int4,
    m int4
);

现在您可以轻松创建测试数组:

select ARRAY[
    row(1,2)::test,
    row(3,4)::test,
    row(5,6)::test
];

您可以编写一个函数,将数组中的每个项目乘以 n*m,并返回乘积的总和:

CREATE OR REPLACE FUNCTION test_test(IN work_array test[]) RETURNS INT4 as $$
DECLARE
    i      INT4;
    result INT4 := 0;
BEGIN
    FOR i IN SELECT generate_subscripts( work_array, 1 ) LOOP
        result := result + work_array[i].n * work_array[i].m;
    END LOOP;
    RETURN result;
END;
$$ language plpgsql;

并运行它:

# SELECT test_test(
    ARRAY[
        row(1, 2)::test,
        row(3,4)::test,
        row(5,6)::test
    ]
);
 test_test
-----------
        44
(1 row)

【讨论】:

【参考方案2】:

如果您打算使用 MySQL 5.1,则无法传入数组。 查看 MySQL 5.1 faq 如果你打算使用 PostgreSQL,可以看here

【讨论】:

【参考方案3】:

我不知道如何将一个实际的数组传递给那些引擎(我使用 sqlserver),但这里有个想法是传递一个分隔字符串并使用这个函数在你的 sproc 中解析它。

CREATE FUNCTION [dbo].[Split]
(
    @ItemList NVARCHAR(4000), 
    @delimiter CHAR(1)
)
RETURNS @IDTable TABLE (Item VARCHAR(50))  
AS      

BEGIN    
    DECLARE @tempItemList NVARCHAR(4000)
    SET @tempItemList = @ItemList

    DECLARE @i INT    
    DECLARE @Item NVARCHAR(4000)

    SET @tempItemList = REPLACE (@tempItemList, ' ', '')
    SET @i = CHARINDEX(@delimiter, @tempItemList)

    WHILE (LEN(@tempItemList) > 0)
    BEGIN
        IF @i = 0
            SET @Item = @tempItemList
        ELSE
            SET @Item = LEFT(@tempItemList, @i - 1)
        INSERT INTO @IDTable(Item) VALUES(@Item)
        IF @i = 0
            SET @tempItemList = ''
        ELSE
            SET @tempItemList = RIGHT(@tempItemList, LEN(@tempItemList) - @i)
        SET @i = CHARINDEX(@delimiter, @tempItemList)
    END 
    RETURN
END  

【讨论】:

这个问题是在 PostgreSQL 或 MySql 环境中专门提出的,而不是 MSSQL【参考方案4】:

您没有说明,但如果您指的是 SQL Server,here's one way。

MS 支持ref。

【讨论】:

从 SQL Server 2008 开始,实际上可以使用表变量作为存储过程参数。【参考方案5】:

对于 PostgreSQL,你可以这样做:

CREATE OR REPLACE FUNCTION fnExplode(in_array anyarray) RETURNS SETOF ANYELEMENT AS
$$
    SELECT ($1)[s] FROM generate_series(1,array_upper($1, 1)) AS s;
$$
LANGUAGE SQL IMMUTABLE;

然后,您可以将分隔字符串传递给您的存储过程。

说,param1 是一个包含'1|2|3|4|5'的输入参数

声明:

SELECT CAST(fnExplode(string_to_array(param1, '|')) AS INTEGER);

产生可以连接或插入的结果集。

同样,对于 MySQL,您可以这样做:

DELIMITER $$
CREATE PROCEDURE `spTest_Array`
(
    v_id_arr TEXT
)
BEGIN
    DECLARE v_cur_position INT; 
    DECLARE v_remainder TEXT; 
    DECLARE v_cur_string VARCHAR(255); 
    CREATE TEMPORARY TABLE tmp_test
    ( 
        id INT
    ) ENGINE=MEMORY; 

    SET v_remainder = v_id_arr; 
    SET v_cur_position = 1;

    WHILE CHAR_LENGTH(v_remainder) > 0 AND v_cur_position > 0 DO 
        SET v_cur_position = INSTR(v_remainder, '|'); 
        IF v_cur_position = 0 THEN 
            SET v_cur_string = v_remainder; 
        ELSE 
            SET v_cur_string = LEFT(v_remainder, v_cur_position - 1); 
        END IF; 

        IF TRIM(v_cur_string) != '' THEN 
            INSERT INTO tmp_test
                (id)
            VALUES 
                (v_cur_string);                 
        END IF; 

        SET v_remainder = SUBSTRING(v_remainder, v_cur_position + 1); 
    END WHILE; 

    SELECT 
        id
    FROM 
    tmp_test;

    DROP TEMPORARY TABLE tmp_test;
END 
$$

然后只需 CALL spTest_Array('1|2|3|4|5') 应该会产生与上述 PostgreSQL 查询相同的结果集。

【讨论】:

【参考方案6】:

感谢 MySQL 中的 JSON 支持,您现在实际上可以将数组传递给 MySQL 存储过程。创建一个 JSON_ARRAY 并将其作为 JSON 参数传递给您的存储过程。 然后在过程中,使用 MySQL 的 WHILE 循环和 MySQL 的 JSON "pathing" ,访问 JSON_ARRAY 中的每个元素并按照您的意愿进行操作。 这里有一个例子https://gist.githubusercontent.com/jonathanvx/513066eea8cb5919b648b2453db47890/raw/22f33fdf64a2f292688edbc67392ba2ccf8da47c/json.sql

【讨论】:

【参考方案7】:

顺便说一下,下面是如何将数组添加到函数(存储过程)调用:

CallableStatement proc = null;
List<Integer> faultcd_array = Arrays.asList(1003, 1234, 5678);
//conn - your connection manager
conn = DriverManager.getConnection(connection string here);
proc = conn.prepareCall(" ? = call procedureName(?) ");
proc.registerOutParameter(1, Types.OTHER);
//This sets-up the array
Integer[] dataFaults = faultcd_array.toArray(new Integer[faultcd_array.size()]);
java.sql.Array sqlFaultsArray = conn.createArrayOf("int4", dataFaults);
proc.setArray(2, sqlFaultsArray);
//:
//add code to retrieve cursor, use the data.
//:

【讨论】:

以上是关于如何将值的“数组”传递给我的存储过程?的主要内容,如果未能解决你的问题,请参考以下文章

调用存储过程、传递 NULL 值、处理布尔值

如何使用 SQL 查询将值传递给具有空间/地理数据类型的存储过程

将值传递到 T-SQL 中的存储过程

在 Java 中创建一个 bytea 数组以传递给 Postgresql 存储过程

使用 JPA 2.1 / Hibernate 4 将值列表传递给存储过程

将存储过程结果传递给 Laravel API 资源