Sql daily comparison by month - sql

I am writing a report for work which requires that I compare the amount of students dropped on a daily basis, what I mean is the report needs to show that on today the 5th of august X amounts of students dropped from the 1st to the 5th compared to X amount which dropped within the 1st to the 5th of July and so on for each Month of the year. Can anyone please help me by providing me with a query which I can use to have that info? thanks.

You want to compare the first number of days from a month. The following query gives you an example:
select yr, mon, count(*)
from (select extract(year from date) as yr, extract(month from date) as mon,
extract(day from date) as day
from t
) t
where day <= extract(day from now())
group by yr, mon
However, the exact syntax may depend on your database. For instance, the current date may be now(), getdate(), system_date or something else. Some databases don't support the extract, but most have a way to get the month and day of month.

Related

Specific Month-day select statement query

I would like to select from a table where the date falls within a specific time each year f.e:
select * from Customer where date >= August 15th and date <= December 20th
Since this will be for a report that runs every year, I do not want to hardcore the date as I will have to change it every year. I would like to have it dynamic to pick the date from August 15th to December 20th of the current year.
I have the below query where I can retrieve the Month and Date:
SELECT DATENAME(month, date) AS Month,DATENAME(day, date) AS Day from Customer
However, I am struggling to have this selection date range.
TIA
In SQL SERVER 2017
maybe this can help you:
SELECT * FROM Customer WHERE date BETWEEN
CONVERT(DATETIME,CONCAT(YEAR(GETDATE()),'08','15')) AND
CONVERT(DATETIME,CONCAT(YEAR(GETDATE()),'12','20'))
This add the current year to a concatenated date you want, then convert it all into datetime type..

How do I calculate daily averages for multi-year data in SQL?

I have a daily weather data SQL table with columns including date, type (temperature, rain, wind etc measurement) and value. The dataset spans 20 years of data.
How can I calculate daily averages for each day and measurement type, averaging values for the given date from data for all the 20 years in question? So e.g. I want to see the average temperature for 1 Jan (average of temperatures for 1 Jan 2020, 1 Jan 2019, etc)
Given there's a total of 750 million rows of data, should I create a materialised view of the calculations or what's the best way to cache the answers?
You need to extract the month and day from the date. The standard SQL function uses extract():
select extract(month from date) as month, extract(day from date) as day,
avg(temperature), avg(rain), . . .
from t
group by extract(month from date), extract(day from date);
Not all databases support these standard functions so you may need to use the functions specific to your (unspecified) database.
it would depend on which sql server you use, but in general, you should extract the day and the month from the date (on Microsoft SQL Server it is the DATEPART function) and then group by that and calculate the averages.
SELECT DATEPART(month, date_col) AS Month,
DATEPART(day, date_col) AS Day,
AVG(temp) AS Temp,
AVG(rain) AS Rain,
...
FROM table
GROUP BY DATEPART(month, date_col), DATEPART(day, date_col)
There is an extension to postgresql called timescaledb that makes it easier to query this type of data. Beware that it does make changes to the postgresql-database that requires changes to backup-routines. And if the current database is partitioned it will require a dump and restore.
A query can look like this:
-- By month
select
extract(year from created_at) as year,
extract(month from time_bucket('1 day', created_at)) as month,
min(temp) as temp,
from
readings
where
created_at > '2019-01-01' and created_at < '2020-01-01'
group by
year,
month
order by
year,
month;
750 Mio rows. You need an efficient index. Consider this function and the index based on it.
Assuming a table weather with a date column date:
CREATE FUNCTION f_mmdd(date) -- or timestamp input?
RETURNS int LANGUAGE sql IMMUTABLE PARALLEL SAFE AS
'SELECT (EXTRACT(month FROM $1) * 100 + EXTRACT(day FROM $1))::int';
CREATE INDEX weather_mmdd_idx ON weather(f_mmdd(date));
This index helps to quickly identify all rows for a particular day of the year.
The manual about EXTRACT.
The above expression proved fastest for various reasons. Just re-ran some performance tests in Postgres 13, and nothing changed.
Details in this closely related answer:
How do you do date math that ignores the year?
There is also EXTRACT(doy FROM date) to extract the day of the year (1–365/366), which is even faster. But, obviously, there is an off-by-one error for dates past Feb 29 in leap years in the Gregorian calendar.
Then the query for Jan 01 can be:
SELECT date_trunc('day', date) -- if it's a timestamp column
-- date -- if it's really a date column (which I find hard to believe)
, avg(temperature) AS avg_temperature
, avg(rain) AS avg_rain
-- , ...
FROM weather
WHERE f_mmdd(date) = f_mmdd('2000-01-01') -- or just 101 for Jan 01
GROUP BY 1;
The year in f_mmdd('2000-01-01') is arbitrary. Or just use the integer 101 for Jan 01.
You might be able to optimize further with multicolumn indexes for particular dimensions (temperature, rain, ...). But that depends on undisclosed details.
Sounds like the dataset isn't going to change. So a MATERIALIZED VIEW with readily computed aggregates per day might be a better alternative in the long run.
A word of warning: Computed averages are only correct if the measurements are spread out evenly across each day. Else, computed numbers are just averages of the given numbers, not actual average values for each day.

Generate custom start and end of months in SQL Server

