postgresql ERROR: syntax error at or near "CONCAT" - postgresql

i am trying to fetch users list who older than and between 20 to 60 minute randomly. here is my query
SELECT *
FROM t_users
WHERE create_time <= NOW() - INTERVAL CONCAT(floor(random()* (60-20 + 1) + 20),' minutes');
it's giving me error ERROR: syntax error at or near "CONCAT"

You can't use concat() like that to create an interval. The easiest solution is to use make_interval:
WHERE create_time <= NOW() - make_interval(mins => (floor(random()* (60-20 + 1) + 20))::int )

Related

HQL / Postgres : ERROR: operator does not exist: timestamp with time zone + integer

I am trying to familiarise myself with Hql, Postgres and JDBC queries. I have a simple query to retrieve records from a table that were modified in last week :
String query = "SELECT t.id FROM table t"
+ " WHERE CURRENT_TIMESTAMP <= t.last_modified_timestamp + 7";
but getting this exception:
nested exception is org.postgresql.util.PSQLException: ERROR: operator
does not exist: timestamp with time zone + integer
Did I miss something? I probably missed the right command to do so.

Data factory Postgres query date time error

I have a postgressql query. I tried it in db query and it seems to work fine. But in data bricks its not working as expected.
I have to use where clause. Where I am extracting date from timestamp and comparing it with passed value (which is in date time format). I am extracting date and checking if its less than the one from timestamp.
Pls check in the WHERE clause.
select DATE(to_timestamp(time,'YYYY-MM-DD %H24:%m:%s' )) as modifiedtime, *
FROM testg
WHERE DATE(to_timestamp(time,'YYYY-MM-DD %H24:%m:%s' )) >= DATE(to_timestamp('2020-10-25 00:00:00','YYYY-MM-DD %H24:%m:%s' )) - INTERVAL '7 DAY'
order by time asc
In data factory the query looks like:
#concat('select * FROM streamingData WHERE property_name = ''', item(), '''' ,' AND DATE(to_timestamp(''', activity('Lookup1').output.firstRow.max_timestamp, '''',',''','YYYY-MM-DD %H24:%m:%s', ''' ))' ,' >= ''', 'DATE(to_timestamp(''', pipeline().parameters.enddate, '''',',''','YYYY-MM-DD %H24:%m:%s', ''' ))' )
Data:
time:
"2020-10-25 13:00:22.000000+01"
"2020-10-24 14:00:22.000000+01"
"2020-10-25 12:00:22.000000+01"
"2020-10-26 01:00:22.000000+01"
and I am using trigger().outputs.windowEndTime() -
output is: 2020-10-20 01:00:22
I am comparing both the date values i.e.
If 2020-10-26 >= 2020-10-20
Even after filtering, i get all the data i.e. also the dates from 2019 etc.
What am I missing.
Strangely I tried the comparison using Between (which was not working) and I was still getting all the years even after filtering.
Methods used :
Used between clause - was not working
Used <= and >= - was also not working.
I used later "SYMMETRIC" function. with between - with which the filter worked. I suppose in BETWEEN SYMMETRIC the arguments are automatically swapped and that a nonempty range is always implied.
at the end the query is like:
#concat('select * FROM streamingData WHERE property_name = ''', item(), '''' ,' AND time BETWEEN SYMMETRIC to_timestamp(''', activity('LKP_RMS_ValueStream_Time').output.firstRow.max_timestamp, '''',',''','YYYY-MM-DD', ''' )' ,' AND ', 'to_timestamp(''', pipeline().parameters.enddate, '''',',''','YYYY-MM-DD', ''' )' , ' - ', 'INTERVAL ''', '7 DAY', '''' )
Thanks for the time and help.

ERROR: operator does not exist: timestamp without time zone + integer

i am adding nthmonth (2) in my postgresql function , but at the time of execution it showing error "ERROR: operator does not exist: timestamp without time zone + integer"
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
QUERY: SELECT pi_date + nthMonth || ' month ' :: INTERVAL
DECLARE
beginMonth timestamp;
pi_date timestamp := to_timestamp('14-Jan-2016 01:50 AM,'DD-MON-YYYY HH:MI AM);
> beginMonth := pi_date + nthMonth || ' month ' :: INTERVAL;
It's fairly obvious - the "+" is binding more tightly than the "||" (as it is telling you).
You want something like:
pi_date + (nthMonth || ' months'::interval)
Or, perhaps a little clearer:
pi_date + (nthMonth * interval '1 month')

PostgreSQL, Npgsql returning 42601: syntax error at or near "$1"

