SQLite How can i create in sqlite a Table with 365 Rows and how can i insert the dates? - sqlite

"How can i create in sqlite a Table with 365 Rows and how can i insert the dates?"
For example:
Table MyTable
id month date
1 jan 2021-01-01
2 jan 2021-01-02
3 jan 2021-01-03
.
.
.
365 dec 2021-12-31
How can i create this automatically ?
Thanks

You may reach this using recursive query
create table days as
with recursive qq as (
select 1 id, 'jan' month, '2021-01-01' date_col union all
select id + 1, substr('janfebmaraprmayjunjulaugsepoctnovdec', 1 + 3 *
strftime('%m', date(date_col, '+1 day')), -3), date(date_col, '+1 day')
from qq
where id <= 364
)
The monstrous line
substr('janfebmaraprmayjunjulaugsepoctnovdec', 1 + 3 * strftime('%m', date(date_col, '+1 day')), -3)
will cut the name of the month you need from the line based on the month number of the date. Ths one is needed because SQLIte seems to be not able to get month name from date.
There were suggestions of how one can get month names from date but it did not worked for me. Try those if you want
Here's an example on dbfiddle

Related

Get the MAX(value) using fiscal type years ie; 2016/2017, etc

My calendar year runs from 07-01-(of one year) to 06-30-(of the next year).
My SQLITE DB has a Timestamp column and it's data type is datetime and stores the timestamp as 2023-09-01 00:00:00.
What I'm trying to do is get the MAX date of the latest snowfall. For example, with my seasonal years beginning July-01 (earliest) and ending June 30 (latest), I want to find only the latest (MAX) date snowfall was recorded, regardless of the year, based on the month.
Say if out of five years (2017 to 2022) worth of data in the database and it snowed Mar 15, 2020. And there was no date greater than than this one in any year, then this would be the latest date regardless which year it fell.
I've been trying many variations of the below query. This query says it runs with no mistakes and returns "null" values. I'm using SQLITE DB Browser to write and test the query.
SELECT Timestamp, MAX(strftime('%m-%d-%Y', Timestamp)) AS lastDate,
snowDepth AS lastDepth FROM DiaryData
WHERE lastDepth <> 0 BETWEEN strftime('%Y-%m-%d', Timestamp,'start of year', '+7 months')
AND strftime('%Y-%m-%d', Timestamp, 'start of year', '+1 year', '+7 months', '- 1 day')
ORDER BY lastDate LIMIT 1
and this is what's in my test database:
Timestamp snowFalling snowLaying snowDepth
2021-11-10 00:00:00 0 0 7.2
2022-09-15 00:00:00 0 0 9.5
2022-12-01 00:00:00 1 0 2.15
2022-10-13 00:00:00 1 0 0.0
2022-05-19 00:00:00 0 0 8.82
2023-01-11 00:00:00 0 0 3.77
If it's running properly I should expect:
Timestamp
lastDate
lastDepth
2022-05-19 00:00:00
05-19-2022
8.82
What am I missing or is this not possible in SQLITE? Any help would be appreciative.
Use aggregation by fiscal year utilizing SQLite's feature of bare columns:
SELECT Timestamp,
strftime('%m-%d-%Y', MAX(Timestamp)) AS lastDate,
snowDepth AS lastDepth
FROM DiaryData
WHERE snowDepth <> 0
GROUP BY strftime('%Y', Timestamp, '+6 months');
See the demo.
I'd get season for each record first, snowfall date relative to record's season start date after this, and largest snowfall date relative to record's season start date finally:
with
data as (
select
*
, case
when cast(strftime('%m', "Timestamp") as int) <= 7
then strftime('%Y-%m-%d', "Timestamp", 'start of year', '-1 year', '+6 months')
else strftime('%Y-%m-%d', "Timestamp", 'start of year', '+6 months')
end as "Season start date"
from DiaryData
where 1==1
and "snowDepth" <> 0.0
)
, data2 as (
select
*
, julianday("Timestamp") - julianday("Season start date")
as "Showfall date relative to season start date"
from data
)
, data3 as (
select
"Timestamp"
, "snowFalling"
, "snowLaying"
, "snowDepth"
from data2
group by null
having max("Showfall date relative to season start date")
)
select
*
from data3
demo
You can use the ROW_NUMBER window function to address this problem, yet need to apply a subtle tweak. In order to account for fiscal years, you can partition on the year for timestamps slided 6 months further. In this way, ranges like [2021-01-01, 2021-12-31] will instead be slided to [2021-06-01, 2022-05-31].
WITH cte AS (
SELECT *, ROW_NUMBER() OVER(
PARTITION BY STRFTIME('%Y', DATE(Timestamp_, '+6 months'))
ORDER BY Timestamp_ DESC ) AS rn
FROM tab
)
SELECT Timestamp_,
STRFTIME('%d-%m-%Y', Timestamp_) AS lastDate,
snowDepth AS lastDepth
FROM cte
WHERE rn = 1
Check the demo here.