I'm facing an issue while working with custom dates in T-SQL, we have a client that works with a different methodology of start and end of his month, instead of the default day 01 to start the month and ending in 31, 30 or 29, it's month start at day 26 and ends at 25 of the next month.
E.g., how usually is:
select sum(sales) as sales
from sales
where salesDate between '2020-09-01' and '2020-09-30'
-- or left(salesDate,7) = '2020-09'
Client custom month:
select sum(sales) as sales
from sales
where salesDate between '2020-08-26' and '2020-09-25' -- for setember
So, for this need, I have to calculate how many sales this client did from january until now, month per month, with this custom way... how can I do that?
Example of the query result I want to perform with this month determination:
This is a pretty awful situation. One method is to construct the first date of the month based on the rules:
select mon, sum(sales) as sales
from sales s cross apply
(values (case when day(salesdate) >= 26
then dateadd(month, 1, datefromparts(year(salesdate), month(salesdate), 1))
else datefromparts(year(salesdate), month(salesdate), 1)
) v(mon)
where v.mon >= '2020-01-01'
group by v.mon;
I would recommend adding the fiscal month column as a persisted computed column in the salesDate table so you can add an index and not have to worry about the computation.
Or, better yet, add a calendar table where you can look up the fiscal month for any (reasonable) date.

Break down date by month and the week of each month using Sql

What I need is break down the date by month and the week of that month. For example, for '2020-01-06' I want to see January, 1 week, or for '2020-01-13', I want to see January, 2nd week.
Here is the code that wrote:
.....
distinct t1.incidentid
,t1.status as [CW_Staus],
t1.title
,t1.createddatetime
,datename(MM,t1.createddatetime) as Month
,datename(ww,t1.createddatetime) as Week
.....
Now, what I see is this
However, with the start of each month, I want to restart the week count. for '2020-02-01', I want to see Feb, 1week.
What am I missing in the code?
Thank you
You could try taking the day of the month and divide by 7:
SELECT DISTINCT
t1.incidentid,
t1.status AS [CW_Staus],
t1.title,
t1.createddatetime,
DATENAME(MM, t1.createddatetime) AS Month,
1 + ((DATEPART(day, t1.createddatetime)-1) / 7) AS WeekOfMonth
...
Keep in mind that the above logic assumes that you actually want to reset the count of weeks for each month, at the start of each month. More typically, there are ISO standard ways of counting the week in the year. There are edge cases to be considered, as any given year may not have an whole number of weeks.

Timestamps and Intervals: NUMTOYMINTERVAL SYSTDATE CALCULATION SQL QUERY

I am working on a homework problem, I'm close but need some help with a data conversion I think. Or sysdate - start_date calculation
The question is:
Using the EX schema, write a SELECT statement that retrieves the date_id and start_date from the Date_Sample table (format below), followed by a column named Years_and_Months_Since_Start that uses an interval function to retrieve the number of years and months that have elapsed between the start_date and the sysdate. (Your values will vary based on the date you do this lab.) Display only the records with start dates having the month and day equal to Feb 28 (of any year).
DATE_ID START_DATE YEARS_AND_MONTHS_SINCE_START
2 Sunday , February 28, 1999 13-8
4 Monday , February 28, 2005 7-8
5 Tuesday , February 28, 2006 6-8
Our EX schema that refers to this question is simply a Date_Sample Table with two columns:
DATE_ID NUMBER NOT Null
START_DATE DATE
I Have written this code:
SELECT date_id, TO_CHAR(start_date, 'Day, MONTH DD, YYYY') AS start_date ,
NUMTOYMINTERVAL((SYSDATE - start_date), 'YEAR') AS years_and_months_since_start
FROM date_sample
WHERE TO_CHAR(start_date, 'MM/DD') = '02/28';
But my Years and months since start column is not working properly. It's getting very high numbers for years and months when the date calculated is from 1999-ish. ie, it should be 13-8 and I'm getting 5027-2 so I know it's not correct. I used NUMTOYMINTERVAL, which should be correct, but don't think the sysdate-start_date is working. Data Type for start_date is simply date. I tried ROUND but maybe need some help to get it right.
Something is wrong with my calculation and trying to figure out how to get the correct interval there. Not sure if I have provided enough information to everyone but I will let you know if I figure it out before you do.
It's a question from Murach's Oracle and SQL/PL book, chapter 17 if anyone else is trying to learn that chapter. Page 559.
you'll want MONTHS_BETWEEN in that numtoyminterval as the product of subtracting two date variables gives the answer in days which isn't usable to you and the reason its so high is you've told Oracle the answer was in years! Also use the fm modifier on the to_char to prevent excess whitespace.
select date_id,
to_char(start_date, 'fmDay, Month DD, YYYY') as start_date,
extract(year from numtoyminterval(months_between(trunc(sysdate), start_date), 'month') )
|| '-' ||
extract(month from numtoyminterval(months_between(trunc(sysdate), start_date), 'month') )
as years_and_months_since_start
from your_table
where to_char(start_date, 'MM/DD') = '02/28';
You can simplify the answer like this
SELECT date_id, start_date, numtoyminterval(months_between(sysdate, start_date), 'month') as "Years and Months Since Start"
FROM date_sample
WHERE EXTRACT (MONTH FROM start_date) = 2 AND EXTRACT (DAY FROM start_date) = 28;