我有 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
所以我真的迷路了,现在。
不幸的是,似乎无法使用 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;
WITH…AS
构造将查询结果放入一种临时表中,其结果可用于对另一个表的查询。不过,这都是一个语句,所以你不能像那样使用结果三次。
WITH vars AS(
SELECT Id FROM SomeTable where UniqueName = 'foo'
)
SELECT * FROM SomeTable WHERE Id in (select id from vars);
这种功能是可以的:
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();