SQL query that can create a row for skipped months - sql

I have a table that I join to a calendar table, but I need to populate / create new row for each month between. I.e.
Date GIS CODE Running Total Open
2007-04-30 BEJOORDING, 6566, WESTERN AUSTRALIA 5
2007-09-30 BEJOORDING, 6566, WESTERN AUSTRALIA 6
I need some sort of query that can create end of month date rows between 2007-04-30 and 2007-09-30.
I will then need to fill down the blanks with the most recent fields so I will have a timeline for all end of month values.
I am assuming I will have to use some sort of CTE table but I am not the best at this / understand exactly how they work.
Any help will be greatly appreciated.

This CTE query will give you a table with all end-of-month values between the first and last ones in your table (I've assumed called log). You can then LEFT JOIN that to the table to create rows for all months in the timespan.
WITH CTE AS (
SELECT MIN(Date) AS [Date], MAX(Date) AS Max_Date FROM log
UNION ALL
SELECT EOMONTH(DATEADD(MONTH, 1, [Date])), Max_Date
FROM CTE
WHERE Date < Max_Date
)
SELECT Date
FROM CTE
Demo on SQLFiddle

Can be achieved with a RIGHT JOIN to a subquery against the calendar table using the EOMONTH() function

Related

How to Select dates when i sold nothing?

Assume i have a table of item_sold from 01-01-2020 to 01-01-2023 with columns product_id, product_name, quantity and date.
I want to get all the dates when i sold nothing.
I am using Postgresql, please help me in this problem.
I tried withclaue and many other things but they didn't worked.
You need some kind of calendar table containing all dates which you potentially want to report. Assuming the date range be the entire years of 2020 through 2023 inclusive, we can try the following left anti-join approach:
WITH dates AS (
SELECT ('2020-01-01'::date + s.a) AS dt
FROM generate_series(0, 365*4) AS s(a)
)
SELECT d.dt
FROM dates d
LEFT JOIN yourTable t
ON t.item_sold = d.dt
WHERE t.item_sold IS NULL
ORDER BY d.dt;

Return sums even if no data exist in given day

I have a table with amounts only on some days, e.g.:
[DATE] [AMT]
11/1/2017 $123
11/1/2017 $50
11/3/2017 $123
How can I query the data and get:
11/1/2017 $173
11/2/2017 $0
11/3/2017 $123
I tried like:
SELECT Day([Date]) AS [Day], Nz(Sum(AMT),0) AS [Day Total]
FROM mytable
WHERE Month([Date])=11
GROUP BY Day([Date]);
But still it doesn't return 0s for days without data, any ideas?
In Access, you can create a series of dates between the first and the last date, and then create an outer join to your summed data.
Here is how to create the date series:
Create a date table between two dates
You need a table with all the days, so you can fill the holes, lets call it allDays
Get a list of dates between two dates using a function
Then your query is:
SELECT a.[date], COALESCE(SUM([AMT]),0)
FROM allDates a
LEFT JOIN yourTable t
ON a.[date] = t.[date]
GROUP BY a.[date]
There are two simple solutions.
Join to a table with all dates in the month, as in Juan's answer.
Use this query by user RedFilter to generate the dates.
I suggest you try the following query:
SELECT DATE_FORMAT(date, "%b") AS month, SUM(total_price) as total
FROM table
WHERE date <= NOW()
and date >= Date_add(Now(),interval - 12 month)
GROUP BY DATE_FORMAT(date, "%m-%Y"))

Select the value for each first day of the month

I have the below table
I want to select the value of [UsedSpace(MB)] for each first day of the month.
For example 1/5/2015 the value of [UsedSpace(MB)] should be 10.
I tried the below query, but without success.
Select Cast(DATEADD(mm,DATEDIFF(mm,0,ExecuteTime),0) AS DATE) AS [Monthly],
[UsedSpace(MB)]
from tbl_Test
group by DATEADD(mm,DATEDIFF(mm,0,ExecuteTime),0), [UsedSpace(MB)]
Order by DATEADD(mm,DATEDIFF(mm,0,ExecuteTime),0)
Please any suggestions.
If you know that you will always have a single record for each date then you could limit the results in the WHERE statement. If there may be multiple records on the same date or no record on a date then you should use a MIN function.
SELECT
CAST(ExecuteTime as Date) AS Date,
UsedSpace
FROM tbl_Test
WHERE Day(ExecuteTime) = 1
For the sample data provided, you can simply make a where clause for the first day of the month. If you need a more generic solution, you need to get the lowest date for each month, and then join this with the original table.
WITH cte AS
(
SELECT MIN(ExecuteTime) AS Monthly
FROM tbl_Test
GROUP BY DATEADD(m, DATEDIFF(m, 0, ExecuteTime), 0)
)
SELECT t.ExecuteTime, t.[UsedSpace(MB)]
FROM tbl_Test AS t
JOIN cte AS m
ON t.ExecuteTime = m.Monthly
ORDER BY t.ExecuteTime