Select Rows by Consecutive Dates in SQLite

I have a table with data like below:
Log Table:
User Id
Login Date
1
2022-01-03
1
2022-01-04
1
2022-01-10
1
2022-01-11
1
2022-01-12
1
2022-01-23
1
2022-01-25
1
2022-01-26
1
2022-01-27
1
2022-01-28
What I'm trying to do is to create a query that return rows of the latest logins by consecutive dates with var_date as parameter.
If var_date is 2022-01-29, then the result is:
User Id
Login Date
1
2022-01-25
1
2022-01-26
1
2022-01-27
1
2022-01-28
If var_date is 2022-01-30, then no result is returned, since 2022-01-29 is not in the table.
If var_date is 2022-01-24, then the query will return row with 2022-01-23 as login date.
How am I to do this in SQLite?
Thank you.
This question is a variant of gaps and islands, with the islands being clusters of records per user with continuous dates. Here is one approach using analytic functions:
WITH cte AS (
SELECT *, CASE WHEN julianday(LoginDate) -
julianday(LAG(LoginDate) OVER (PARTITION BY UserID
ORDER BY LoginDate))
> 1 THEN 1 ELSE 0 END AS counter
FROM yourTable
),
cte2 AS (
SELECT *, SUM(counter) OVER (PARTITION BY UserID ORDER BY LoginDate) AS grp
FROM cte
)
SELECT UserID, LoginDate
FROM cte2 t1
WHERE LoginDate < '2022-01-29' AND
grp = (SELECT t2.grp FROM cte2 t2
WHERE t2.UserID = t1.UserID AND t2.LoginDate = '2022-01-28');
Demo
The two CTEs generate a pseudo date group for each cluster per user. The final query returns all records less than the target date for which the group value is the same as the immediately preceding date. Hence, for dates having no immediate record for a given user, the query will return empty set.
Use a recursive CTE:
WITH cte(UserId, LoginDate) AS (
SELECT :var_user_id, :var_date
UNION ALL
SELECT UserId, date(c.LoginDate, '-1 day')
FROM cte c
WHERE EXISTS (SELECT 1 FROM tablename t WHERE t.UserId = c.UserId AND t.LoginDate = date(c.LoginDate, '-1 day'))
)
SELECT *
FROM cte
WHERE LoginDate < (SELECT MAX(LoginDate) FROM cte);
Change :var_user_id and :var_date to the values that you want for the user's id and the date.
See the demo.

Not A valid month error while subtracting timestamps

