Is it possible to define global variables in postgresql - postgresql

I am using postgresql 9.4 and while writing functions I want to use self-defined error_codes (int). However I may want to change the exact numeric values later.
For instance
-1 means USER_NOT_FOUND.
-2 means USER_DOES_NOT_HAVE_PERMISSION.
I can define these in a table codes_table(code_name::text, code_value::integer) and use them in functions as follows
(SELECT codes_table.code_value FROM codes_table WHERE codes_table.code_name = 'USER_NOT_FOUND')
Is there another way for this. Maybe global variables?

Postgres does not have global variables.
However you can define custom configuration parameters.
To keep things clear define your own parameters with a given prefix, say glb.
This simple function will make it easier to place the parameter in queries:
create or replace function glb(code text)
returns integer language sql as $$
select current_setting('glb.' || code)::integer;
$$;
set glb.user_not_found to -1;
set glb.user_does_not_have_permission to -2;
select glb('user_not_found'), glb('user_does_not_have_permission');
User-defined parameters are local in the session, therefore the parameters should be defined at the beginning of each session.

Building on #klin's answer, there are a couple of ways to persist a configuration parameter beyond the current session. Note that these require superuser privieges.
To set a value for all connections to a particular database:
ALTER DATABASE db SET abc.xyz = 1;
You can also set a server-wide value using the ALTER SYSTEM command, added in 9.4. It only seems to work for user-defined parameters if they have already been SET in your current session. Note also that this requires a configuration reload to take effect.
SET abc.xyz = 1;
ALTER SYSTEM SET abc.xyz = 1;
SELECT pg_reload_conf();
Pre-9.4, you can accomplish the same thing by adding the parameter to your server's postgresql.conf file. In 9.1 and earlier, you also need to register a custom variable class.

You can use a trick and declare your variables as a 1-row CTE, which you then CROSS JOIN to the rest. See example:
WITH
variables AS (
SELECT 'value1'::TEXT AS var1, 10::INT AS var2
)
SELECT t.*, v.*
FROM
my_table AS t
CROSS JOIN variables AS v
WHERE t.random_int_column = var2;

Postgresql does not support global variables on the DB level. Why not add it:
CREATE TABLE global_variables (
key text not null PRIMARY KEY
value text
);
INSERT INTO global_variables (key, value) VALUES ('error_code_for_spaceship_engine', '404');
If different types may be the values, consider JSON to be the type for value, but then deserialization code is required for each type.

You can use this
CREATE OR REPLACE FUNCTION globals.maxCities()
RETURNS integer AS
$$SELECT 100 $$ LANGUAGE sql IMMUTABLE;
.. and directly use globals.maxCities() in the code.

Related

How to declare a variable in select statement in Postgres SQL [duplicate]

