I'm trying to list all days of the next week of given date
Example:
If today is 2019-09-24 then the result should be:
DAY_OF_WEEK
2019-09-24
2019-09-25
2019-09-26
2019-09-27
2019-09-28
2019-09-29
2019-09-30
This is the query I came up with and I wonder if there is more elegant way to achieve the same results:
SELECT date('now') AS DAY_OF_WEEK
UNION
SELECT date('now', '+1 day') AS DAY_OF_WEEK
UNION
SELECT date('now', '+2 day') AS DAY_OF_WEEK
UNION
SELECT date('now', '+3 day') AS DAY_OF_WEEK
UNION
SELECT date('now', '+4 day') AS DAY_OF_WEEK
UNION
SELECT date('now', '+5 day') AS DAY_OF_WEEK
UNION
SELECT date('now', '+6 day') AS DAY_OF_WEEK
Your code is correct.
If you want you can use a CTE which returns only the numbers from 0 to 6 and select from it the number of days to add to the current date:
WITH days as (
SELECT 0 AS day UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL
SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
)
SELECT date('now', '+' || day || ' day') AS DAY_OF_WEEK FROM days
See the demo.
Or with a RECURSIVE CTE:
WITH RECURSIVE days(day) AS (
SELECT 0
UNION ALL
SELECT day + 1 FROM days
LIMIT 7
)
SELECT date('now', '+' || day || ' day') AS DAY_OF_WEEK FROM days;
See the demo.
Results:
| DAY_OF_WEEK |
| ----------- |
| 2019-09-24 |
| 2019-09-25 |
| 2019-09-26 |
| 2019-09-27 |
| 2019-09-28 |
| 2019-09-29 |
| 2019-09-30 |
Related
The data table looks like the following:
ID DATE
1 2020-12-31 10:10:00
2 2020-12-31 20:30:00
3 2020-12-31 20:50:00
4 2021-01-02 17:10:00
5 2021-01-02 17:20:00
6 2021-01-02 17:30:00
7 2021-01-03 23:10:00
..
And I would like to query only the last entry per hour per day, and to have the resulte like:
ID DATE
1 2020-12-31 10:10:00
3 2020-12-31 20:50:00
6 2021-01-02 17:30:00
7 2021-01-03 23:10:00
..
I tried to look for hourly query and found the following
strftime('%H', " + DATE + ", '+1 hours')
However, not sure how to use it properly (e.g. with GROUP BY ? then how to ensure it takes the lastest entry of the hour), therefore, would be great to have some help here!
You can do it with ROW_NUMBER() window function:
SELECT ID, DATE
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY strftime('%Y%m%d%H', DATE) ORDER BY DATE DESC) rn
FROM tablename
)
WHERE rn = 1
ORDER BY ID
Instead of strftime('%Y%m%d%H', DATE) you could also use substr(DATE, 1, 13).
For versions of SQLite previous to 3.25.0 which do not support window functions you can do it with NOT EXISTS:
SELECT t1.*
FROM tablename t1
WHERE NOT EXISTS (
SELECT 1
FROM tablename t2
WHERE strftime('%Y%m%d%H', t2.DATE) = strftime('%Y%m%d%H', t1.DATE)
AND t2.DATE > t1.DATE
)
See the demo.
Results:
> ID | DATE
> -: | :------------------
> 1 | 2020-12-31 10:10:00
> 3 | 2020-12-31 20:50:00
> 6 | 2021-01-02 17:30:00
> 7 | 2021-01-03 23:10:00
I have datas in a table with schema:
Id INTEGER,
date DATETIME,
value REAL
id is primary key, and I have an index on date column to speed up querying values within a specific date range.
What should I do if I need N equal date ranges between specific start and end dates, and query aggregated datas for each date range?
For example:
Start date: 2015-01-01
End date: 2019-12-31
N: 5
In this case equal date intervals should be:
2015-01-01 ~ 2015-12-31
2016-01-01 ~ 2016-12-31
2017-01-01 ~ 2017-12-31
2018-01-01 ~ 2018-12-31
2019-01-01 ~ 2019-12-31
And the query should aggregate all values (AVG) in between those intervals, so I would like to have 5 total rows after the execution.
Maybe something with CTE?
There are 2 ways to do it.
They both use recursive ctes but return different results.
The 1st one with NTILE():
with
dates as (select '2015-01-01' mindate, '2019-12-31' maxdate),
alldates as (
select mindate date from dates
union all
select date(a.date, '1 day')
from alldates a cross join dates d
where a.date < d.maxdate
),
groups as (
select *, ntile(5) over (order by date) grp
from alldates
),
cte as (
select min(date) date1, max(date) date2
from groups
group by grp
)
select * from cte;
Results:
| date1 | date2 |
| ---------- | ---------- |
| 2015-01-01 | 2016-01-01 |
| 2016-01-02 | 2016-12-31 |
| 2017-01-01 | 2017-12-31 |
| 2018-01-01 | 2018-12-31 |
| 2019-01-01 | 2019-12-31 |
And the 2nd builds the groups with math:
with
dates as (select '2015-01-01' mindate, '2019-12-31' maxdate),
cte1 as (
select mindate date from dates
union all
select date(
c.date,
((strftime('%s', d.maxdate) - strftime('%s', d.mindate)) / 5) || ' second'
)
from cte1 c inner join dates d
on c.date < d.maxdate
),
cte2 as (
select date date1, lead(date) over (order by date) date2
from cte1
),
cte as (
select date1,
case
when date2 = (select maxdate from dates) then date2
else date(date2, '-1 day')
end date2
from cte2
where date2 is not null
)
select * from cte
Results:
| date1 | date2 |
| ---------- | ---------- |
| 2015-01-01 | 2015-12-31 |
| 2016-01-01 | 2016-12-30 |
| 2016-12-31 | 2017-12-30 |
| 2017-12-31 | 2018-12-30 |
| 2018-12-31 | 2019-12-31 |
In both cases you can get the averages by joining the table to the cte:
select c.date1, c.date2, avg(t.value) avg_value
from cte c inner join tablename t
on t.date between c.date1 and c.date2
group by c.date1, c.date2
I have a table with columns as id,date,name
id date name
1 2019-08-01 00:00:00 abc
1 2019-08-01 00:00:00 def
2 2019-08-01 00:00:00 pqr
1 2019-08-31 00:00:00 def
I want to get the count of id for given month.
The expected result for count of id for month 8 must be 3
SELECT strftime('%Y/%m/%d', date) as vdate,count(DISTINCT vdate,id) AS totalcount FROM cardtable WHERE date BETWEEN date('" + $rootScope.mydate + "', 'start of month') AND date('" + $rootScope.mydate + "','start of month','+1 month','-1 day') group by vdate
Basically i want to count if id and date both are distinct.for example if there are 2 entries on date 2019-08-01 with same id than it should give count as 1,if there 3 entries on date 2019-08-01 in which 2 entries are with id 1 and 3rd entry with 2 than it should count 2 and when there are 2 entries with id 1 and on different date lets say 1 entry on 2019-08-01 with id 1 and other on 2019-08-31 with id 1 than count id for month 8 must 2.How can i modify the above query.
Use a subquery which returns the distinct values that you want to count:
SELECT COUNT(*) AS totalcount
FROM (
SELECT DISTINCT strftime('%Y/%m/%d', date), id
FROM cardtable
WHERE date(date) BETWEEN
date('" + $rootScope.mydate + "', 'start of month')
AND
date('" + $rootScope.mydate + "','start of month','+1 month','-1 day')
)
See the demo.
Results:
| totalcount |
| ---------- |
| 3 |
I need compare value from 1 column with previous value from 2 column. For example, I have table:
id | create_date | end_date
1 | 2016-12-31 | 2017-01-25
2 | 2017-01-26 | 2017-05-21
3 | 2017-05-22 | 2017-08-26
4 | 2017-09-01 | 2017-09-02
I need to compare create_date for id = 2 with end_date for id = 1
and compare create_date for id = 3 with end_date for id = 2 etc.
Result: show me id which has create_date (id = n) <> end_date (id = n-1) + interval '1' day
Should I use lag() function? How I can compare it? Which function I should use and how?
Thank you
Teradata doesn't have lag/lead, but you can still get the same functionality:
select
id,
create_date,
end_date,
max(end_date) over (order by id between 1 preceding and 1 preceding) as prev_end_date
...
qualify
create_date <> prev_end_date + INTERVAL '1' day;
i have table which contains 4 rows of perticular emp.. and they have attendance of
like : formate(mm/dd/rrrr)
2 column name
atten date : | strtdate
1) 4/02/2016 | 1) 4/02/2016
2) 4/03/2016 | 2) 4/02/2016
3) 4/05/2016 | 3) 4/02/2016
4) 4/ 07/2016 | 4) 4/02/2016
5) 4/08/2016 | 5) 4/02/2016
here i need like this o/p column
fromdt | todate
1) 4/02/2016 | 4/03/2016
2) 4/03/2016 | 4/05/2016
3) 4/05/2016 | 4/05/2016
4) 4/07/2016 | 4/08/2016
You can do this by using the LEAD() analytic function:
with sample_data as (select 1 emp_id, to_date('02/04/2016', 'dd/mm/yyyy') atten_date, to_date('02/04/2016', 'dd/mm/yyyy') strtdate from dual union all
select 1 emp_id, to_date('03/04/2016', 'dd/mm/yyyy') atten_date, to_date('02/04/2016', 'dd/mm/yyyy') strtdate from dual union all
select 1 emp_id, to_date('05/04/2016', 'dd/mm/yyyy') atten_date, to_date('02/04/2016', 'dd/mm/yyyy') strtdate from dual union all
select 1 emp_id, to_date('07/04/2016', 'dd/mm/yyyy') atten_date, to_date('02/04/2016', 'dd/mm/yyyy') strtdate from dual union all
select 1 emp_id, to_date('08/04/2016', 'dd/mm/yyyy') atten_date, to_date('02/04/2016', 'dd/mm/yyyy') strtdate from dual)
-- end of subquery mimicking a table called "sample_data" with data in it. See SQL below:
select emp_id,
fromdt,
todate
from (select emp_id,
atten_date fromdt,
lead(atten_date) over (partition by emp_id order by atten_date) todate
from sample_data)
where todate is not null;
EMP_ID FROMDT TODATE
---------- ---------- ----------
1 04/02/2016 04/03/2016
1 04/03/2016 04/05/2016
1 04/05/2016 04/07/2016
1 04/07/2016 04/08/2016
if you need the row number displayed then you can use the ROW_NUMBER() analytic function to do that, if that information isn't already available as part of the source data.
If well understood your requirements this solution may work for you:
with sample_data as
(
select 10 emp_id, to_date('4/02/2016','mm/dd/yyyy') attendate, to_date('4/02/2016','mm/dd/yyyy') strtdate from dual union all
select 10 emp_id, to_date('4/03/2016','mm/dd/yyyy') attendate, to_date('4/02/2016','mm/dd/yyyy') strtdate from dual union all
select 10 emp_id, to_date('4/05/2016','mm/dd/yyyy') attendate, to_date('4/02/2016','mm/dd/yyyy') strtdate from dual union all
select 10 emp_id, to_date('4/07/2016','mm/dd/yyyy') attendate, to_date('4/02/2016','mm/dd/yyyy') strtdate from dual union all
select 10 emp_id, to_date('4/08/2016','mm/dd/yyyy') attendate, to_date('4/02/2016','mm/dd/yyyy') strtdate from dual
)
, marked_data as
(
select emp_id
, attendate
, strtdate
, row_number() over (partition by emp_id, strtdate order by attendate) as is_from
, row_number() over (partition by emp_id, strtdate order by attendate) - 1 as is_to
from sample_data
)
select md1.emp_id
, md1.attendate as fromdt
, md2.attendate as todt
, md1.strtdate
from marked_data md1
join marked_data md2
on md1.emp_id = md2.emp_id
and md1.strtdate = md2.strtdate
and md1.is_from = md2.is_to
You will have as a result:
EMP_ID FROMDT TODT STRTDATE
1 10 4/2/2016 4/3/2016 4/2/2016
2 10 4/3/2016 4/5/2016 4/2/2016
3 10 4/5/2016 4/7/2016 4/2/2016
4 10 4/7/2016 4/8/2016 4/2/2016