I am trying to subtract timestamp values. It gives ORA-01843: NOT A VALID MONTH error.
Below query runs fine in SQL Devloper,
But while runtime it throws not a valid month error.
I am not able to find out. Can anybody modify this query.
Select substr(TO_TIMESTAMP(TO_CHAR(end_time,'DD-MM-YY HH12:MI:SS'))-(TO_TIMESTAMP(TO_CHAR(start_time,'DD-MM-YY HH12:MI:SS')),12,8))as Duration from Job_execution
If those datatypes are TIMESTAMP, then why don't you just subtract them?
SQL> create table job_execution
2 (id number,
3 start_time timestamp(6),
4 end_time timestamp(6));
Table created.
SQL> insert into job_execution (id, start_time, end_time) values
2 (1, to_timestamp('20.11.2019 10:30:00', 'dd.mm.yyyy hh24:mi:ss'),
3 to_timestamp('25.11.2019 14:00:00', 'dd.mm.yyyy hh24:mi:ss'));
1 row created.
SQL> select end_time - start_time diff from job_execution where id = 1;
DIFF
---------------------------------------------------------------------------
+000000005 03:30:00.000000
SQL>
"Not a valid month" can be result of timestamp values stored into VARCHAR2 columns where you think everything is entered correctly, but there are values such as 25.18.2019 (dd.mm.yyyy), as there's no 18th month in any year.
That's why I asked for the datatype.
[EDIT: how to format the result]
If you want a "nice" displayed result, then it requires some more typing. For example:
SQL> with difference as
2 (select end_time - start_Time as diff
3 from job_execution
4 where id = 1
5 )
6 select extract (day from diff) ||' '||
7 lpad(extract (hour from diff), 2, '0') ||':'||
8 lpad(extract (minute from diff), 2, '0') ||':'||
9 lpad(extract (second from diff), 2, '0') result
10 from difference;
RESULT
--------------------------------------------------------------
5 03:30:00
SQL>

T-SQL - Determine number of specific days between 2 dates based on sales

