SQL Conditional Select Help (Amazon Redshift SQL) - sql

I currently have 2 queries that I am trying to merge into 1. Basically I want to pull previous days sales if it's Tuesday - Friday and the previous 3 days sales if it's Monday. My queries are below - is there a way to do a conditional select for those date based on the day of the week?
Monday's version
SELECT *
FROM A
WHEN DATE_TRUNC('day', timestamp) IN (CURRENT_DATE - 1, CURRENT_DATE - 2, CURRENT_DATE - 3)
AND DATE_PART(weekday, current_date) = 1
Tuesday - Friday version
SELECT *
FROM A
WHEN DATE_TRUNC('day', timestamp) = CURRENT_DATE - 1
AND DATE_PART(weekday, current_date) = 1

one solution is :
SELECT *
FROM A
WHERE DATE_TRUNC('date', timestamp) <= DATE_TRUNC('date', CURRENT_DATE)
AND DATE_TRUNC('date', timestamp) >= case when DATE_TRUNC('day of week',CURRENT_DATE) = 'Monday' then DATE_TRUNC('date', CURRENT_DATE - 3) else DATE_TRUNC('date',CURRENT_DATE) end

You can use `OR:
SELECT *
FROM A
WHERE (DATE_TRUNC('day', timestamp) IN (CURRENT_DATE - 1, CURRENT_DATE - 2, CURRENT_DATE - 3) AND
DATE_PART(weekday, current_date) = 1
) OR
(DATE_TRUNC('day', timestamp) = CURRENT_DATE - 1 AND
DATE_PART(weekday, current_date) <> 1
)
This can be slightly simplified to:
WHERE timestamp > CURRENT_DATE -
(CASE WHEN DATE_PART(weekday, current_date) = 1 INTERVAL '3 DAY'
ELSE INTERVAL '1 DAY'
END)
Note: This assumes that there are no future timestamps.

Related

get List of counts from table based on dates in sql

I have to fetch List of counts from table by department here is my table structure
empid empname department departmentId joinedon
i want to populate all the joined employee on today , yesterday and More than 2 days like [12,25,89] i.e
12* joined today
25 joined yesterday
81 joined all prior to yesterday(2+day)
* 0 if there isn't any entries for given date range.
You would use aggregation on a case expression:
select (case when joinedon::date = current_date then 'today'
when joinedon::date = current_date - interval '1 day' then 'yesterday'
when joinedon::date < current_date - interval '1 day' then 'older'
end) as grp,
count(*)
from t
group by grp;
In additional to #Gordon Linoff answer:
SELECT
days.day,
coalesce(t.cnt, 0) count
FROM (
SELECT * FROM (VALUES ('today'), ('yesterday'), ('older')) AS days (day)
)days
LEFT JOIN (
SELECT (CASE WHEN joinedon::date = current_date THEN 'today'
WHEN joinedon::date = current_date - interval '1 day' THEN 'yesterday'
WHEN joinedon::date < current_date - interval '1 day' THEN 'older'
end) as day,
count(*) cnt
FROM t
GROUP BY day
) t on t.day = days.day;
Test it here
You can use the group by as follows:
select department,
(case when joinedon::date = current_date then 'today'
when joinedon::date = current_date - interval '1 day' then 'yesterday'
when joinedon::date < current_date - interval '1 day' then 'More than 2 days'
end) as grp,
Coalesce(count(*),0)
from t
group by grp, department;

How to get generate_series() function in Redshift to result in just dates NOT date-time

Is there a way to remove the timestamp on the result set?
This is the query I am running in Redshift:
SELECT CURRENT_DATE - (i * interval '1 day') as dates
FROM generate_series(0,7) i
ORDER BY 1;
This is the result:
1
2020-10-21T00:00:00.000Z
2
2020-10-22T00:00:00.000Z
3
2020-10-23T00:00:00.000Z
4
2020-10-24T00:00:00.000Z
5
2020-10-25T00:00:00.000Z
6
2020-10-26T00:00:00.000Z
7
2020-10-27T00:00:00.000Z
8
2020-10-28T00:00:00.000Z
Just cast:
SELECT cast(current_date - i * interval '1 day' as date) as dates
FROM generate_series(0, 7) i
ORDER BY 1;
Or:
SELECT (current_date - i * interval '1 day')::date as dates
FROM generate_series(0, 7) i
ORDER BY 1;

invalid value "(202" for "yyyy" error in generate_series() with dates in PostgreSQL

I'm trying to generate dynamic dates based on the current date. I want to use generate_series() to populate dates between start and end dates (interval = 1 day).
If current date is before 10/1, start date is 10/1 in previous year
If current date is after 10/1, start date is 10/1 in the current year
end date is 9/30 in year 4. For example,
current date = 5/22/2019 -> start date = 10/1/2018, end date = 9/30/2021
current date = 11/1/2019 -> start date = 10/1/2019, end date = 9/30/2022
select generate_series(
to_date(cast(start_date as text), 'yyyy-mm-dd'),
to_date(concat(extract(year from to_date(cast(start_date as text), 'yyyy-mm-dd')+3),'-','09','-', 30), 'yyyy-mm-dd'),
'1 day'
)
from (
select case
when extract(month from current_date) <= 10 then concat(extract(year from current_date) -1,'-',10,'-', '01')
when extract(month from current_date) > 10 then concat(extract(year from current_date),'-',10,'-', '01')
end) as start_date
ERROR: invalid value "(202" for "yyyy"
DETAIL: Value must be an integer.
SQL state: 22007
It's complaining about year isn't integer. Which parts do I need to modify to run this query?
select case
when date_trunc('month', current_date) ::date < make_date(extract(year from current_date) ::int, 10, 1) then
generate_series(make_date((extract(year from current_date) - 1) ::int, 10, 1)
,make_date((extract(year from current_date) + 2) ::int, 10, 1) - 1
,'1 day') ::date
else
generate_series(make_date(extract(year from current_date) ::int, 10, 1)
,make_date((extract(year from current_date) + 3) ::int, 10, 1) - 1
,'1 day') ::date
end as dt;
Here In place of current_date you can use as below: current_date => '11/1/2019'::date or '05/22/2019'::date

How to find the last 'working' day of last month?

Is there a way to find the last working day of last month? I know I can get last day of last month with SELECT (date_trunc('month', now())::date - 1), but how do I get the last "weekday"?
I believe this does what you want:
select (date_trunc('month', current_date) + interval '1 month' -
(case extract(dow from date_trunc('month', current_date) + interval '1 month')
when 0 then 2
when 1 then 3
else 1
end) * interval '1 day'
) as last_weekday_in_month
Such requests often suggest the need for a calendar table.
Piggy-backing off of Gordon's answer, I think this is what you want:
SELECT (
date_trunc('month', current_date) - interval '1 day' -
(case extract(dow from date_trunc('month', current_date) - interval '1 day')
when 0 then 2
when 6 then 1
else 0
end) * interval '1 day'
)::date as last_weekday_in_last_month;
Assuming your weekends are 0 (Sunday) and 6 (Saturday). It uses OP's original logic to find the last date of the last month, then Gordon's CASE logic to subtract more days if the last date is 0 or 6.

Select count while count is greater than a specific number in postgres sql

I want to get last month records from table. I have tried:
SELECT count(*) as numberOfRows from Table where created_at > CURRENT_DATE - INTERVAL '1 months'
It's Ok, but I want to add some conditions:
If numberOfRows >= 10, do nothing (numberOfRows can be 20, 30, ...)
else if numberOfRows < 10, select from this table until numberOfRows
= 10 (last 2 months, 3 months, etc...).
How can I do that?
Thanks in advances!
WITH curr_month_cnt AS (
SELECT COUNT(*) AS cnt
FROM your_table
WHERE created_at > CURRENT_DATE - INTERVAL '1 months'
)
SELECT *
FROM your_table
WHERE created_at > CURRENT_DATE - INTERVAL '1 months'
UNION ALL
SELECT t.*
FROM
(
SELECT *
FROM your_table
WHERE
created_at <= CURRENT_DATE - INTERVAL '1 months' AND
(SELECT cnt FROM curr_month_cnt) < 10
ORDER BY created_at desc
LIMIT
GREATEST(0, 10 - (SELECT cnt FROM curr_month_cnt))
) t
This will return a maximum of 10 records, starting with the most recent month and going backwards. In the event that the latest month have not 10 records, then two and three months old data would be returned, in that order.
Based on your description, you would seem to want:
select greatest(10, count(*)) as numberOfRows
from Table
where created_at > CURRENT_DATE - INTERVAL '1 months';
This seems rather surprising. Perhaps you want:
select (case when sum( (CURRENT_DATE - INTERVAL '1 months' ) :: int) >= 10
then sum( (CURRENT_DATE - INTERVAL '1 months' ) :: int)
else least(10, count(*))
end) as numberOfRows
from Table
where created_at > CURRENT_DATE - INTERVAL '1 months';