Spread a table in a date time interval

Hello everyone it's been some days that I use sql to make analysis and I meet all kinds of problems that I solves thanks to your forum.
Now I'd like to create a view that recuperates the interval of time and shows in detail the dates in this interval.
I have the following table:
And I want to create the view that displays the result:
For example in the player1 MyTable to play five days from 01/01/2012
to 05/01/2012. So the view displays 5 lines for player1 with the date 01/01/2012, 02/01/2012, 03/01/2012, 04/01/2012, 05/01/2012.
Thank you in advance for your help.
You have to create a common table expression that give you the date range ( i have created a date range of the current month but you can choice another range) :
WITH DateRange(dt) AS
(
SELECT CONVERT(datetime, '2012-01-01') dt
UNION ALL
SELECT DATEADD(dd,1,dt) dt FROM DateRange WHERE dt < CONVERT(datetime, '2012-01-31')
)
SELECT dates.dt AS DatePlaying, PlayerName
FROM MyTable t
JOIN DateRange dates ON dt BETWEEN t.BeginDate AND t.DateEnd
ORDER BY PlayerName, DatePlaying
Another approach to this is simply to create an enumeration table to add values to dates:
with enumt as (select row_number() over (order by (select NULL)) as seqnum
from mytable
)
select dateadd(d, e.seqnum, mt.DateBegin) as DatePlaying, mt.PlayerName
from MyTable mt join
enum e
on enumt.seqnum <= e.NumberOfPlayingDay
The only purpose of the "with" clause is to generate a sequence of integers starting at 1.

SQL to identify missing week

I have a database table with the following structure -
Week_End Sales
2009-11-01 43223.43
2009-11-08 4324.23
2009-11-15 64343.23
...
Week_End is a datetime column, and the date increments by 7 days with each new entry.
What I want is a SQL statement that will identify if there is a week missing in the sequence. So, if the table contained the following data -
Week_End Sales
2009-11-01 43223.43
2009-11-08 4324.23
2009-11-22 64343.73
...
The query would return 2009-11-15.
Is this possible? I am using SQL Server 2008, btw.
You've already accepted an answer so I guess you don't need this, but I was almost finished with it anyway and it has one advantage that the selected solution doesn't have: it doesn't require updating every year. Here it is:
SELECT T1.*
FROM Table1 T1
LEFT JOIN Table1 T2
ON T2.Week_End = DATEADD(week, 1, T1.Week_End)
WHERE T2.Week_End IS NULL
AND T1.Week_End <> (SELECT MAX(Week_End) FROM Table1)
It is based on Andemar's solution, but handles the changing year too, and doesn't require the existence of the Sales column.
Join the table on itself to search for consecutive rows:
select a.*
from YourTable a
left join YourTable b
on datepart(wk,b.Week_End) = datepart(wk,a.Week_End) + 1
-- No next week
where b.sales is null
-- Not the last week
and datepart(wk,a.Week_End) <> (
select datepart(wk,max(Week_End)) from YourTable
)
This should return any weeks without a next week.
Assuming your "week_end" dates are always going to be the Sundays of the week, you could try a CTE - a common table expression that lists out all the Sundays for 2009, and then do an outer join against your table.
All those rows missing from your table will have a NULL value for their "week_end" in the select:
;WITH Sundays2009 AS
(
SELECT CAST('20090104' AS DATETIME) AS Sunday
UNION ALL
SELECT
DATEADD(DAY, 7, cte.Sunday)
FROM
Sundays2009 cte
WHERE
DATEADD(DAY, 7, cte.Sunday) < '20100101'
)
SELECT
sun.Sunday 'Missing week end date'
FROM
Sundays2009 sun
LEFT OUTER JOIN
dbo.YourTable tbl ON sun.Sunday = tbl.week_end
WHERE
tbl.week_end IS NULL
I know this has already been answered, but can I suggest something really simple?
/* First make a list of weeks using a table of numbers (mine is dbo.nums(num), starting with 1) */
WITH AllWeeks AS (
SELECT DATEADD(week,num-1,w.FirstWeek) AS eachWeek
FROM
dbo.nums
JOIN
(SELECT MIN(week_end) AS FirstWeek, MAX(week_end) as LastWeek FROM yourTable) w
ON num <= DATEDIFF(week,FirstWeek,LastWeek)
)
/* Now just look for ones that don't exist in your table */
SELECT w.eachWeek AS MissingWeek
FROM AllWeeks w
WHERE NOT EXISTS (SELECT * FROM yourTable t WHERE t.week_end = w.eachWeek)
;
If you know the range you want to look over, you don't need to use the MIN/MAX subquery in the CTE.