How do I declare a variable for use in a PostgreSQL 8.3 query?
In MS SQL Server I can do this:
DECLARE #myvar INT
SET #myvar = 5
SELECT *
FROM somewhere
WHERE something = #myvar
How do I do the same in PostgreSQL? According to the documentation variables are declared simply as "name type;", but this gives me a syntax error:
myvar INTEGER;
Could someone give me an example of the correct syntax?
I accomplished the same goal by using a WITH clause, it's nowhere near as elegant but can do the same thing. Though for this example it's really overkill. I also don't particularly recommend this.
WITH myconstants (var1, var2) as (
values (5, 'foo')
)
SELECT *
FROM somewhere, myconstants
WHERE something = var1
OR something_else = var2;
There is no such feature in PostgreSQL. You can do it only in pl/PgSQL (or other pl/*), but not in plain SQL.
An exception is WITH () query which can work as a variable, or even tuple of variables. It allows you to return a table of temporary values.
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) > ...;
You could also try this in 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;
The above requires Postgres 9.0 or later.
Dynamic Config Settings
you can "abuse" dynamic config settings for this:
-- choose some prefix that is unlikely to be used by postgres
set session my.vars.id = '1';
select *
from person
where id = current_setting('my.vars.id')::int;
Config settings are always varchar values, so you need to cast them to the correct data type when using them. This works with any SQL client whereas \set only works in psql
The above requires Postgres 9.2 or later.
For previous versions, the variable had to be declared in postgresql.conf prior to being used, so it limited its usability somewhat. Actually not the variable completely, but the config "class" which is essentially the prefix. But once the prefix was defined, any variable could be used without changing postgresql.conf
It depends on your client.
However, if you're using the psql client, then you can use the following:
my_db=> \set myvar 5
my_db=> SELECT :myvar + 1 AS my_var_plus_1;
my_var_plus_1
---------------
6
If you are using text variables you need to quote.
\set myvar 'sometextvalue'
select * from sometable where name = :'myvar';
This solution is based on the one proposed by fei0x but it has the advantages that there is no need to join the value list of constants in the query and constants can be easily listed at the start of the query. It also works in recursive queries.
Basically, every constant is a single-value table declared in a WITH clause which can then be called anywhere in the remaining part of the query.
Basic example with two constants:
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)
Alternatively you can use SELECT * FROM constant_name instead of TABLE constant_name which might not be valid for other query languages different to postgresql.
Using a Temp Table outside of pl/PgSQL
Outside of using pl/pgsql or other pl/* language as suggested, this is the only other possibility I could think of.
begin;
select 5::int as var into temp table myvar;
select *
from somewhere s, myvar v
where s.something = v.var;
commit;
I want to propose an improvement to #DarioBarrionuevo's answer, to make it simpler leveraging temporary tables.
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;
True, there is no vivid and unambiguous way to declare a single-value variable, what you can do is
with myVar as (select "any value really")
then, to get access to the value stored in this construction, you do
(select * from myVar)
for example
with var as (select 123)
... where id = (select * from var)
You may resort to tool special features. Like for DBeaver own proprietary syntax:
#set name = 'me'
SELECT :name;
SELECT ${name};
DELETE FROM book b
WHERE b.author_id IN (SELECT a.id FROM author AS a WHERE a.name = :name);
As you will have gathered from the other answers, PostgreSQL doesn’t have this mechanism in straight SQL, though you can now use an anonymous block. However, you can do something similar with a Common Table Expression (CTE):
WITH vars AS (
SELECT 5 AS myvar
)
SELECT *
FROM somewhere,vars
WHERE something = vars.myvar;
You can, of course, have as many variables as you like, and they can also be derived. For example:
WITH vars AS (
SELECT
'1980-01-01'::date AS start,
'1999-12-31'::date AS end,
(SELECT avg(height) FROM customers) AS avg_height
)
SELECT *
FROM customers,vars
WHERE (dob BETWEEN vars.start AND vars.end) AND height<vars.avg_height;
The process is:
Generate a one-row cte using SELECT without a table (in Oracle you will need to include FROM DUAL).
CROSS JOIN the cte with the other table. Although there is a CROSS JOIN syntax, the older comma syntax is slightly more readable.
Note that I have cast the dates to avoid possible issues in the SELECT clause. I used PostgreSQL’s shorter syntax, but you could have used the more formal CAST('1980-01-01' AS date) for cross-dialect compatibility.
Normally, you want to avoid cross joins, but since you’re only cross joining a single row, this has the effect of simply widening the table with the variable data.
In many cases, you don’t need to include the vars. prefix if the names don’t clash with the names in the other table. I include it here to make the point clear.
Also, you can go on to add more CTEs.
This also works in all current versions of MSSQL and MySQL, which do support variables, as well as SQLite which doesn’t, and Oracle which sort of does and sort of doesn’t.
Here is an example using PREPARE statements. You still can't use ?, but you can use $n notation:
PREPARE foo(integer) AS
SELECT *
FROM somewhere
WHERE something = $1;
EXECUTE foo(5);
DEALLOCATE foo;
In DBeaver you can use parameters in queries just like you can from code, so this will work:
SELECT *
FROM somewhere
WHERE something = :myvar
When you run the query DBeaver will ask you for the value for :myvar and run the query.
Here is a code segment using plain variable in postges terminal. I have used it a few times. But need to figure a better way. Here I am working with string variable. Working with integer variable, you don't need the triple quote. Triple quote becomes single quote at query time; otherwise you got syntax error. There might be a way to eliminate the need of triple quote when working with string variables. Please update if you find a way to improve.
\set strainname '''B.1.1.7'''
select *
from covid19strain
where name = :strainname ;
In psql, you can use these 'variables' as macros. Note that they get "evaluated" every time they are used, rather than at the time that they are "set".
Simple example:
\set my_random '(SELECT random())'
select :my_random; -- gives 0.23330629315990592
select :my_random; -- gives 0.67458399344433542
this gives two different answers each time.
However, you can still use these as a valuable shorthand to avoid repeating lots of subselects.
\set the_id '(SELECT id FROM table_1 WHERE name = ''xxx'' LIMIT 1)'
and then use it in your queries later as
:the_id
e.g.
INSERT INTO table2 (table1_id,x,y,z) VALUES (:the_id, 1,2,3)
Note you have to double-quote the strings in the variables, because the whole thing is then string-interpolated (i.e. macro-expanded) into your query.

DB2oC (DB2 on Cloud) : Facing "attempted to modify data but was not defined as MODIFIES SQL DATA" error

I have created very simple function in DB2oC as below, which has one UPDATE sql statement and one SELECT sql statement along with MODIFIES SQL DATA. But still I get the below error, though I have specified MODIFIES SQL DATA. I did GRANT ALL on that TEST table to my user id and also did GRANT EXECUTE ON FUNCTION to my user id on safe side. Can you please help to explain on what could be the issue?
I have simply invoked the function using SELECT statement like below:
SELECT TESTSCHEMA.MAIN_FUNCTION() FROM TABLE(VALUES(1));
SQL Error [38002]: User defined routine "TESTSCHEMA.MAIN_FUNCTION"
(specific name "SQL201211013006981") attempted to modify data but was
not defined as MODIFIES SQL DATA.. SQLCODE=-577, SQLSTATE=38002,
DRIVER=4.27.25
CREATE OR REPLACE FUNCTION MAIN_FUNCTION()
RETURNS VARCHAR(20)
LANGUAGE SQL
MODIFIES SQL DATA
BEGIN
DECLARE val VARCHAR(20);
UPDATE TEST t SET t.CONTENT_TEXT = 'test value' WHERE t.ID = 1;
select CONTENT_TEXT into val from TEST where ID = 1;
return val;
end;
Appreciate your help.
For the modifies SQL data clause , the usage of the function is restricted on Db2-LUW.
These restrictions do not apply for user defined functions that do not modify data.
For your specific example, that UDF will operate when used as the sole expression on the right hand side of an assignment statement in a compound-SQL compiled statemnent.
For example:
create or replace variable my_result varchar(20) default null;
begin
set my_result = main_function();
end#
Consider using stored procedures to modify table contents, instead of user defined functions.
You could avoid using a function, and just use a single "change data statement"
SELECT CONTENT_TEXT
FROM NEW TABLE(
UPDATE TEST t
SET t.CONTENT_TEXT = 'test value'
WHERE t.ID = 1
)

Assigning variable in SQL editor context in Firebird

I would like to know if it is possible in Firebird to assign and reference a variable in SQL Editor context.
To be clear, I present a code sample in MySQL that do what I want.
SET #var = 10;
SELECT #var;
Firebird only supports variables in PSQL (Procedural SQL), including anonymous procedures (EXECUTE BLOCK). There is no direct equivalent of using variables like in MySQL in DSQL (Dynamic SQL, the normal 'SQL' you use with Firebird).
The closest alternative is to use the context variables using RDB$GET_CONTEXT and RDB$SET_CONTEXT. The near equivalent of your code would be
select RDB$SET_CONTEXT('USER_TRANSACTION', 'var', 10) from RDB$DATABASE;
select RDB$GET_CONTEXT('USER_TRANSACTION', 'var') from RDB$DATABASE;
Be aware, a context variable is stored and retrieved as VARCHAR(255), so if you need to retrieve an integer, you will need to explicitly cast it.
Instead of 'USER_TRANSACTION', with scope limited to the current transaction, you can also use 'USER_SESSION', with scope limited to the current connection.
There is no such thing as "Editor context". Notepad, Word, SynWrite - you can edit anything in them, SQL or not. An editor is just an editor, there is no special context, SQL-wise, in it.
In editor you edit all the SQL texts. DSQL statements, PSQL scripts, everything. Editor does not matter, only difference between DSQL vs PSQL matters here, so read about them in the documentation. Editor has no its own SQL context.
Language-native variables only exist in PSQL context, that is "Procedural" SQL, language used for writing stored procedures, triggers, execute blocks, etc. Also, SQL functions, starting with Firebird 3.
Example from https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-psql.html
CREATE OR ALTER PROCEDURE DEPT_BUDGET (
DNO CHAR(3))
RETURNS (
TOT DECIMAL(12,2))
AS
DECLARE VARIABLE SUMB DECIMAL(12,2);
DECLARE VARIABLE RDNO CHAR(3);
DECLARE VARIABLE CNT INTEGER;
BEGIN
TOT = 0;
SELECT
BUDGET
FROM
DEPARTMENT
WHERE DEPT_NO = :DNO
INTO :TOT;
SELECT
COUNT(BUDGET)
FROM
DEPARTMENT
WHERE HEAD_DEPT = :DNO
INTO :CNT;
IF (CNT = 0) THEN
SUSPEND;
FOR
SELECT
DEPT_NO
FROM
DEPARTMENT
WHERE HEAD_DEPT = :DNO
INTO :RDNO
DO
BEGIN
EXECUTE PROCEDURE DEPT_BUDGET(:RDNO)
RETURNING_VALUES :SUMB;
TOT = TOT + SUMB;
END
SUSPEND;
END
Apart from PSQL in Firebird there are more languages ("contexts"): DSQL (Dynamic SQL), ESQL (Embedded SQL) and pre-SQL native query language. Of those only DSQL is of any general use nowadays.
In DSQL you have no language-level variables, but you have functions to set/fetch parts of context: RDB$GET_CONTEXT() and RDB$SET_CONTEXT().
https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-functions-scalarfuncs.html#fblangref25-functions-workcontext
select rdb$set_context('USER_SESSION', 'MyVar', 493) from rdb$database
and later
select rdb$get_context('USER_SESSION', 'MyVar') from rdb$database
You can not change 'USER_SESSION' here, as that is the only context you are allowed to write something, other contexts for reading only. But you are free to change the 2nd parameter as you like - that is the name of textual environment variable you set and retrieve.
UPD. I was wrong, there is one more writable context, 'USER_TRANSACTION', see 2.0.7 Release Notest at https://firebirdsql.org/file/documentation/release_notes/html/rlsnotes207.html#dml-dsql-context-ns
Read docs by the two links above and also read the file situated like
c:\Program Files (x86)\Firebird\Firebird_2_1\doc\sql.extensions\README.context_variables2.txt
adjust the path for specific Firebird version on your computer. You can see there full list of contexts (first parameter allowed values) available in your FB version.
However, since you want to use language-native variables, think about, using PSQL instead - see EXECUTE BLOCK in Firebird documentation and my first example. If you do not need to return more than one different datasets from your script, then wrapping it all into one EB for the sake of having variables may suit you better.

Anchor row data type variable from declare cursor

How can I declare variable using anchor data type (row) from a declared cursor in db2?
create or replace PROCEDURE "SP_ATUALIZA_ID_DISTRIBUIDOR_FT"
BEGIN
DECLARE C_ID_DIST_ERRADOS CURSOR FOR
SELECT DISTINCT
F.ID_MES,
F.ID_DISTRIBUIDOR_SO,
D.CNPJ_DISTRIBUIDOR_SO,
F.ID_COMPANIA
FROM
DMTLDBR.TB_FATO_VENDAS_SELLOUT F,
DMTLDBR.TB_DIM_ECDISTRIBUIDOR_SO D
WHERE ID_MES <= 201309 AND
F.ID_DISTRIBUIDOR_SO = D.ID_DISTRIBUIDOR_SO AND
F.ID_COMPANIA <> D.ID_COMPANIA
ORDER BY ID_MES;
BEGIN
DECLARE REG_C_ID_DIST_ERRADOS ANCHOR ROW OF C_ID_DIST_ERRADOS;
OPEN C_ID_DIST_ERADOS
...
END;
END;
I've a procedure that is declaring a internal cursor, which will be used to fetch results and insert into a variable 'reg_c_id_dist_errados'. I've tried to use "anchor row of" but db2 has alerted me.
You can anchor a type to a row of a table , among other things. There are different ways to use these things depending on your requirements.
Your query has a join so you can declare a type to match each row from the cursor, and you can then declare strongly-typed cursor-type for your rowtype. Later you can assign a query to a variable of that cursor-type.
You can pass cursors as parameters to stored procedures, and you can have a procedure return a cursor type, and you can declare variables of each of the types you create.
You don't show whether you want the result-set of the procedure to be a cursor-type, or whether you want to process the result-set inside the stored-procedure in typed variables.
Study the Db2 Knowledge Centre for your version of Db2-LUW to learn about strongly typed cursors and how to use them in SQL PL.
There is an example online (shown as a module, but you can use the same techniques in a stored procedures) in this file "modules.db2" which also appears under the SAMPLES directory on your DB2-LUW server if you installed the samples component at installation time.
You can see the example online at
the example modules.sql
Here is one suggestion for using user defined types for a row-type that matches the cursor in your code:
--#SET TERMINATOR #
-- this type represents a row that might be returned in the cursor.
-- Choose your own name for the type.
-- Choose the correct data-types for your tables.
create or replace type DE_ROW_T as row
(
id_mes bigint,
ID_DISTRIBUIDOR_SO bigint,
CNPJ_DISTRIBUIDOR_SO bigint,
ID_COMPANIA bigint
)#
create or replace type C_ID_DIST_ERRADOS_CURSOR_T as DE_ROW_T CURSOR#
create or replace PROCEDURE "SP_ATUALIZA_ID_DISTRIBUIDOR_FT"
language sql
specific SP_ATUALIZA_ID_DISTRIBUIDOR_FT
BEGIN
DECLARE V_ROW DE_ROW_T;
DECLARE C_ID_DIST_ERRADOS C_ID_DIST_ERRADOS_CURSOR_T;
SET C_ID_DIST_ERRADOS = CURSOR FOR
SELECT DISTINCT
F.ID_MES,
F.ID_DISTRIBUIDOR_SO,
D.CNPJ_DISTRIBUIDOR_SO,
F.ID_COMPANIA
FROM
DMTLDBR.TB_FATO_VENDAS_SELLOUT F,
DMTLDBR.TB_DIM_ECDISTRIBUIDOR_SO D
WHERE ID_MES <= 201309 AND
F.ID_DISTRIBUIDOR_SO = D.ID_DISTRIBUIDOR_SO AND
F.ID_COMPANIA <> D.ID_COMPANIA
ORDER BY ID_MES;
OPEN C_ID_DIST_ERRADOS;
FETCH C_ID_DIST_ERRADOS INTO v_row;
END#

Postgresql & PgAdmin SIMPLE variable [duplicate]

How do I declare a variable for use in a PostgreSQL 8.3 query?
In MS SQL Server I can do this:
DECLARE #myvar INT
SET #myvar = 5
SELECT *
FROM somewhere
WHERE something = #myvar
How do I do the same in PostgreSQL? According to the documentation variables are declared simply as "name type;", but this gives me a syntax error:
myvar INTEGER;
Could someone give me an example of the correct syntax?
I accomplished the same goal by using a WITH clause, it's nowhere near as elegant but can do the same thing. Though for this example it's really overkill. I also don't particularly recommend this.
WITH myconstants (var1, var2) as (
values (5, 'foo')
)
SELECT *
FROM somewhere, myconstants
WHERE something = var1
OR something_else = var2;
There is no such feature in PostgreSQL. You can do it only in pl/PgSQL (or other pl/*), but not in plain SQL.
An exception is WITH () query which can work as a variable, or even tuple of variables. It allows you to return a table of temporary values.
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) > ...;
You could also try this in 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;
The above requires Postgres 9.0 or later.
Dynamic Config Settings
you can "abuse" dynamic config settings for this:
-- choose some prefix that is unlikely to be used by postgres
set session my.vars.id = '1';
select *
from person
where id = current_setting('my.vars.id')::int;
Config settings are always varchar values, so you need to cast them to the correct data type when using them. This works with any SQL client whereas \set only works in psql
The above requires Postgres 9.2 or later.
For previous versions, the variable had to be declared in postgresql.conf prior to being used, so it limited its usability somewhat. Actually not the variable completely, but the config "class" which is essentially the prefix. But once the prefix was defined, any variable could be used without changing postgresql.conf
It depends on your client.
However, if you're using the psql client, then you can use the following:
my_db=> \set myvar 5
my_db=> SELECT :myvar + 1 AS my_var_plus_1;
my_var_plus_1
---------------
6
If you are using text variables you need to quote.
\set myvar 'sometextvalue'
select * from sometable where name = :'myvar';
This solution is based on the one proposed by fei0x but it has the advantages that there is no need to join the value list of constants in the query and constants can be easily listed at the start of the query. It also works in recursive queries.
Basically, every constant is a single-value table declared in a WITH clause which can then be called anywhere in the remaining part of the query.
Basic example with two constants:
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)
Alternatively you can use SELECT * FROM constant_name instead of TABLE constant_name which might not be valid for other query languages different to postgresql.
Using a Temp Table outside of pl/PgSQL
Outside of using pl/pgsql or other pl/* language as suggested, this is the only other possibility I could think of.
begin;
select 5::int as var into temp table myvar;
select *
from somewhere s, myvar v
where s.something = v.var;
commit;
I want to propose an improvement to #DarioBarrionuevo's answer, to make it simpler leveraging temporary tables.
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;
True, there is no vivid and unambiguous way to declare a single-value variable, what you can do is
with myVar as (select "any value really")
then, to get access to the value stored in this construction, you do
(select * from myVar)
for example
with var as (select 123)
... where id = (select * from var)
You may resort to tool special features. Like for DBeaver own proprietary syntax:
#set name = 'me'
SELECT :name;
SELECT ${name};
DELETE FROM book b
WHERE b.author_id IN (SELECT a.id FROM author AS a WHERE a.name = :name);
As you will have gathered from the other answers, PostgreSQL doesn’t have this mechanism in straight SQL, though you can now use an anonymous block. However, you can do something similar with a Common Table Expression (CTE):
WITH vars AS (
SELECT 5 AS myvar
)
SELECT *
FROM somewhere,vars
WHERE something = vars.myvar;
You can, of course, have as many variables as you like, and they can also be derived. For example:
WITH vars AS (
SELECT
'1980-01-01'::date AS start,
'1999-12-31'::date AS end,
(SELECT avg(height) FROM customers) AS avg_height
)
SELECT *
FROM customers,vars
WHERE (dob BETWEEN vars.start AND vars.end) AND height<vars.avg_height;
The process is:
Generate a one-row cte using SELECT without a table (in Oracle you will need to include FROM DUAL).
CROSS JOIN the cte with the other table. Although there is a CROSS JOIN syntax, the older comma syntax is slightly more readable.
Note that I have cast the dates to avoid possible issues in the SELECT clause. I used PostgreSQL’s shorter syntax, but you could have used the more formal CAST('1980-01-01' AS date) for cross-dialect compatibility.
Normally, you want to avoid cross joins, but since you’re only cross joining a single row, this has the effect of simply widening the table with the variable data.
In many cases, you don’t need to include the vars. prefix if the names don’t clash with the names in the other table. I include it here to make the point clear.
Also, you can go on to add more CTEs.
This also works in all current versions of MSSQL and MySQL, which do support variables, as well as SQLite which doesn’t, and Oracle which sort of does and sort of doesn’t.
Here is an example using PREPARE statements. You still can't use ?, but you can use $n notation:
PREPARE foo(integer) AS
SELECT *
FROM somewhere
WHERE something = $1;
EXECUTE foo(5);
DEALLOCATE foo;
In DBeaver you can use parameters in queries just like you can from code, so this will work:
SELECT *
FROM somewhere
WHERE something = :myvar
When you run the query DBeaver will ask you for the value for :myvar and run the query.
Here is a code segment using plain variable in postges terminal. I have used it a few times. But need to figure a better way. Here I am working with string variable. Working with integer variable, you don't need the triple quote. Triple quote becomes single quote at query time; otherwise you got syntax error. There might be a way to eliminate the need of triple quote when working with string variables. Please update if you find a way to improve.
\set strainname '''B.1.1.7'''
select *
from covid19strain
where name = :strainname ;
In psql, you can use these 'variables' as macros. Note that they get "evaluated" every time they are used, rather than at the time that they are "set".
Simple example:
\set my_random '(SELECT random())'
select :my_random; -- gives 0.23330629315990592
select :my_random; -- gives 0.67458399344433542
this gives two different answers each time.
However, you can still use these as a valuable shorthand to avoid repeating lots of subselects.
\set the_id '(SELECT id FROM table_1 WHERE name = ''xxx'' LIMIT 1)'
and then use it in your queries later as
:the_id
e.g.
INSERT INTO table2 (table1_id,x,y,z) VALUES (:the_id, 1,2,3)
Note you have to double-quote the strings in the variables, because the whole thing is then string-interpolated (i.e. macro-expanded) into your query.