Date Range search - tSQL using nvarchar - tsql

Apologies for not using the correct type (date). Poor choice using nvarchar, but I cannot convert at this stage.
To the question:
I want to be able to search for data in a certain date range, e.g., 10.01.16 -> 19.02.16
However, it seems to bring back only the first two digits worth of data, so everything between 10 and 19 regardless of month and year.
My query is as follows:
SELECT ID, Day, Date FROM oneHr$
WHERE date >= CONVERT(NVARCHAR, '10.01.16', 4)
AND date <= CONVERT(NVARCHAR , '19.02.16', 4)
ORDER BY Date ASC
Any ideas? Help very much appreciated and thanks in advance.
This is what is being returned:
ID Day Date
--------------------
943 fri 10.02.15
746 mon 10.02.16
234 tue 10.03.15
835 fri 10.04.15
988 tue 10.05.15
487 wed 11.01.16
343 wed 11.02.15
874 mon 12.01.16
663 thu 12.01.15
198 tue 12.02.15
775 wed 13.01.16
993 thu 14.01.15
375 fri 15.03.15
337 wed 16.12.15
784 tue 17.11.15
777 mon 18.08.15
252 thu 19.01.16
664 wed 19.02.15
UPDATE
So, I've changed Date to be of type datetime and all looking good. However, I'm trying to define a range rather than hard code it and it isn't working. Any ideas?
set #date1 = '2016-01-01 00:00:00' -- Date1 (start range)
set #date2 = '2016-01-10 00:00:00' -- Date2 (end range)
/* Not Working */
select * from oneHr$
where Date >= #date1
and Date <= #date2
order by ID
/* Working */
select * from oneHr$
where Date >= '2016-01-01 00:00:00'
and Date <= '2016-01-10 00:00:00'
order by ID

Why not do something like this?
SELECT ID, Day, Date FROM oneHr$
WHERE CONVERT(DATE, date, 4) >= #Date1
AND CONVERT(DATE, date, 4) <= #Date2
ORDER BY Date ASC
Then you won't have to convert your inputs to nvarchar at all.

Related

Certain Range of Date in each Month

I'd like to have a range of day 20th - 25th in each month in BigQuery but i dont know what syntax should i use. For ex:
Jan 20 - 25
Feb 20 - 25
and so on
I only can think of creating a CTE for every month then union all those.
Consider below query.
SELECT DATE_ADD(month, INTERVAL day - 1 DAY) date_range,
FROM UNNEST(GENERATE_DATE_ARRAY('2022-01-01', '2022-03-01', INTERVAL 1 MONTH)) month,
UNNEST(GENERATE_ARRAY(20, 25)) day;
Query results
Below seem to be more simple than my original answer and you could adjust date range by specifying condition on WHERE clause.
SELECT *
FROM UNNEST(GENERATE_DATE_ARRAY('2022-01-01', '2022-12-31', INTERVAL 1 DAY)) date_range
WHERE EXTRACT(DAY FROM date_range) BETWEEN 21 AND 25
For the usecase that you commented,
WHERE EXTRACT(DAY FROM date_range) >= 21 OR EXTRACT(DAY FROM date_range) = 1

How to split and aggregate days into different month

