function to_char(unknown, unknown) is not unique - postgresql

When running the following the query.select * from surgicals where to_char(dt_surgery ,'DD-MM-YYYY' ) = to_char('12-02-2012','DD-MM-YYYY');
the error coming as 'SQL state 42725: ERROR: function to_char(unknown, unknown) is not unique'
How to run above select query?

You probably mean to_char('12-02-2012'::date, 'DD-MM-YYYY'). to_char cannot convert a plain string to string. Still, it does not seem to make sense, you need one of these two, depending on the format of your date constant (which cannot be determined from the actual example date you provided):
select * from surgicals where to_char(dt_surgery ,'DD-MM-YYYY' ) = '12-02-2012';
select * from surgicals where to_char(dt_surgery ,'MM-DD-YYYY' ) = '12-02-2012';

The wrongness here is that you're doing string comparison of dates. Use date/time math, which can take into account fun things like time zones etc. and still get it right.

Maybe this is what you need:
SELECT *
FROM surgicals
WHERE date_trunc('day', dt_surgery) = '2012-02-12'
;

Related

Querying date/time on 2 columns

I have a column date and column time on my PostgreSQL table. I wish to make a query, to filter rows that are not expired based on date and time. I tried this, but it does not works and returns an error Postgrex.Error) ERROR 42601 (syntax_error) syntax error at or nea:
from q in Line, where: fragment("date ? + time ? > NOW()", q.date, q.time)
I think this problem can be solved by not using time and date prefixes:
from q in Line, where: fragment("? + ? > NOW()", q.date, q.time)
or even
from q in Line, where: q.date + q.time < fragment("NOW()")
Provided, your columns have the correct data type
not sure if you need to run a standard query or if you are filtering via some GUI, but time and date types can be combined together via simple addition. https://www.postgresql.org/docs/current/functions-datetime.html
The following code:
WITH q AS (
SELECT* FROM (VALUES
('11:29:10'::time,'03-18-2019'::date),
('11:29:10'::time,'03-18-2021'::date)
) t ("time","date")
)
SELECT * FROM q WHERE q.time+q.date > NOW()
Should only print the date in the future, which is what you are trying to achieve.
Hope this helps!

Postgres: query for a specific date on a timestampz returns no data while I can see the data in my postgres client

I'm very new at postgres and I've been googling this for about 1h before posting here.
Hopefully, you can help me with this probably trivial issue.
I have a database LTC that was created with this schema:
CREATE TABLE LTC (
id SERIAL PRIMARY KEY,
time timestamptz,
side CHAR(4),
price REAL,
v REAL,
n INT
);
I want to query to get all the data for time='2017-08-12T03:58:26.563Z' (ISO string from javascript). I know there are over a hundred lines of data in the database for that time, i see it in my postgres client.
Here is the query I'm doing:
select * from LTC where time = '2017-08-12T03:58:26.563Z'::timestamptz
Why am I getting no results?
Edit:
Still unsure why it wasn't working, but I wrote a work-around that does:
In JavaScript:
var date = new Date('2017-08-12T03:58:26.563Z').toISOString(); // actual time passed as parameter in my function, hard-coded for the example
var reg = new RegExp("([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})\.[0-9]*Z","gmi");
var start = date.replace(reg, function(match,year,month,day,hour,min,sec,ms) {
return year+'-'+month+'-'+day+'T'+hour+':'+min+':00.000Z';
});
var end = date.replace(reg, function(match,year,month,day,hour,min,sec,ms) {
var min = parseInt(min)+1;
if (min<=9) {
min = '0'+min;
}
return year+'-'+month+'-'+day+'T'+hour+':'+min+':00.000Z';
});
var query = "select * from LTC where time >= '"+start+"'::timestamptz and time < '"+end+"'::timestamptz"; // This works
Try using date_trunc('second',timestamp) on both to ensure that numerical precision is not what is throwing you off. There may be additional decimal places that are not being shown by your client and throwing off the equality.
The other possible solution is giving a range (between x and y) to avoid the numerical equality issue.
It would be easier for us to help if you can get an exact copy of the data being represented (using pg_dump perhaps, if you are familiar) so that we can test with the data that you are using.
The final thing you may want to check is explicitly stating the time zones that you are referencing. I generally use timestamp without time zone to avoid this issue, but auto-setting time zones to different values may be throwing you off as well. A good way to test is by selecting the two values, something like
select *, l.time = p.ts as test
from LTC l, (select '2017-08-12T03:58:26.563Z'::timestamptz as ts) p
;
EDIT:
I have built a test to try to reproduce your behavior:
CREATE TABLE LTC (
id serial
, time timestamptz
);
INSERT INTO LTC (time)
values ('2017-08-12T03:58:26.56312345'::timestamptz)
returning *;
select *
from LTC
where time = '2017-08-12T03:58:26.563Z'::timestamptz
;
select *, l.time = p.ts as test
from LTC l, (select '2017-08-12T03:58:26.563Z'::timestamptz as ts) p
;
What I get here is actually:
1;"2017-08-12 03:58:26.563123-04";"2017-08-11 23:58:26.563-04";f
Hopefully you can see what is happening - the '2017-08-12T03:58:26.563Z'::timestamptz is being interpreted as a UTC time and then converted to my time zone (UTC-04), so what is being compared is actually a different date altogether! In the future, showing this type of equality side-by-side is a great way to test that you are executing what you think you are (especially with dates / times where auto-conversion happens often).

