I want to delete all database entries in my Postgres database that are older than X minutes. My prepared statement in go looks like this:
delete
from my_table
where expires < (to_timestamp($1) - '$2 minutes'::interval);
How can I correctly pass the second parameter $2?
PS: I know there's different statements to solve the problem, but I am explicitly interested in how to pass parameters that are quoted.
There is no way to interpolate a parameter into a string literal.
A possible solution for your case would be to multiply a number with an interval:
where expires < (to_timestamp($1) - $2 * '1 minute'::interval)
You can cast the parameter to text and then concatenate it with the string ' minutes'.
delete from my_table
where expires < (to_timestamp($1) - ($2::text || ' minutes')::interval
UPDATE: actually, since postgres does have a any || text operator, the result of which is text, you shouldn't need to type cast the parameter.
You can use make_interval
delete from my_table
where expires < (to_timestamp($1) - make_interval(mins => $2));
You can also parametrize the entire interval string instead. This removes the need for an intermediate cast to text and concat.
query := `
delete from my_table
where expires < (to_timestamp($1) - $2::interval);
`
interval := fmt.Sprintf("%d minutes", mins)
db.Exec(query, timestamp, interval)
Related
select service_code,service_cat_code,mobile_no,upper(applicant_name_eng) as name,to_char(license_date,'dd/mm/yyyy')as license_from,to_char(license_valid_upto,'dd/mm/yyyy')as license_to,Upper(license_no),district_code,taluk_code,CONCAT(address_building,', ', address_cityvillage,', ',address_locality,', ',address_landmark,', ',address_street) as address
from mst_license
WHERE cast(license_valid_upto as date) = case
WHEN license_valid_upto < now()
THEN
case
when license_valid_upto = '2021-06-30'
then 1 else 0
END
ELSE
case when license_valid_upto > now()
then 1 else 0
End
END
and Upper(license_no)='1SP146924BJP'
I want license valid should be either greater than now or if license valid less than now it must be with the date ''30/06/2021' but when i use above query i get error
ERROR: operator does not exist: date = integer
LINE 3: WHERE cast(license_valid_upto as date) = case
^
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
SQL state: 42883
Character: 418
Help me out guys
The main issue you have is that your case statement returns an integer (1 or 0) but you are trying to compare that to a date, which you cannot do as Postgres is a strict data typing. Even if it did work it would always be false (well except for 1969-12-31/1970-01-01). Moreover the case structure is not needed. The best/correct to compare dates is just use date values. Since you did not indicate the data type for column license_valid_upto so based on how it is used I'll assume it is timestamp with timezone as that is what NOW() returns. Your query becomes:
select service_code
, service_cat_code
, mobile_no
, upper(applicant_name_eng) as name
, to_char(license_date,'dd/mm/yyyy')as license_from
, to_char(license_valid_upto,'dd/mm/yyyy')as license_to
, upper(license_no) as license_no
, district_code
, taluk_code
, concat(address_building,', '
,address_cityvillage,', '
,address_locality,', '
,address_landmark,', '
,address_street) as address
from mst_license
where and upper(license_no)='1SP146924BJP'
and ( cast(license_valid_upto as date) > cast( now() as date)
or (cast (icense_valid_upto as date) < cast( now() as date)
and cast (icense_valid_upto as date) = date '2021-06-30'
)
);
Also, learn for format your queries for readability and so you do not need to scroll right. You, and others looking at your queries later will appreciate it later.
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.
I have a float8 that contains a number of seconds ie 65.455. I was trying to format a column in a view so that it would read as 1:05.455.
Using postgres command like this:
TO_CHAR((user_data.totaltime || ' second')::interval, 'MI:SS')
I can format it as 1:05 but i loose the precision i need.
Anyone know of a way to achieve what i need ? It doesn't look like interval allows the formatting of milliseconds.
Try justify_interval:
SELECT justify_interval(
CAST(65.455::text || ' seconds' AS interval)
);
Here is a rather brute force you may do this, using the base string functions:
SELECT
FLOOR(65.455 / 60)::text || ':' || LPAD(FLOOR(65.455 % 60)::text, 2, '0') ||
TRIM(LEADING '0' FROM (65.455 % 1)::text);
This outputs:
1:05.455
Demo
i have a starting table where there are some meteo data stored every 15 minutes, one field stores leaf wet at 1 minute sampling in a numeric array form, thus i have a 15 values array each row.
Now i want to create a 1 hour aggregation of this table, crating an array of 60 values for this field.
I tried array_cat at first place, but says
array_cat(numeric[]) not existing
the function obviuously exists, so i tought the format was not the one expected, i tried first unnesting and then aggregating, not working again.
Finally i was able to aggregate trough string conversion, but it's not what i wanted (i might in the future apply some numeric elaboration oh that 60-values array)
I paste the query for further investigations
SELECT dati1_v.id_stazione,
to_char(dati1_v.data_ora, 'YYYY-MM-DD HH24:00:00'::text) AS date_hour,
round(avg(dati1_v.temp1_media), 2) AS t_avg,
round(avg(dati1_v.ur1_media), 2) AS hum_avg,
sum(dati1_v.pioggia) AS rain_tot,
max(dati1_v.pioggia) AS rain_max,
round((avg((SELECT avg(lw.lw) AS avg FROM unnest(dati1_v.lw_top_array) lw(lw))) - lws.top_min) /
(lws.top_max - lws.top_min) * 100::numeric, 2) AS lw_top_avg,
array_agg((SELECT round((avg(lw.lw) - lws.top_min) / (lws.top_max - lws.top_min) * 100::numeric, 2) AS round
FROM unnest(dati1_v.lw_top_array) lw(lw))) AS lw_top_array,
array_cat(dati1_v.lw_top_array) AS lw_top_array_tot,
-- array_agg((select lw_top_array from unnest(dati1_v.lw_top_array))) AS lw_top_array_tot,
-- array_agg(array_to_string(dati1_v.lw_top_array, ',')) AS lw_top_array_tot,
round((avg((SELECT avg(lw.lw) AS avg FROM unnest(dati1_v.lw_bottom_array) lw(lw))) - lws.bottom_min) /
(lws.bottom_max - lws.bottom_min) * 100::numeric, 2) AS lw_bottom_avg,
array_agg((SELECT round((avg(lw.lw) - lws.bottom_min) / (lws.bottom_max - lws.bottom_min) * 100::numeric,
2) AS round
FROM unnest(dati1_v.lw_bottom_array) lw(lw))) AS lw_bottom_array
FROM dati1_v,
lw_settings lws
WHERE lws.id = 1
GROUP BY dati1_v.id_stazione, to_char(dati1_v.data_ora, 'YYYY-MM-DD HH24:00:00'::text), lws.top_min, lws.top_max,
lws.bottom_min, lws.bottom_max
ORDER BY dati1_v.id_stazione, to_char(dati1_v.data_ora, 'YYYY-MM-DD HH24:00:00'::text)
in particular, my tries were related to this specific block:
array_cat(dati1_v.lw_top_array) AS lw_top_array_tot,
-- array_agg((select lw_top_array from unnest(dati1_v.lw_top_array))) AS lw_top_array_tot,
-- array_agg(array_to_string(dati1_v.lw_top_array, ',')) AS lw_top_array_tot
Thanks
For me in similar case helped UNNEST in subquery and ARRAY_AGG of unnnested
SELECT
ARRAY_AGG(
DISTINCT lw_top
) as lw_top_array
FROM (
SELECT
UNNEST(lw_top_array) AS lw_top
FROM
dati1_v
) as tmp;
for me helped next query
SELECT
my_table.key,
array_agg(_unnested.item) as array_coll
from my_table
left join LATERAL (SELECT unnest(my_table.array_coll) as item) _unnested ON TRUE
GROUP by my_table.key
In PostgreSQL, the Group_concat function is not available but you can get similar result as string_agg and array_to_string.
string_agg(array_to_string(file_ids, ','), ',') filter ( where file_ids notnull ) AS file_ids_str
array_to_string and array_to_string works in next way
array_to_string([1, 2, 456], ',') => '1,2,456'
string_agg(['a', 'ab'], ',') => 'a,ab'
the only problem is that result is string with ',' as separator
In PostgreSQL: I convert string to timestamp with to_timestamp():
select * from ms_secondaryhealthcarearea
where to_timestamp((COALESCE(update_datetime, '19900101010101'),'YYYYMMDDHH24MISS')
> to_timestamp('20121128191843','YYYYMMDDHH24MISS')
But I get this error:
ERROR: syntax error at end of input
LINE 1: ...H24MISS') >to_timestamp('20121128191843','YYYYMMDDHH24MISS')
^
********** Error **********
ERROR: syntax error at end of input
SQL state: 42601
Character: 176
Why? How to convert a string to timestamp?
One too many opening brackets. Try this:
select *
from ms_secondaryhealthcarearea
where to_timestamp(COALESCE(update_datetime, '19900101010101'),'YYYYMMDDHH24MISS') >to_timestamp('20121128191843','YYYYMMDDHH24MISS')
You had two opening brackets at to_timestamp:
where to_timestamp((COA.. -- <-- the second one is not needed!
#ppeterka has pointed out the syntax error.
The more pressing question is: Why store timestamp data as string to begin with? If your circumstances allow, consider converting the column to its proper type:
ALTER TABLE ms_secondaryhealthcarearea
ALTER COLUMN update_datetime TYPE timestamp
USING to_timestamp(update_datetime,'YYYYMMDDHH24MISS');
Or use timestamptz - depending on your requirements.
Another way to convert a string to a timestamp type of PostgreSql is the above,
SELECT to_timestamp('23-11-1986 06:30:00', 'DD-MM-YYYY hh24:mi:ss')::timestamp without time zone;
I had the same requirement as how I read the title. How to convert an epoch timestamp as text to a real timestamp. In my case I extracted one from a json object. So I ended up with a timestamp as text with milliseconds
'1528446110978' (GMT: Friday, June 8, 2018 8:21:50.978 AM)
This is what I tried. Just the latter (ts_ok_with_ms) is exactly right.
SELECT
data->>'expiration' AS expiration,
pg_typeof(data->>'expiration'),
-- to_timestamp(data->>'expiration'), < ERROR: function to_timestamp(text) does not exist
to_timestamp(
(data->>'expiration')::int8
) AS ts_wrong,
to_timestamp(
LEFT(
data->>'expiration',
10
)::int8
) AS ts_ok,
to_timestamp(
LEFT(
data->>'expiration',
10
)::int8
) + (
CASE
WHEN LENGTH(data->>'expiration') = 13
THEN RIGHT(data->>'expiration', 3) ELSE '0'
END||' ms')::interval AS ts_ok_with_ms
FROM (
SELECT '{"expiration": 1528446110978}'::json AS data
) dummy
This is the (transposed) record that is returned:
expiration 1528446110978
pg_typeof text
ts_wrong 50404-07-12 12:09:37.999872+00
ts_ok 2018-06-08 08:21:50+00
ts_ok_with_ms 2018-06-08 08:21:50.978+00
I'm sure I overlooked a simpler version of how to get from a timestamp string in a json object to a real timestamp with ms (ts_ok_with_ms), but I hope this helps nonetheless.
Update: Here's a function for your convenience.
CREATE OR REPLACE FUNCTION data.timestamp_from_text(ts text)
RETURNS timestamptz
LANGUAGE SQL AS
$$
SELECT to_timestamp(LEFT(ts, 10)::int8) +
(
CASE
WHEN LENGTH(ts) = 13
THEN RIGHT(ts, 3) ELSE '0'
END||' ms'
)::interval
$$;