Как объявить переменную для использования в запросе PostgreSQL 8.3?
В MS SQL Server я могу это сделать:
DECLARE @myvar INT
SET @myvar = 5
SELECT *
FROM somewhere
WHERE something = @myvar
Как мне сделать то же самое в PostgreSQL? В соответствии с документацией переменные объявляются просто как "name type;", но это дает мне синтаксическую ошибку:
myvar INTEGER;
Может ли кто-нибудь дать мне пример правильного синтаксиса?
В PostgreSQL такой функции нет. Вы можете сделать это только в pl/PgSQL (или другом pl/*), но не в простом SQL.
Исключением является запрос WITH()
который может работать как переменная или даже как tuple
переменных. Это позволяет вам возвращать таблицу временных значений.
WITH master_user AS (
SELECT
login,
registration_date
FROM users
WHERE ...
)
SELECT *
FROM users
WHERE master_login = (SELECT login
FROM master_user)
AND (SELECT registration_date
FROM master_user) > ...;
Я достиг той же цели, используя предложение WITH
, оно далеко не так элегантно, но может сделать то же самое. Хотя для этого примера это действительно перебор. Я также не особо рекомендую это.
WITH myconstants (var1, var2) as (
values (5, 'foo')
)
SELECT *
FROM somewhere, myconstants
WHERE something = var1
OR something_else = var2;
\set
как предложено в ответе Шахриара Агаджани.
Вы также можете попробовать это в PLPGSQL:
DO $$
DECLARE myvar integer;
BEGIN
SELECT 5 INTO myvar;
DROP TABLE IF EXISTS tmp_table;
CREATE TABLE tmp_table AS
SELECT * FROM yourtable WHERE id = myvar;
END $$;
SELECT * FROM tmp_table;
Для этого требуется Postgres 9.0 или новее.
Это зависит от вашего клиента.
Однако, если вы используете клиент psql, вы можете использовать следующее:
my_db=> \set myvar 5
my_db=> SELECT :myvar + 1 AS my_var_plus_1;
my_var_plus_1
---------------
6
\set
должен быть в нижнем регистре
вы можете "злоупотреблять" динамическими настройками конфигурации для этого:
-- choose some prefix that is unlikey to be used by postgres
set session my.vars.id = '1';
select *
from person
where id = current_setting('my.vars.id')::int;
Конфигурационные параметры всегда являются значениями varchar, поэтому при их использовании вам нужно придать их правильному типу данных. Это работает с любым SQL-клиентом, тогда как \set
работает только в psql
Вышеизложенное требует Postgres 9.2 или новее.
Для предыдущих версий переменная должна была быть объявлена в postgresql.conf
до ее использования, поэтому она несколько ограничила ее юзабилити. На самом деле не переменная полностью, а конфиг "класс", который по сути является префиксом. Но как только префикс был определен, любая переменная могла бы использоваться без изменения postgresql.conf
Вне использования pl/pgsql или другого языка pl/*, как это было предложено, это единственная возможность, о которой я мог подумать.
begin;
select 5::int as var into temp table myvar;
select *
from somewhere s, myvar v
where s.something = v.var;
commit;
Я хочу предложить улучшение @DarioBarrionuevo answer, чтобы упростить использование временных таблиц.
DO $$
DECLARE myvar integer = 5;
BEGIN
CREATE TEMP TABLE tmp_table ON COMMIT DROP AS
-- put here your query with variables:
SELECT *
FROM yourtable
WHERE id = myvar;
END $$;
SELECT * FROM tmp_table;
Вот пример использования операторов PREPARE. Вы все еще не можете использовать ?
, но вы можете использовать обозначение $n
:
PREPARE foo(integer) AS
SELECT *
FROM somewhere
WHERE something = $1;
EXECUTE foo(5);
DEALLOCATE foo;
Это решение основано на предложении fei0x, но имеет те преимущества, что нет необходимости присоединять список значений констант в запросе, и константы могут быть легко перечислены в начале запроса. Это также работает в рекурсивных запросах.
По сути, каждая константа - это таблица с одним значением, объявленная в предложении WITH, которая затем может быть вызвана в любой части оставшейся части запроса.
WITH
constant_1_str AS (VALUES ('Hello World')),
constant_2_int AS (VALUES (100))
SELECT *
FROM some_table
WHERE table_column = (table constant_1_str)
LIMIT (table constant_2_int)
В качестве альтернативы вы можете использовать SELECT * FROM constant_name
вместо TABLE constant_name
что может быть недопустимо для других языков запросов, отличных от postgresql.