57

SQL Server has the ability to declare a variable, then call that variable in a query like so:

DECLARE @StartDate date;
SET @StartDate = '2015-01-01';

SELECT *
FROM Orders
WHERE OrderDate >= @StartDate;

Does this functionality work in Amazon's RedShift? From the documentation, it looks that DECLARE is used solely for cursors. SET looks to be the function I am looking for, but when I attempt to use that, I get an error.

set session StartDate = '2015-01-01';
 [Error Code: 500310, SQL State: 42704]  [Amazon](500310) Invalid operation: unrecognized configuration parameter "startdate";

Is it possible to do this in RedShift?

John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
mikebmassey
  • 8,354
  • 26
  • 70
  • 95

7 Answers7

67

Slavik Meltser's answer is great. As a variation on this theme, you can also use a WITH construct:

WITH tmp_variables AS (
SELECT 
   '2015-01-01'::DATE AS StartDate, 
   'some string'      AS some_value,
   5556::BIGINT       AS some_id
)

SELECT *
FROM Orders
WHERE OrderDate >= (SELECT StartDate FROM tmp_variables);
jrenk
  • 1,387
  • 3
  • 24
  • 46
Johan Lammens
  • 681
  • 1
  • 5
  • 3
  • 1
    this is better in my use-case: a custom ETLM system that won't `explain` the second statement after create tempe table. – Merlin Jan 15 '18 at 00:56
  • 1
    You are correct, it will also work. But, this is only aesthetic approach, as `WITH` statement in Redshift transforms into a `TEMP TABLE` anyway during a query run. – Slavik Meltser Jan 10 '19 at 19:33
  • I wonder if it has any impact on performance or if RedShift is smart enough to understand that those are constants. E.g would it evaluate the (Select StartDate..) on every row or just run and store the result once. I made assumptions about RedShift's ability to optimize, but I found with "where" clauses it's actually very slow. – Leo Ufimtsev Jan 13 '22 at 13:59
  • 1
    [EDIT] Curiosity got the best of me. I tested with a query that scans over 50+ million rows and does aggregate/distinct functions. Hard-coding dates or using dates via function (DATE/TO_TIMESTAMP) and inside "WITH" clause has no impact on performance. (~18 seconds). ```WITH vars as (SELECT TO_TIMESTAMP('2021-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')::TIMESTAMP as from_date``` – Leo Ufimtsev Jan 13 '22 at 14:26
43

Actually, you can simulate a variable using a temporarily table, create one, set data and you are good to go.

Something like this:

CREATE TEMP TABLE tmp_variables AS SELECT 
   '2015-01-01'::DATE AS StartDate, 
   'some string'      AS some_value,
   5556::BIGINT       AS some_id;

SELECT *
FROM Orders
WHERE OrderDate >= (SELECT StartDate FROM tmp_variables);

The temp table will be deleted after the transaction execution.
Temp tables are bound per session (connect), therefor cannot be shared across sessions.

Slavik Meltser
  • 9,712
  • 3
  • 47
  • 48
26

No, Amazon Redshift does not have the concept of variables. Redshift presents itself as PostgreSQL, but is highly modified.

There was mention of User Defined Functions at the 2014 AWS re:Invent conference, which might meet some of your needs.

Update in 2016: Scalar User Defined Functions can perform computations but cannot act as stored variables.

John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
9

Note that if you are using the psql client to query, psql variables can still be used as always with Redshift:

$ psql --host=my_cluster_name.clusterid.us-east-1.redshift.amazonaws.com \
     --dbname=your_db   --port=5432 --username=your_login -v dt_format=DD-MM-YYYY

# select current_date;     
    date    
------------
 2015-06-15
(1 row)

# select to_char(current_date,:'dt_format');
  to_char   
------------
 15-06-2015
(1 row)

# \set
AUTOCOMMIT = 'on'
...
dt_format = 'DD-MM-YYYY'
...
# \set dt_format 'MM/DD/YYYY'
# select to_char(current_date,:'dt_format');
  to_char   
------------
 06/15/2015
(1 row)
DogBoneBlues
  • 362
  • 1
  • 5
5

You can now use user defined functions (UDF's) to do what you want:

CREATE FUNCTION my_const()
    RETURNS CSTRING IMMUTABLE AS 
    $$ return 'my_string_constant' $$ language plpythonu;

Unfortunately, this does require certain access permissions on your redshift database.

nbubis
  • 2,304
  • 5
  • 31
  • 46
0

Not an exact answer but in DBeaver, you can set up variables to use in your local queries in the IDE. Our team has found this helpful in testing before we put code into production.

From this answer: https://stackoverflow.com/a/58308439/220997

You should then be able to do:

@set date = '2019-10-09'

SELECT ${date}::DATE, ${date}::TIMESTAMP WITHOUT TIME ZONE

which produces:

| date       | timestamp           |
|------------|---------------------|
| 2019-10-09 | 2019-10-09 00:00:00 |

Again note: This only works in the DBeaver IDE. This SQL won't work when integrated in stored procedures or called from other tools

Gabe
  • 5,113
  • 11
  • 55
  • 88
0

Redshift is built on old postgres. In running session:

set param.variable = 'xxx'
select current_setting('param.variable')
Output`xxx`

select * 
  from your_table
 where filter_column = current_setting('param.variable')