Issue with generate_series in case sentence - postgresql

Recently my team have updated the version of our postgres server from 9.3 to 10.1
One of our procedures has a piece of code that right now is giving us some problems. This is just an example base on the original code:
SELECT
CASE
WHEN current_date = '2017-12-14' THEN generate_series(current_date , '2017-12-31'::DATE , '1 day')
WHEN current_date = '2017-12-15' THEN generate_series(current_date , '2017-12-31'::DATE , '1 day')
ELSE generate_series('2017-12-01'::DATE, '2017-12-31'::DATE, '1 day')
END AS workday
If I run this code in our previous server I've got the sequence. However in postgres 10.1 I'am getting this error message:
"set-returning functions are not allowed in CASE. "
Is there any problem with this version of postgres is this a bug, or is there another way to get the expected result

You need to move the set-returning functions out of the CASE statement so that it only returns a single row at a time. I would simplify your statement by making the CASE a subquery that you use the resulting column from:
SELECT generate_series(series_start_date::DATE, '2017-12-31'::DATE, '1 day') FROM
(
SELECT
CASE
WHEN current_date='2017-12-14' THEN current_date
WHEN current_date='2017-12-15' THEN current_date
ELSE '2017-12-01'
END AS series_start_date
) as temp_alias;
That query should give you what you want.
Putting 'temp_alias' in there is required, but isn't used.
Disclaimer: I tested this on Postgres 9.6, which is all I have available to test with at the moment. It should work with Postgres 10.1.

The use of set-returning functions in scalar contexts was a hack. They were completely rewritten by Andres Freund to a much better implementation.
Release note: Change the implementation of set-returning functions appearing in a query's SELECT list (Andres Freund).
As an altenative you can use LATERAL JOIN to join the logic of determining reference date to generate_series:
SELECT workday_series.*
FROM
(SELECT CASE CURRENT_DATE
WHEN '2017-12-14' THEN CURRENT_DATE
WHEN '2017-12-15' THEN CURRENT_DATE
ELSE '2017-12-01'
END) AS REF (date_reference)
JOIN LATERAL generate_series(ref.date_reference, '2017-12-31'::DATE, '1 day') AS workday_series(workday) ON TRUE;
SQL fiddle here.

Related

postgresql generating a list of dates between two dates fields

I would like to get the list of dates from two fields: start and end.
I found a case here: Show a list of dates between two dates?
But I would like to have a better solution without going through an intermediary table.
Here is the initial table:
Here is the result I would like to have:
Thank you
Use generate_series()
select t.id, t.name, t.g.dt::date as start_end
from the_table t
cross join generate_series(t.date_start, t.date_end, interval '1 day') as g(dt)
order by t.id, g.dt;

How to get the values from dummy table to variables?

(SELECT SUBSTRING(TO_CHAR(current_timestamp, 'yyyy-mm-dd hh12:mi:ss AM'),21,2)),
current_date ,
current_date - INTERVAL '1' DAYS,
to_char(current_date,'Day') into
vs_current_ampm,
vd_current_dt,
vd_prev_dt,
vl_day;
The forementioned query has a minor syntax error, i.e., an extra ) after 21,2.
I have changed that and the below query works fine.
SELECT
SUBSTRING(TO_CHAR(current_timestamp, 'yyyy-mm-dd hh12:mi:ss AM'),21,2),
current_date , current_date - INTERVAL '1' DAYS,
to_char(current_date,'Day');
If you would like to use the results in another place, you might need to use a cursor as I mentioned in the comments.
Check the documentation here.

Using BETWEEN or comparison operators in PostgreSQL

I'm having trouble with using the between operator in where clause. I have the following queries:
SELECT *
FROM table
WHERE timestamp_column BETWEEN (current_date - interval '1 day')::date
AND current_date => 500k rows
SELECT *
FROM table
WHERE timestamp_column >= (current_date - interval '1 day')::date => 1 mil rows
Does anyone have any idea why the result set is different? Shouldn't it be the same? I am trying to compare the number of rows from a database in PostgreSQL with data from Sybase ASE. The same 2 queries ran in Sybase give the same results. The expected result set is 1 milion rows. This should be the number of rows that I have between yesterday and today.
PostgreSQL v9.5, timestamp_column = timestamp without time zone
I tried using now(), current_timestamp but same result.
What am I missing here? If I didn't made myself clear let me know.

Loop postgresql Function through Date Range

I have a user defined function. This question shows how to loop through dates. Using this approach, I tried this query:
select myfun(a::date) from generate_series('2015-01-01'::date,'2016-01-27','1 day') s(a)
This doesn't quite work. What it returns is a single column of the form:
(10101, "Sample", "test")
(10102, "Sample2", "test2")
When in reality there should be three columns. It merges them into one.
I noticed that this is the same behavior that you get in a vanilla query such as select mytable when I omit the asterisk. The above query doesn't have an asterisk in it, but adding one causes an error.
Place the function call in the FROM clause:
select f.*
from
generate_series('2015-01-01'::date,'2016-01-27','1 day') s(a),
myfun(a::date) f;
or using more formal syntax:
select f.*
from generate_series('2015-01-01'::date,'2016-01-27','1 day') s(a)
cross join myfun(a::date) f;
This form of the FROM clause is known as lateral join.

How to execute SELECT DISTINCT ON query using SQLAlchemy

I have a requirement to display spend estimation for last 30 days. SpendEstimation is calculated multiple times a day. This can be achieved using simple SQL query:
SELECT DISTINCT ON (date) date(time) AS date, resource_id , time
FROM spend_estimation
WHERE
resource_id = '<id>'
and time > now() - interval '30 days'
ORDER BY date DESC, time DESC;
Unfortunately I can't seem to be able to do the same using SQLAlchemy. It always creates select distinct on all columns. Generated query does not contain distinct on.
query = session.query(
func.date(SpendEstimation.time).label('date'),
SpendEstimation.resource_id,
SpendEstimation.time
).distinct(
'date'
).order_by(
'date',
SpendEstimation.time
)
SELECT DISTINCT
date(time) AS date,
resource_id,
time
FROM spend
ORDER BY date, time
It is missing ON (date) bit. If I user query.group_by - then SQLAlchemy adds distinct on. Though I can't think of solution for given problem using group by.
Tried using function in distinct part and order by part as well.
query = session.query(
func.date(SpendEstimation.time).label('date'),
SpendEstimation.resource_id,
SpendEstimation.time
).distinct(
func.date(SpendEstimation.time).label('date')
).order_by(
func.date(SpendEstimation.time).label('date'),
SpendEstimation.time
)
Which resulted in this SQL:
SELECT DISTINCT
date(time) AS date,
resource_id,
time,
date(time) AS date # only difference
FROM spend
ORDER BY date, time
Which is still missing DISTINCT ON.
Your SqlAlchemy version might be the culprit.
Sqlalchemy with postgres. Try to get 'DISTINCT ON' instead of 'DISTINCT'
Links to this bug report:
https://bitbucket.org/zzzeek/sqlalchemy/issues/2142
A fix wasn't backported to 0.6, looks like it was fixed in 0.7.
Stupid question: have you tried distinct on SpendEstimation.date instead of 'date'?
EDIT: It just struck me that you're trying to use the named column from the SELECT. SQLAlchemy is not that smart. Try passing in the func expression into the distinct() call.