The Problem: Given a day of the week (1, 2, 3, 4, 5, 6, 7), a starting date and an ending date, compute the number of times the given day of the week appears between the starting and ending dates not inclusive of a date for which there were no sales.
Context:
Table "Ticket" has the following structure and sample content:
i_ticket_id c_items_total dt_create_time dt_close_time
----------------------------------------------------------------------------
1 8.50 '10/1/2012 10:23:00' '10/1/2012 11:05:05'
2 10.50 '10/1/2012 11:00:00' '10/1/2012 11:45:05'
3 8.50 '10/2/2012 08:00:00' '10/2/2012 09:25:05'
4 8.50 '10/4/2012 08:00:00' '10/4/2012 09:25:05'
5 7.50 '10/5/2012 13:22:23' '10/5/2012 14:33:27'
.
.
233 6.75 '10/31/2012 23:20:00' '10/31/2012 23:55:39'
Details
There may or may not be any tickets for one or more days during a month. (i.e. the place was closed that/those day/s)
Days in which the business is closed are not regular. There is no predictable pattern.
Based on Get number of weekdays (Sundays, Mondays, Tuesdays) between two dates SQL,
I have derived a query which returns the number of times a given day of the week occurs between the start date and the end date:
DECLARE #dtStart DATETIME = '10/1/2013 04:00:00'
DECLARE #dtEnd DATETIME = '11/1/2013 03:59:00'
DECLARE #day_number INTEGER = 1
DECLARE #numdays INTEGER
SET #numdays = (SELECT 1 + DATEDIFF(wk, #dtStart, #dtEnd)-
CASE WHEN DATEPART(weekday, #dtStart) #day_number THEN 1 ELSE 0 END -
CASE WHEN DATEPART(weekday, #dtEnd) <= #day_number THEN 1 ELSE 0 END)
Now I just need to filter this so that any zero-dollar days are not included in the count. Any help you can provide to add this filter based on the contents of the tickets table is greatly appreciated!
If I understand correctly, you can use a calendar table to count the number of days where the day of week is n and between the start and end and is a date that has ticket sales, which I guess is when the date exists in tickets and has the sum(c_items_total) > 0
WITH cal AS
(
SELECT cast('2012-01-01' AS DATE) dt, datepart(weekday, '2012-01-01') dow
UNION ALL
SELECT dateadd(day, 1, dt), datepart(weekday, dateadd(day, 1, dt))
FROM cal
WHERE dt < getdate()
)
SELECT COUNT(1)
FROM cal
WHERE dow = 5
AND dt BETWEEN '2012-04-01' AND '2012-12-31'
AND EXISTS (
SELECT 1
FROM tickets
WHERE cast(dt_create_time AS DATE) = dt
GROUP BY cast(dt_create_time AS DATE)
HAVING sum(c_items_total) > 0
)
OPTION (MAXRECURSION 0)
SQLFiddle

SQL Group Distinct Count

I have the following table
User ID Start Date End Date
-------------------------------------
John Doe Mar 11 2011 May 28 2011
Robret S Mar 21 2011 Jun 29 2011
Tina T Feb 01 2011 August 20 2011
I want to show how many people I have available for the past 6 months, even if the month has no people. How can this be possible. I know I have to do grouping and use distinct count.
Expected Output:
February = 1 Resource
March = 3 Resources
April = 3 Resources
May = 3 Resources
June = 2 Resources
July = 1 Resource
August = 1 Resource
With Calendar As
(
Select Cast('20110501' As DateTime) As [Date]
Union All
Select DateAdd(m,-1,[Date])
From Calendar
Where [Date] > DateAdd(m,-5,'20110501')
)
Select DateName(m, C.Date) + ' ' + Cast(Year(C.Date) As char(4))
, Case Count(*)
When 1 Then Cast(Count(*) As varchar(10)) + ' Resource'
Else Cast(Count(*) As varchar(10)) + ' Resources'
End
From Calendar As C
Left Join MyTable As T
On C.Date Between T.StartDate And T.EndDate
Group By C.Date
Results:
December 2010 | 1 Resource
January 2011 | 1 Resource
February 2011 | 1 Resource
March 2011 | 1 Resource
April 2011 | 3 Resources
May 2011 | 3 Resources
You will need the existing data records for the last 6 months, so that you can merge the two sets of data. You can generate the last 6 months in a CTE and do a left join with your data. That will allow you to show the last 6 months even if you have no data.
I don't think you can do what you want using a "simple" select statement (even using GROUPing etc.) The following is off the top of my head, so you'll have to experiment with it a little, and preferably read Joe Celko's excellent SQL for Smarties book.
You need to create a second table that contains all of your months (start/end dates). You only need one table for all types of similar queries, and it must contain all the months in the date ranges your interested in querying:
CREATE TABLE months (id, start DATE, end DATE);
INSERT INTO months (id, start, end)
values ( (1, 2011-01-01, 2011-01-31),
(2, 2011-02-01, 2011-02-28), ...);
You then LEFT OUTER JOIN from your user table to this month table. That will give you a row for each user for each month they were available, which you can GROUP as required:
SELECT months.id, COUNT(user.id)
FROM months LEFT OUTER JOIN users
ON user.start_date < months.end
AND user.end_date > months.start
GROUP BY months.id;
Hope that helps.
WITH resources AS (
SELECT
Date = DATEADD(month, v.number, [Start Date])
FROM atable t
INNER JOIN master.dbo.spt_values v ON v.type = 'P'
AND v.number BETWEEN 0 AND DATEDIFF(month, t.[Start Date], t.[End Date])
)
SELECT
Month = DATENAME(month, Date),
ResourceCount = CAST(COUNT(*) AS varchar(30)) +
CASE COUNT(*) WHEN 1 THEN ' Resource' ELSE ' Resources' END
FROM resources
WHERE Date > DATEADD(month, -6, DATEADD(day, -DAY(GETDATE()), GETDATE()))
GROUP BY YEAR(Date), MONTH(Date), DATENAME(month, Date)
ORDER BY YEAR(Date), MONTH(Date)

Resources