updates in month and day differences - sql

I have a table as shown below:
Note: the MAX last_orderdate is 20131015 and the format is yyyymmdd.
I would like to show the final result looks like below:
Is there any query to help me in this as I have 200000 plus records.
Thank you very much for spending your time to look at my question.

For DATEDIFF() function
Try this:
UPDATE A
SET A.monthDiff = DATEDIFF(mm, CONVERT(DATE, A.orderDate, 112), B.lastOrderDate),
A.dayDiff = DATEDIFF(dd, CONVERT(DATE, A.orderDate, 112), B.lastOrderDate)
FROM tableA A, (SELECT MAX(CONVERT(DATE, orderDate, 112)) lastOrderDate FROM tableA) B
Check the SQL FIDDLE DEMO
OUTPUT
| ID | ORDERDATE | MONTHDIFF | DAYDIFF |
|----|-----------|-----------|---------|
| 1 | 20130105 | 9 | 283 |
| 2 | 20130205 | 8 | 252 |
| 3 | 20130305 | 7 | 224 |
| 4 | 20130909 | 1 | 36 |
| 5 | 20131001 | 0 | 14 |
| 6 | 20131015 | 0 | 0 |

try something like this:
declare #a date
set #a='20130105'
declare #b date
set #b='20131015'
select datediff(d,#a,#b) as date_diff,datediff(m,#a,#b) as month_diff

Try this.
select DATEDIFF(DAYOFYEAR,'20131015','20131125').
DAYOFYEAR represents count of days. Depeneds on your requirement, you can change to see month,day or year difference using DATEDIFF

Related

Count of files received in the last 30 days split by each day

I am trying to get a count of the number of files my company has received in the past month split up by each day. The example below shows what I want the output to look like.
| Date- | | -Received- |
|--------| |------------|
| 2/1/20 | | - 16 - |
| 2/2/20 | | - 26 - |
| 2/3/20 | | - 14 - |
| 2/4/20 | | - 32 - |
The PK for my table is RecNo and the date variable is DateRecd.
Thank you in advance!
Do you just want aggregation and filtering?
select date, count(*)
from t
where date > convert(date, dateadd(day, -30, getdate()))
group by date
order by date;

Creating and populating row in a table for missing dates after each first valid entry

I have a dataset that represents number of views on individual files per day.
I would like to import this data into some visualization tool and show how many views a file received each day, beginning with the first valid date with an entry, in the form of something like a bar graph.
For example, I have a table like this:
+-----------+-----------+----------------+----------------+--------------+------------------+-----------------+------------------+
| Metadata1 | Metadata2 | Unique_Item_ID | Item_ID | Unique Views | Total View Count | Start_Date | End_Date |
+-----------+-----------+----------------+----------------+--------------+------------------+-----------------+------------------+
| Folder1 | Subf1 | {000dda83} | Document.docx | 6 | 11 | 11/27/2019 0:00 | 11/27/2019 23:59 |
| Folder2 | Sub2f | {004120b6} | Reporting.mp4 | 3 | 10 | 11/8/2019 0:00 | 11/8/2019 23:59 |
| Folder2 | Sub2f | {004120b6} | Reporting.mp4 | 8 | 13 | 11/20/2019 0:00 | 11/20/2019 23:59 |
| Folder2 | Sub2f | {004120b6} | Reporting.mp4 | 12 | 27 | 11/29/2019 0:00 | 11/29/2019 23:59 |
| Folder3 | Sub3f | {004f9957} | Case Study.pdf | 1 | 1 | 10/8/2019 0:00 | 10/8/2019 23:59 |
+-----------+-----------+----------------+----------------+--------------+------------------+-----------------+------------------+
From a query like:
SELECT
TOP 5 [Metadata1],
[Metadata2],
[Unique_Item_ID],
[Item_ID],
[Unique Views],
[Total View Count],
[Start_Date],
[End_Date]
FROM
DailyViewStats
How can I create a view that will create and populate rows with 0 view count for each Unique_Item_ID that does not exist, but only after the first occurrence of a valid existing row for each distinct Unique_Item_ID?
I know that I can use a partition function to identify the first valid row for each Unique_Item_ID, but I'm not sure how to leverage this. I tried using a cross join on all distinct Start_Dates in the table, to match up with all the unique items and their metadata, but I was unable to determine a WHERE statement that effectively removed any entry before the first valid one per Unique_Item_ID.
Using
ROW_NUMBER() OVER (PARTITION BY Unique_Item_ID ORDER BY Start_Date ASC) as RowNum
I believe I can use this to identify the minimum dates I need when RowNum = 1. But how do I use this?
If today were 11/29, for Document.docx, I want to see something like this:
+-----------+-----------+----------------+---------------+--------------+------------------+-----------------+------------------+
| Metadata1 | Metadata2 | Unique_Item_ID | Item_ID | Unique Views | Total View Count | Start_Date | End_Date |
+-----------+-----------+----------------+---------------+--------------+------------------+-----------------+------------------+
| Folder1 | Subf1 | {000dda83} | Document.docx | 6 | 11 | 11/27/2019 0:00 | 11/27/2019 23:59 |
| Folder1 | Subf1 | {000dda83} | Document.docx | 0 | 0 | 11/28/2019 0:00 | 11/28/2019 23:59 |
| Folder1 | Subf1 | {000dda83} | Document.docx | 0 | 0 | 11/29/2019 0:00 | 11/29/2019 23:59 |
+-----------+-----------+----------------+---------------+--------------+------------------+-----------------+------------------+
For each file existing in the table.
One direct way to do this is to employ a calendar table. In the example below the calendar is provided by a recursive CTE with a ~37K range of days. Once that is set up you want to overlay each of the unique Id's with each day. This is done below in the form of a cross join CTE, only including the keys. From the derived cross join table, simply LEFT JOIN the bulk of your data and the values will appear aligned with each day of the calendar. I took the liberty of simplifying your model below.
DECLARE #T TABLE( Unique_Item_ID NVARCHAR(50), Total_View_Count INT, DateViewed DATETIME)
INSERT #T VALUES
('000dda83',11, '11/27/2019'),
('004120b6',10, '11/8/2019'),
('004120b6',13, '11/20/2019')
DECLARE #StartDate DATETIME = '10/01/2019'
DECLARE #EndDate DATETIME = '01/01/2020'
;WITH OrderedDays as
(
SELECT CalendarDate = #StartDate
UNION ALL
SELECT CalendarDate = DATEADD(DAY, 1, CalendarDate)
FROM OrderedDays WHERE DATEADD (DAY, 1, CalendarDate) <= #EndDate
),
Calendar AS
(
SELECT
DayIndex = ROW_NUMBER() OVER(PARTITION BY 1 ORDER BY CalendarDate),
CalendarDate,
CalenderDayOfMonth = DATEPART(DAY, CalendarDate),
CalenderMonthOfYear = DATEPART(MONTH, CalendarDate),
CalendarYear = DATEPART(YEAR, CalendarDate),
CalenderWeekOfYear = DATEPART(WEEK, CalendarDate),
CalenderQuarterOfYear = DATEPART(QUARTER, CalendarDate),
CalenderDayOfYear = DATEPART(DAYOFYEAR, CalendarDate),
CalenderDayOfWeek = DATEPART(WEEKDAY, CalendarDate),
CalenderWeekday = DATENAME(WEEKDAY, CalendarDate)
FROM
OrderedDays
)
,CrossJoinData AS
(
SELECT Unique_Item_ID, CalendarDate
FROM
Calendar C
CROSS JOIN #T T
GROUP BY
Unique_Item_ID, CalendarDate
HAVING
MIN(T.DateViewed) <= C.CalendarDate
)
SELECT
CJ.Unique_Item_ID,
CJ.CalendarDate,
T.Total_View_Count
FROM
CrossJoinData CJ
LEFT OUTER JOIN #T T ON T.Unique_Item_ID = CJ.Unique_Item_ID AND T.DateViewed = CJ.CalendarDate
ORDER BY
CJ.Unique_Item_ID,
CJ.CalendarDate
OPTION (MAXRECURSION 0)

Count concurrent dates in user-input date range using SQL

The user will input a date range, and I want to output in SQL every date between and including that range in the number of concurrent uses of said equipment.
In this example, the user date range is 03/08/2016 to 03/09/2016, so you can see below I include anything on or between those dates (grouped by category, but I've simplified here by only using 'powerchair')
The table schema is as follows;
trans_date | trans_end_date | eq_category
17/03/2016 | 16/10/2016 | POWERCHAIR
08/08/2016 | 08/08/2016 | POWERCHAIR
12/08/2016 | 12/08/2016 | POWERCHAIR
17/08/2016 | 18/08/2016 | POWERCHAIR
22/08/2016 | 22/08/2016 | POWERCHAIR
26/08/2016 | 26/08/2016 | POWERCHAIR
02/09/2016 | 02/09/2016 | POWERCHAIR
And I would like to output;
date | concurrent_use
03-08-2016 | 1
04-08-2016 | 1
05-08-2016 | 1
06-08-2016 | 1
07-08-2016 | 1
08-08-2016 | 2
09-08-2016 | 1
10-08-2016 | 1
11-08-2016 | 1
12-08-2016 | 2
13-08-2016 | 1
14-08-2016 | 1
15-08-2016 | 1
16-08-2016 | 1
17-08-2016 | 2
18-08-2016 | 2
19-08-2016 | 1
20-08-2016 | 1
21-08-2016 | 1
22-08-2016 | 2
23-08-2016 | 1
24-08-2016 | 1
25-08-2016 | 1
26-08-2016 | 2
27-08-2016 | 1
28-08-2016 | 1
29-08-2016 | 1
30-08-2016 | 1
31-08-2016 | 1
01-09-2016 | 1
02-09-2016 | 2
03-09-2016 | 1
Anything 1 or 0, I can then filter out as there mustn't have been any equipment out concurrently that day.
I don't think this is a gaps/islands problem, but I'm drawing a blank trying to get this in an SQL statement.
Try like below. You need to generate dates using recursive cte. Then we need to count the no of occurrences of each date falling in range.
;WITH CTE
AS (SELECT CONVERT(DATE, '2016-08-03', 103) DATE1
UNION ALL
SELECT Dateadd(DAY, 1, DATE1) AS DATE1
FROM CTE
WHERE Dateadd(DD, 1, DATE1) <= '2016-09-03')
SELECT C.DATE1,
Count(1) OCCURENCES
FROM CTE C
JOIN #TABLE1 T
ON C.DATE1 BETWEEN [TRANS_DATE] AN [TRANS_END_DATE]
GROUP BY C.DATE1
You need a set of numbers or dates. So, if you want everything in that range:
with d as (
select cast('2016-08-03' as date) as d
union all
select dateadd(day, 1, d.d)
from d
where d < '2016-09-03'
)
select d.d, count(s.trans_date)
from d left join
schema s
on d.d between s.trans_date and s.trans_date_end
group by d.d;
I'm not sure if both the start and end dates are included in the range.

SQL Days before end of the month

i have got table with transactions, looking like:
+----+--------------+----------------+------+
| ID | OrderDate | DeliveryDate | EUR |
+----+--------------+----------------+------+
| 1 | 2015-02-21 | 2015-02-25 | 100 |
| 2 | 2015-03-01 | 2015-03-14 | 110 |
| 3 | 2015-03-01 | 2015-03-17 | 90 |
| 4 | 2015-03-10 | 2015-03-20 | 250 |
| 5 | 2015-03-31 | 2015-03-31 | 350 |
+----+--------------+----------------+------+
ANd I need to get sum of revenue and number of orders (COUNT of IDs) based on Days before the end of the month when order gets delivered.
SELECT datediff(day, OrderDate, CAST(DATEADD(month, DATEDIFF(month,0,getdate()+1,0)-1) as Date) as DBEOM, SUM(EUR) as Rev, COUNT(ID) as NumberOfOrders
FROM transactions
WHERE MONTH(DeliveryDate) = 3 AND YEAR(DeliveryDate) = 2015
GROUP BY datediff(day, OrderDate, CAST(DATEADD(month, DATEDIFF(month,0,getdate()+1,0)-1) as Date) as DBEOM
ORDER BY 1
The result in this case would be like:
+-----+-----+----------------+
|DBEOM| Rev | NumberOfOrders |
+-----+-----+----------------+
| 0 | 350 | 1 |
| 21 | 250 | 1 |
| 30 | 200 | 2 |
+-----+-----+----------------+
This is done in SQL 2008, so I can't simply use EOMONTH. I have tried, what is above, but i am getting
ERROR -
[Microsoft][ODBC SQL Server Driver][SQL Server]The datediff function
requires 3 argument(s).
Many thanks in advance for advice!
The easiest way I've found get the last day of the month with more primitive functions is to get the first day of the next month and then subtract a day.
I'm not a TSQL guy so this syntax likely won't be correct but you need something more like
DATEADD(day, DATEFROMPARTS(DATEPART(year, DATEADD(month,1,getdate()), DATEPART(month, DATEADD(month,1,getdate()), 1), -1)
Try:
SELECT datediff(day,
OrderDate,
dateadd(DAY,
-1,
dateadd(MONTH,
1,
dateadd(DAY,
1-day(DeliveryDate),
DeliveryDate
)
)
)
) as DBEOM, SUM(EUR) as Rev, COUNT(ID) as NumberOfOrders
FROM t
WHERE MONTH(DeliveryDate) = 3 AND YEAR(DeliveryDate) = 2015
GROUP BY datediff(day,
OrderDate,
dateadd(DAY,
-1,
dateadd(MONTH,
1,
dateadd(DAY,
1-day(DeliveryDate),
DeliveryDate
)
)
)
)
ORDER BY 1
sqlfiddle.com

SQL not delivering expected result with RIGHT JOIN

I have been working on this query for some time now, and reading right join question after right join question here on SO, but I cannot figure this one out.
I have the following Query:
DECLARE #ExpectedDateSample VARCHAR(10)
DECLARE #Date datetime
DECLARE #DaysInMonth INT
DECLARE #i INT
--GIVE VALUES
SET #ExpectedDateSample = SUBSTRING(CONVERT(VARCHAR, DATEADD(MONTH, +0, GETDATE()), 112),5,2)+'/'+CONVERT(VARCHAR(4), DATEPART(YEAR, GETDATE()))
SET #Date = Getdate()
SELECT #DaysInMonth = datepart(dd,dateadd(dd,-1,dateadd(mm,1,cast(cast(year(#Date) as varchar)+'-'+cast(month(#Date) as varchar)+'-01' as datetime))))
SET #i = 1
--MAKE TEMP TABLE
CREATE TABLE #TempDays
(
[days] VARCHAR(50)
)
WHILE #i <= #DaysInMonth
BEGIN
INSERT INTO #TempDays
VALUES(#i)
SET #i = #i + 1
END
SELECT DATEPART(DD, CONVERT(DATE, a.budg_tempDODate1, 103)) ExpectedDate, SUM(a.budg_do1_total) ExpectedAmount
FROM CRM.dbo.budget a
RIGHT JOIN #TempDays on DATEPART(DD, CONVERT(DATE, a.budg_tempDODate1, 103)) = #TempDays.days
WHERE DATEPART(MONTH, a.budg_tempDODate1) = DATEPART(MONTH, GetDate()) AND DATEPART(YEAR, a.budg_tempDODate1) = DATEPART(YEAR, GetDate())
GROUP BY a.budg_tempDODate1
--DROP TABLE TO ALLOW CREATION AGAIN
DROP TABLE #TempDays
In my Budget table I have a few days out of the month missing, but that is why I create a Temp table to count all the days of the month. And then RIGHT join to that Temp table.
I am trying to calculate how much cash is expected on each day of the month. If the day does not exist in my budget table, DO NOT leave it out completely, but rather display 0 is expected.
What I am currently getting
+------+---------------+
| DAYS | AMOUNT |
+------+---------------+
| 1 | 34627.000000 |
| 2 | 72474.000000 |
| 3 | 27084.000000 |
| 4 | 9268.000000 |
| 5 | 32304.000000 |
| 6 | 23261.000000 |
| 7 | 5614.000000 |
| 9 | 3464.000000 |
| 10 | 20046.000000 |
| 12 | 7449.000000 |
| 13 | 265163.000000 |
| 14 | 24210.000000 |
| 15 | 68848.000000 |
| 16 | 31702.000000 |
| 17 | 2500.000000 |
| 19 | 2914.000000 |
| 20 | 238406.000000 |
| 21 | 15642.000000 |
| 22 | 2514.000000 |
| 23 | 46521.000000 |
| 24 | 34093.000000 |
| 25 | 899081.000000 |
| 26 | 204085.000000 |
| 27 | 316341.000000 |
| 28 | 48826.000000 |
| 29 | 2657.000000 |
| 30 | 440401.000000 |
+------+---------------+
What I was Expecting:
+------+---------------+
| DAYS | AMOUNT |
+------+---------------+
| 1 | 34627.000000 |
| 2 | 72474.000000 |
| 3 | 27084.000000 |
| 4 | 9268.000000 |
| 5 | 32304.000000 |
| 6 | 23261.000000 |
| 7 | 5614.000000 |
| 8 | NULL |
| 9 | 3464.000000 |
| 10 | 20046.000000 |
| 11 | NULL |
| 12 | 7449.000000 |
| 13 | 265163.000000 |
| 14 | 24210.000000 |
| 15 | 68848.000000 |
| 16 | 31702.000000 |
| 17 | 2500.000000 |
| 18 | NULL |
| 19 | 2914.000000 |
| 20 | 238406.000000 |
| 21 | 15642.000000 |
| 22 | 2514.000000 |
| 23 | 46521.000000 |
| 24 | 34093.000000 |
| 25 | 899081.000000 |
| 26 | 204085.000000 |
| 27 | 316341.000000 |
| 28 | 48826.000000 |
| 29 | 2657.000000 |
| 30 | 440401.000000 |
+------+---------------+
As you can see, the expected result still shows the days Im not expecting any value.
Can Anybody notice anything immediately wrong with my query... Any help and tips would be greatly appreciated.
I'm using SQL server 2008
Thanks!
Mike
Change your where clause to part of the join, and display the day value from #tempdays, not the data table
SELECT
#TempDays.days ExpectedDate, SUM(a.budg_do1_total) ExpectedAmount
FROM CRM.dbo.budget a
RIGHT JOIN #TempDays on
DATEPART(DD, CONVERT(DATE, a.budg_tempDODate1, 103)) = #TempDays.days
AND DATEPART(MONTH, a.budg_tempDODate1) = DATEPART(MONTH, GetDate())
AND DATEPART(YEAR, a.budg_tempDODate1) = DATEPART(YEAR, GetDate())
GROUP BY #TempDays.days
The problem is your Where Clause -
WHERE DATEPART(MONTH, a.budg_tempDODate1) = DATEPART(MONTH, GetDate()) AND DATEPART(YEAR, a.budg_tempDODate1) = DATEPART(YEAR, GetDate())
The where clause and the group by clauses are applied on the table with less data.
So, the result set is getting confined to the table with less data ignoring the join clauses.
I have rewritten this and tested it.
declare #budget table
(
budg_tempDODate1 datetime,
budg_do1_total float
)
insert into #budget(budg_tempDODate1, budg_do1_total)
select '2014-06-01', 25
union select '2014-06-01', 23
union select '2014-06-02', 23
union select '2014-06-02', 23
union select '2014-06-02', 23
union select '2014-06-03', 23
union select '2014-06-04', 23
union select '2014-06-05', 23
union select '2014-06-05', 23
union select '2014-06-05', 23
union select '2014-06-06', 23
union select '2014-06-07', 23
union select '2014-06-08', 23
union select '2014-06-09', 23
union select '2014-06-10', 23
DECLARE #ExpectedDateSample VARCHAR(10)
DECLARE #Date datetime
DECLARE #DaysInMonth INT
DECLARE #i INT
--GIVE VALUES
SET #ExpectedDateSample = SUBSTRING(CONVERT(VARCHAR, DATEADD(MONTH, +0, GETDATE()), 112),5,2)+'/'+CONVERT(VARCHAR(4), DATEPART(YEAR, GETDATE()))
SET #Date = Getdate()
SELECT #DaysInMonth = datepart(dd,dateadd(dd,-1,dateadd(mm,1,cast(cast(year(#Date) as varchar)+'-'+cast(month(#Date) as varchar)+'-01' as datetime))))
SET #i = 1
--MAKE TEMP TABLE
CREATE TABLE #TempDays
(
[days] int
)
WHILE #i <= #DaysInMonth
BEGIN
INSERT INTO #TempDays
VALUES(#i)
SET #i = #i + 1
END
--select * from #TempDays
SELECT
td.days as ExpectedDate,
SUM(isnull(a.budg_do1_total, 0)) ExpectedAmount
FROM
--CRM.dbo.budget a
#TempDays td
left outer JOIN #budget a on
DATEPART(MONTH, a.budg_tempDODate1) = DATEPART(MONTH, GetDate())
AND DATEPART(YEAR, a.budg_tempDODate1) = DATEPART(YEAR, GetDate())
AND DATEPART(DD, CONVERT(DATE, a.budg_tempDODate1, 103)) = td.days
GROUP BY
--a.budg_tempDODate1
td.days
--DROP TABLE TO ALLOW CREATION AGAIN
DROP TABLE #TempDays
Here is the sql fiddle