How to return multiple results in Postgres but I need to use a variable

问题描述 投票:0回答:3

我有 Microsoft SQL 背景。所以我想做的是我知道我可以在 MSSql 中做的事情,但我非常想找出 Postgres 中的等价物(截至本文发布时的最新 docker 版本)。

这是我的 MSSql.

DECLARE @id INTEGER

SELECT @id = Id FROM SomeTable where UniqueName = 'foo' // UniqueName is unique (bet you didn't guess that)

SELECT * FROM SomeTable WHERE Id = @id

SELECT * FROM AnotherTable WHERE Id = @id

SELECT * FROM FinalTable WHERE Id = @id

这可能吗?

最初,我尝试使用 CTE(等效):

WITH vars AS(
    SELECT Id FROM SomeTable where UniqueName = 'foo' 
)

SELECT * FROM SomeTable WHERE Id = vars.Id;

SELECT * FROM AnotherTable WHERE Id = vars.Id;

SELECT * FROM FinalTable WHERE Id = vars.Id;

但是我在第二个查询中得到一个错误:

SELECT * FROM AnotherTable
说它不知道
vars
了。

那么,在 Postgres 中可以做到这一点吗?


编辑:所以我认为这可能可以通过 PL/pgSQL(PostgreSQL 的扩展)实现。我试过这个:

DO $$
DECLARE
    @id integer
BEGIN

    SELECT Id INTO id FROM SomeTable WHERE UniqueName = 'foo'

    SELECT * FROM SomeTable WHERE Id = id ;

    SELECT * FROM AnotherTable WHERE Id = id ;

    SELECT * FROM FinalTable WHERE Id = id ;

END $$;

但这无法返回任何数据(是的,我可以确认此查询有一些数据):

ERROR:  query has no destination for result data
HINT:  If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT:  PL/pgSQL function inline_code_block line 8 at SQL statement 

SQL state: 42601

所以我真的迷路了,现在。

postgresql
3个回答
1
投票

不幸的是,似乎无法使用 WITH 语句,您可以通过类似的方式修复它:

SELECT set_config('my.vars.id', Id::char, False) FROM SomeTable WHERE UniqueName = 'foo';

SELECT * FROM SomeTable WHERE Id = current_setting('my.vars.id')::int;

SELECT * FROM AnotherTable WHERE Id = current_setting('my.vars.id')::int;

SELECT * FROM FinalTable WHERE Id = current_setting('my.vars.id')::int;

0
投票

WITH…AS
构造将查询结果放入一种临时表中,其结果可用于对另一个表的查询。不过,这都是一个语句,所以你不能像那样使用结果三次。

WITH vars AS(
    SELECT Id FROM SomeTable where UniqueName = 'foo' 
)
SELECT * FROM SomeTable WHERE Id in (select id from vars);

https://www.postgresql.org/docs/current/queries-with.html


0
投票

这种功能是可以的:

CREATE OR REPLACE FUNCTION fun_test(inputName text) RETURNS setof refcursor AS
$$
DECLARE foundid INTEGER;
DECLARE result1 refcursor;
DECLARE result2 refcursor;
DECLARE result3 refcursor;
BEGIN
    SELECT id INTO foundid FROM SomeTable WHERE UniqueName = inputName;
    result1 = 'First resultset';
    result2 = 'Second resultset';
    result3 = 'Third resultset';
    OPEN result1 FOR SELECT * FROM Table1 WHERE id = foundid;
    RETURN NEXT result1;
    OPEN result2 FOR SELECT * FROM Table2 WHERE id = foundid;
    RETURN NEXT result2;
    OPEN result3 FOR SELECT * FROM Table3 WHERE id = foundid;
    RETURN NEXT result3;
END;
$$ LANGUAGE plpgsql;

检索结果是这样完成的:

  • 在像 pgAdmin 这样的 SQL 客户端上,在事务中一次执行 1

    FETCH
    (如果您一次执行整个事情,pgAdmin 将只显示最后一个结果集):

    BEGIN;
    SELECT fun_test('foo');
    FETCH ALL IN "First resultset";
    FETCH ALL IN "Second resultset";
    FETCH ALL IN "Third resultset";
    COMMIT;
    
  • 如果您从事软件开发,您可以一次发送所有查询并获得返回的多个结果集,其方法类似于我使用 C++/Qt 编写的以下示例:

    if (database.open()) {
        QSqlQuery query(database);
        query.exec(
            "SELECT fun_test('foo');" \
            "FETCH ALL IN \"First resultset\";" \
            "FETCH ALL IN \"Second resultset\";" \
            "FETCH ALL IN \"Third resultset\";"
        );
        for (auto rsi = 0; rsi < 3; ++rsi) {
            //By calling nextResult() first, we ignore the first resultset
            //that contains the identifiers of the next resultsets.
            //We may sometimes want to read it though,
            //in which case the for loop must be altered.
            query.nextResult(); 
            if (query.first()) {
                do {
                    //Do something such as:
                    qDebug() << query.record();
                } while (query.next());
            }
        }
    }
    

    如您所见,您甚至不需要事务,因为所有内容都作为单个查询执行。
    在实际情况下,您可能需要 3 个独立的

    do { ... } while(...);
    循环,每个循环负责自己的记录集。
    示例:

    query.exec(
        "SELECT fun_test('foo');" \
        "FETCH ALL IN \"First resultset\";" \
        "FETCH ALL IN \"Second resultset\";" \
        "FETCH ALL IN \"Third resultset\";"
    );
    query.nextResult();
    if (query.first()) {
        do {
            //Do something with records from First resultset
        } while (query.next());
    }
    query.nextResult();
    if (query.first()) {
        do {
            //Do something with records from Second resultset
        } while (query.next());
    }
    query.nextResult();
    if (query.first()) {
        do {
            //Do something  with records from Third resultset
        } while (query.next());
    }
    query.finish();
    
© www.soinside.com 2019 - 2024. All rights reserved.