Is it possible to combine the ANY and BETWEEN operator

I need to check if any value in a Postgres array is between a given range. Something like this:
SELECT * FROM my_table WHERE ANY(my_array) BETWEEN 50 AND 60;
I realize that I can't actually do this, since the ANY operator must always be on the right side of the expression. Does anyone know of a convenient work around for doing something like this?
You can use range types, specifically the range membership operator #>:
SELECT * FROM my_table WHERE '[50,60]'::int4range #> ANY(my_array);
If you need to pull the range bounds from a column or parameter, the range constructor function might suit you better:
SELECT * FROM my_table WHERE int4range(a,b,'[]') #> ANY(my_array);
if you need range
select array_agg(q.arr) arr
from (
select unnest(ARRAY[1,2,3,4,5,6,7,8,9,10]) arr
) q
where q.arr between 3 and 5

Conversion between timestamp to milliseconds in DB2

I have a column of datatype timestamp. Now I need to convert it to MiiliSeconds and put in another column. How can I do that.
the input is of the format 2011-10-04 13:54:50.455227 and the output needs to be 1317900719
There's a function called timestampdiff. Using it against January 1st 1970 would work otherwise but the function gives approximate results. If you want accuracy you will want to calculate the correct answer with something like
create function ts2millis(t timestamp)
returns bigint
return (
(
(bigint(year(t-1970))*bigint(31556926000))+
(bigint(month(t))*bigint(2629743000))+
(bigint(day(t))*bigint(86400000))+
(bigint(hour(t))*bigint(3600000))+
(bigint(minute(t))*bigint(60000))+
(bigint(second(t))*bigint(1000))+
(bigint(microsecond(t))/bigint(1000))
)
)
#
Your requested output is not miliseconds, but the equivalent to CLib localtime(), here's how to do it:
SELECT
86400*
(
DAYS(TIMESTAMP(v_timestamp))
-
DAYS(TIMESTAMP('1970-01-01-00:00:00'))
)
+
MIDNIGHT_SECONDS(timestamp(v_timestamp))
FROM
SYSIBM.SYSDUMMY1;
where v_timestamp is the variable or column to be calculated.

SUBSTR does not work with datatype "timestamp" in Postgres 8.3

I have a problem with the query below in postgres
SELECT u.username,l.description,l.ip,SUBSTRING(l.createdate,0,11) as createdate,l.action
FROM n_logs AS l LEFT JOIN n_users AS u ON u.id = l.userid
WHERE SUBSTRING(l.createdate,0,11) >= '2009-06-07'
AND SUBSTRING(l.createdate,0,11) <= '2009-07-07';
I always used the above query in an older version of postgres and it worked 100%. Now with the new version of posgres it gives me errors like below
**ERROR: function pg_catalog.substring(timestamp without time zone, integer, integer) does not exist
LINE 1: SELECT u.username,l.description,l.ip,SUBSTRING(l.createdate,...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.**
I assume it has something to do with datatypes, that the data is a time zone and that substring only support string datatypes, now my question is what can I do about my query so that my results would come up?
The explicit solution to your problem is to cast the datetime to string.
...,SUBSTRING(l.createdate::varchar,...
Now, this isn't at all a good practice to use the result to compare dates.
So, the good solution to your need is to change your query using the explicit datetime manipulation, comparison and formatting functions, like extract() and to_char()
You'd have to change your query to have a clause like
l.createdate::DATE >= '2009-06-07'::DATE
AND l.createdate::DATE < '2009-07-08'::DATE;
or one of the alternatives below (which you should really accept instead of this.)
SELECT u.username, l.description, l.ip,
CAST(l.createdate AS DATE) as createdate,
l.action
FROM n_logs AS l
LEFT JOIN
n_users AS u
ON u.id = l.userid
WHERE l.createdate >= '2009-06-07'::TIMESTAMP
AND l.createdate < '2009-07-07'::TIMESTAMP + '1 DAY'::INTERVAL
I'm not sure what you want to achieve, but basically "substring" on date datatypes is not really well defined, as it depends on external format of said data.
In most of the cases you should use extract() or to_char() functions.
Generally - for returning data you want to_char(), and for operations on it (including comparison) - extract(). There are some cases where this general rule does not apply, but these are usually signs of not really well thought data-structure.
Example:
# select to_char( now(), 'YYYY-MM-DD');
to_char
------------
2009-07-07
(1 row)
For extract let's write a simple query that will list all objects created after 8pm:
select * from objects where extract(hour from created) >= 20;
A variation on the Quassnoi's answer:
SELECT
u.username,
l.description,
l.ip,
CAST(l.createdate AS DATE) as createdate,
l.action
FROM
n_logs AS l
LEFT JOIN
n_users AS u
ON
(u.id = l.userid)
WHERE
l.createdate::DATE BETWEEN '2009-06-07'::DATE AND '2009-07-07'::DATE
If you use Postgresql, you will receive:
select('SUBSTRING(offer.date_closed, 0, 11)')
function substr(timestamp without time zone integer integer) does not
exist
Use:
select('SUBSTRING(CONCAT(offer.date_closed, \'\'), 0, 11)')