如何在其他INSERT语句中使用INSERT语句的结果?

时间:2019-04-06 15:16:34

标签: sql postgresql

PostgreSQL 数据库中,我有2个表。

问题

| question_id | question_text | widget | required | position |
|-------------|---------------|--------|----------|----------|
| int         | text          | int    | boolean  | int      |

FACTORS_QUESTIONS_RELATIONSHIP

| factor_id   | question_id   |
|-------------|---------------|
| int         | text          |

您可以在此函数中看到2条插入语句。第一个返回新问题ID的列表。我想在第二个插入语句中使用该ID。如何正确制作?同时,我想从第一条语句返回id作为函数的结果。

CREATE OR REPLACE FUNCTION factorio(
    FACTOR_IDENTIFIER INT,
    TEXT_ARR VARCHAR[],
    WIDGET_ARR INT[],
    REQUIRED_ARR BOOLEAN[],
    POSITION_ARR INT[]
) RETURNS SETOF INT AS $$
    BEGIN
        RETURN QUERY
        WITH RESULT_SET AS (
            INSERT INTO QUESTIONS (TEXT, WIDGET, REQUIRED, POSITION) 
            SELECT 
                UNNEST(ARRAY[TEXT_ARR]) AS TEXT,
                UNNEST(ARRAY[WIDGET_ARR]) AS WIDGET,
                UNNEST(ARRAY[REQUIRED_ARR]) AS REQUIRED,
                UNNEST(ARRAY[POSITION_ARR]) AS POSITION
            RETURNING ID
        )
        --
        INSERT INTO factors_questions_relationship (FACTOR_ID, QUESTION_ID) 
        SELECT FACTOR_IDENTIFIER FACTOR_ID, QUESTION_ID FROM UNNEST(ARRAY[array_agg(SELECT ID FROM RESULT_SET)]) QUESTION_ID
        --
        SELECT ID FROM RESULT_SET;
    END;
$$ LANGUAGE plpgsql;

2 个答案:

答案 0 :(得分:1)

我只会先将ID放在ID的临时表中。然后发出另一个插入。然后返回ID的临时表。

这是一个例子:

DDL

create table z
(
    id int generated by default as identity primary key, 
    question_text text not null
);

create table q_factory
(
    id int generated by default as identity primary key, 
    q_id int not null references z(id),
    some_text text not null
);

功能

create or replace function insert_multiple_test()
returns setof int
as           
$$   
begin
    create temporary table x_t on commit drop
    as
    with resulting_rows as
    (
        insert into z(question_text) values
        ('hello'),
        ('你好'),
        ('hola')
        returning id
    )   
    select id from resulting_rows;

    insert into q_factory(q_id, some_text)
    select id, q.another
    from x_t
    cross join unnest(array[
        'answer to life and everything', 
        'are great and awesome'
    ]) as q(another);

    return query select id from x_t;        
end;
$$ language 'plpgsql'

测试:

select * from insert_multiple_test();

输出:

enter image description here

测试:

select * from q_factory;

输出:

enter image description here

答案 1 :(得分:1)

嗯..好像不需要创建temporary table。即使您的第二条插入语句依赖于第一条语句的返回ID,也可以直接从返回查询中返回if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.M) { // Bug in AnimatorSet for API 23 animation1.start() animation2.start() } else { val animation = AnimatorSet() animation.playTogether(animation1, animation2) animation.start() } 的结果。这是安全的,因为即使在查询中两次引用了result_rows,它也不会运行两次。

无论如何,如果后续的语句/查询是复杂的语句/查询,例如使用循环,您可能仍要使用临时表方法。无法在CTE中嵌入循环。

returning id

测试:

create or replace function insert_multiple_test()
returns setof int
as           
$$   
begin
    return query
    with resulting_rows as
    (
        insert into z(question_text) values
        ('hello'),
        ('你好'),
        ('hola')
        returning id
    ),
    generate_question as 
    (
        insert into q_factory(q_id, some_text)
        select id, q.another
        from resulting_rows
        cross join unnest(array[
           'answer to life and everything', 
           'are multiple and awesome'
        ]) as q(another)                
    )
    select id from resulting_rows;

end;
$$ language 'plpgsql';

即使在查询中两次引用了result_rows,也不会运行两次。仍然是3行:

enter image description here

测试:

select * from insert_multiple_test() as x(the_id);

输出:

enter image description here