db fiddle
run select *, return_date - pickup_date as total from order_history order by id; return the following result:
id pickup_date return_date date_ranges total
1 2020-03-01 2020-03-12 [2020-03-01,2020-04-01) 11
2 2020-03-01 2020-03-22 [2020-03-01,2020-04-01) 21
3 2020-03-11 2020-03-22 [2020-03-01,2020-04-01) 11
4 2020-02-11 2020-03-22 [2020-02-01,2020-03-01) 40
5 2020-01-01 2020-01-22 [2020-01-01,2020-02-01) 21
6 2020-01-01 2020-04-22 [2020-01-01,2020-02-01) 112
for example:
--id=6. total = 112. 112 = 22+ 31 + 29 + 30
--therefore toal should split: jan2020: 30, feb2020:29, march2020: 31, 2020apr:22.
first split then aggregate. aggregate based over range min(pickup_date), max(return_date) then tochar cast to 'YYYY-MM'; In this case the aggregate should group by 2020-01, 2020-02, 2020-03,2020-04.
but if pickup_date in the same month with return_date then compuate return_date - pickup_date then aggregate/sum the result, group by to_char(pickup_date,'YYYY-MM')
step-by-step demo: db<>fiddle
Not quite perfect, but a sketch:
SELECT
id,
ARRAY_AGG( -- 4
LEAST(return_date, gs + interval '1 month - 1 day') -- 2
- GREATEST(pickup_date, gs) -- 3
+ interval '1 day'
)
FROM order_history,
generate_series( -- 1
date_trunc('month', pickup_date),
date_trunc('month', return_date),
interval '1 month'
) gs
GROUP BY id
Generate a set of months that are included in the given date range
a) Calculate the last day of the month (first of a month + 1 month is first of the next month; minus 1 day is last of the current month). This is the max day for returning in this month. b) if it happened earlier, then take the earler day (LEAST())
Same for pickup day. Afterwards calculate the difference of the days kept in one month.
Aggregate the values for one month.
Open questions / Potential enhancements:
You said:
jan2020: 30, feb2020:29, march2020: 31, 2020apr:22.
Why is JAN given with 30 days? On the other hand you count APR 22 days (1st - 22nd). Following the logic, JAN should be 31, shouldn't it?
If you don't want to count the very first day, then you can change (3.) to
GREATEST(pickup_date + interval '1 day', gs)
There's a problem with day saving time in March (30 days, 23 hours instead of 31 days). This can be faced by some rounding, for example.

I need help in writing a subquery

I have a query like this to create date series:
Select month
From
(select to_char(created_date, 'Mon') as Month,
created_date::date as start_day,
(created_date::date + interval '1 month - 1 day ')::date as end_day
from generate_series(date '2021-01-26',
date '2022-04-26', interval '1 month') as g(created_date)) AS "thang"
And the table looks like this:
month
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Now I want to count the status from the KYC table.
So I try this:
Select
(Select month
From
(select to_char(created_date, 'Mon') as Month,
created_date::date as start_day,
(created_date::date + interval '1 month - 1 day ')::date as end_day
from generate_series(date '2021-01-26',
date '2022-04-26', interval '1 month') as g(created_date)) AS "thang"),
count(*) filter (where status = 4) as "KYC_Success"
From kyc
group by 1
I hope the result will be like this:
Month | KYC_Success
Jan | 234
Feb | 435
Mar | 546
Apr | 157
But it said
error: more than one row returned by a subquery used as an expression
What should I change in this query?
Let us assume that the table KYC has a timestamp column called created_date and the status column, and, that you want to count the success status per month - even if there was zero success items in a month.
SELECT thang.month
, count(CASE WHEN kyc.STATUS = 'success' THEN 1 END) AS successes
FROM (
SELECT to_char(created_date, 'Mon') AS Month
, created_date::DATE AS start_date
, (created_date::DATE + interval '1 month - 1 day ')::DATE AS end_date
FROM generate_series(DATE '2021-01-26', DATE '2022-04-26', interval '1 month') AS g(created_date)
) AS "thang"
LEFT JOIN kyc ON kyc.created_date>= thang.start_date
AND kyc.created_date < thang.end_date
GROUP BY thang.month;

Count days for each month between two dates - postgresql

I am trying to write a query which gives the number of days in each month between two specified dates.
Example:
date 1: 2018-01-01
date 2: 2018-05-23
Expected Output:
month days
2018-01-01, 31
2018-02-01, 28
2018-03-01, 31
2018-04-01, 30
2018-05-01, 23
Use generate_series and group by date_trunc
SELECT date_trunc('month',dt) AS month,
COUNT(*) as days
FROM generate_series( DATE '2018-01-01',DATE '2018-05-23',interval '1 DAY' )
as dt group by date_trunc('month',dt)
order by month;
Demo

How to generate 52 weeks from current date using Postgresql

How to generate 52 weeks from current date using postgresql
for example: from current_date(i.e todays date) to 52 weeks .
You can use generate_series which allows you to define range (start, stop) as well as the step interval like: generate_series(startDate, endDate, stepBy) so depending on output format you are after you could do something like:
SELECT generate_series(
current_date,
current_date + interval '52 weeks',
interval '1 week'
) weeks;
which would generate something like this:
weeks
2017-05-24 00:00:00
2017-05-31 00:00:00
2017-06-07 00:00:00
...