I'm trying to use Npgsql and/or Dapper to query a table and I keep running into Npgsql.PostgresException 42601: syntax error at or near "$1".
Here is what I've got trying it with NpgsqlCommand:
using (var conn = new NpgsqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["postgres"].ConnectionString))
{
conn.Open();
using (NpgsqlCommand command = new NpgsqlCommand("select * from Logs.Logs where Log_Date > current_date - interval #days day;", conn))
{
command.Parameters.AddWithValue("#days", days);
var reader = command.ExecuteReader();
I've also tried it with Dapper(my preferred method) with:
using (var conn = new NpgsqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["postgres"].ConnectionString))
{
conn.Open();
var logs = conn.Query<Log>("select * from Logs.Logs where Log_Date > current_date - interval #days day;", new {days = days});
Either way I get the same Npgsql.PostgresException 42601: syntax error at or near "$1" error. The Statement in the Exception shows: select * from Logs.Logs where Log_Date > current_date - interval $1 day
Note, if I do the following it works fine, but it's not properly parameterized:
var logs = conn.Query<Log>("select * from Logs.Logs where Log_Date > current_date - interval '" + days + "' day;");
What am I doing wrong? I very much appreciate any feedback. Thank you.
PostgreSQL doesn't allow you to stick a parameter anywhere in a query. What you want can be achieved with the following:
var command = new NpgsqlCommand("select * from Logs.Logs where Log_Date > current_date - #days", conn))
command.Parameters.AddWithValue("#days", TimeSpan.FromDays(days));
This way you're passing the interval directly from Npgsql to PostgreSQL, rather than a part of the expression designed to create that interval.
i got this error using DapperExtensions
adding
DapperExtensions.DapperExtensions.SqlDialect = new PostgreSqlDialect();
DapperAsyncExtensions.SqlDialect = new PostgreSqlDialect();
before creating the connection fixed the issue
To subtract days from a date (assuming log_date is data type date), you can simplify:
"SELECT * FROM logs.logs WHERE log_date > CURRENT_DATE - #days;"
And provide #days as unquoted numeric literal (digits only) - which is taken to be an integer. This is even more efficient, since date - integer returns date, while date - interval returns timestamp.
The manual about interval input.

Using named placeholders with interval fails in PHP and PostgreSQL

Okay I've confirmed this works explicitly with PHP.
$ php --version
PHP 5.6.16 (cli) (built: Dec 30 2015 15:09:50) (DEBUG)
<pdo version>
pdo_pgsql
PDO Driver for PostgreSQL enabled
PostgreSQL(libpq) Version 9.4.0
Module version 1.0.2
Revision $Id: fe003f8ab9041c47e97784d215c2488c4bda724d $
I would like to recreate the following SQL in PHP using PDO:
UPDATE relationships SET status = 4 WHERE created > NOW() - interval '2 seconds';
This script is working:
<?php
$db = new PDO('pgsql:dbname=db;host=localhost;user=stevetauber');
$stmt = $db->prepare("UPDATE relationships SET status = 4 WHERE created > NOW() - interval '?'");
$stmt->execute(array("2 seconds"));
Here it is with named placeholders:
<?php
$db = new PDO('pgsql:dbname=db;host=localhost;user=stevetauber');
$stmt = $db->prepare("UPDATE relationships SET status = 4 WHERE created > NOW() - interval ':blah'");
$stmt->execute(array(":blah" => "2 seconds"));
Which gives this error:
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: :blah in ... line 5
Now according to PHP documentation,
Example #6 Invalid use of placeholder:
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute(array($_GET['name']));
// placeholder must be used in the place of the whole value
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(array("%$_GET[name]%"));
?>
Here is the updated code:
<?php
$db = new PDO('pgsql:dbname=db;host=localhost;user=stevetauber');
$stmt = $db->prepare("UPDATE relationships SET status = 4 WHERE created > NOW() - :blah");
$stmt->execute(array(":blah" => "interval '2 seconds'"));
Which yields these DB errors (no script errors):
ERROR: operator does not exist: timestamp with time zone > interval at character 51
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
STATEMENT: UPDATE relationships SET status = 4 WHERE created > NOW() - $1
PDO is doing something weird here though because:
# select NOW() - interval '2 seconds' as a , pg_typeof(NOW() - interval '2 seconds') as b;
a | b
-------------------------------+--------------------------
2015-12-30 18:02:20.956453+00 | timestamp with time zone
(1 row)
So how do I use named placeholders with PostgreSQL and interval?
Placeholders are for pure values, not for values decorated with units (or with anything else).
To express interval '2 seconds' in a placeholder, there are two options:
in the query, write :secs * interval '1 second'
and bind :secs to a number in php
or write: cast(:mystring as interval), and bind :mystring to the string '2 seconds'. It will be interpreted dynamically through the explicit cast.
When experimenting with the psql command line client to compare with the PDO driver, use the PREPARE and EXECUTE SQL statements with postgres native $N placeholders, as opposed to having the parameters values already written literally in the query. This will match what the PHP driver is essentially doing when PDO::ATTR_EMULATE_PREPARES is set to false.
In the last part of you question, when trying this in psql (your query, just simplified to not need a table):
select now() > now() - interval '2 seconds';
it does work and returns 't' (true).
But if you tried that:
prepare p as select now() > now() - $1;
if would fail with
ERROR: operator does not exist: timestamp with time zone > interval
which is the same error as with PDO's prepare/execute.
On the other hand, this does work:
=> prepare p as select now() > now() - interval '1 second'*$1;
PREPARE
=> execute p(2);
?column?
----------
t