SQL Days before end of the month - sql

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

Related

Populate a row in SQL Server based on a condition (query optimization)

I am trying to find all the people who took a timeoff for previous months, I got most of it. But if nobody took a timeoff in the current month, I need to populate a row saying 0 to get my visuals right.
This is what my data looks like:
This is what I have for the visual:
select s.*, DATEPART(MONTH, startd) as timeoff_Mon,
DATEDIFF(day, startd, endd) as timeoff, getdate() as dat,
DATEPART(MONTH, GETDATE()) as Current_Mon from sample s;
You can see that Jack was the only employee who took time off in January for a day, and John in Feb for 4 days,
Now, in March, I have got the current month which is the last column in the image above from the current date.
Using this current month, is there a way to populate a row or hardcode a row to populate the time off column as 0??
Desired Output:
Here is the SQL Fiddle with the above-mentioned problem.
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=9e8fbb2ae8dcfec9cc5fdfa784782753
A simple option is to use union all to add the final record if there is no row that overlaps the current month in the table:
select
s.*,
month(startd) as timeoff_mon,
datediff(day, startd, endd) as timeoff,
getdate() as dat,
month(getdate()) as current_mon
from sample s
union all
select null, null, null, null, null, 0, getdate(), datepart(month, getdate())
where not exists (
select 1
from sample s
where
s.startd < dateadd(mm, datediff(mm, 0, getdate()) + 1, 0)
and s.endd >= dateadd(mm, datediff(mm, 0, getdate()), 0)
)
Demo on DB Fiddle:
Name | ID | STARTD | ENDD | timeoff_mon | timeoff | dat | current_mon
:--------- | ---: | :--------- | :--------- | ----------: | ------: | :---------------------- | ----------:
Jack | 5 | 2020-01-25 | 2020-01-26 | 1 | 1 | 2020-03-28 14:28:56.867 | 3
John | 6 | 2020-02-05 | 2020-02-09 | 2 | 4 | 2020-03-28 14:28:56.867 | 3
null | null | null | null | null | 0 | 2020-03-28 14:28:56.867 | 3

Get count for each time row appears in the range between 2 dates

I'am trying to calculate how many times a row "appears" a in the range between 2 dates and grouping them by the month.
So, let's say i have rows that look like this:
Name | StartDate | EndDate
-----------|-----------------|------------
Mathias | 2017-01-01 | 2017-04-01
Lucas | 2017-01-01 | 2017-04-01
i would like to get the output that shows how many records exists between the 2 dates in a query, so something like the following output:
Count | Year | Month
-----------|-----------------|------------
2 | 2017 | 1
2 | 2017 | 2
2 | 2017 | 3
2 | 2017 | 4
0 | 2017 | 5
0 | 2017 | 6
what i've tried is:
SELECT COUNT(*) as COUNT, YEAR(StartDate) YEAR, MONTH(StartDate) MONTH
FROM NamesTable
WHERE Start >= '2017-01-01 00:00:00'
AND Slut <= '2017-06-01 00:00:00'
group by YEAR(StartDate), MONTH(StartDate)
where this is giving me the expected output of:
Count | Year | Month
-----------|-----------------|------------
2 | 2017 | 1
0 | 2017 | 2
0 | 2017 | 3
0 | 2017 | 4
0 | 2017 | 5
0 | 2017 | 6
Because of grouping by the "start date", how can i count rows in the month for every one it expands across?
You need a table with the months range
Table allMonths
+---------+------------+------------+
| monthId | StartDate | EndDate |
+---------+------------+------------+
| 1 | 2017-01-01 | 2017-01-02 |
| 2 | 2017-01-02 | 2017-01-03 |
| 3 | 2017-01-03 | 2017-01-04 |
| 4 | 2017-01-04 | 2017-01-05 |
| 5 | 2017-01-05 | 2017-01-06 |
| 6 | 2017-01-06 | 2017-01-07 |
| 7 | 2017-01-07 | 2017-01-08 |
| 8 | 2017-01-08 | 2017-01-09 |
| 9 | 2017-01-09 | 2017-01-10 |
| 10 | 2017-01-10 | 2017-01-11 |
| 11 | 2017-01-11 | 2017-01-12 |
| 12 | 2017-01-12 | 2018-01-01 |
+---------+------------+------------+
Then your query is:
SELECT am.startDate, COUNT(y.Name)
FROM allMonths am
LEFT JOIN yourTable y
ON am.StartDate <= y.EndDate
AND am.EndDate >= y.StartDate
GROUP BY am.startDate
NOTE: You need to check border cases. Maybe you need change >= to > or change EndDate to the last day of the month.
So, what i ended up doing was something like Juan Carlos proposed, but instead of creating a table i made it up with CTE instead for a cleaner approach:
Declare #todate datetime, #fromdate datetime, #firstOfMonth datetime, #lastOfMonth datetime
Select
#fromdate='2017-01-11',
#todate='2017-12-21',
#firstOfMonth = DATEADD(month, DATEDIFF(month, 0, #fromdate), 0), ----YEAR(#fromdate) + MONTH(#fromdate) + DAY(1),
#lastOfMonth = DATEADD(month, ((YEAR(#fromdate) - 1900) * 12) + MONTH(#fromdate), -1)
;with MonthTable (MonthId, StartOfMonth, EndOfMonth) as
(
SELECT MONTH(#firstOfMonth) as MonthId, #firstOfMonth as StartOfMonth, #lastOfMonth as EndOfMonth
UNION ALL
SELECT MONTH(DATEADD(MONTH, 1, StartOfMonth)), DATEADD(MONTH, 1, StartOfMonth), DATEADD(MONTH, 1, EndOfMonth)
FROM MonthTable
WHERE StartOfMonth <= #todate
)
SELECT am.StartOfMonth, COUNT(y.Start) as count
FROM MonthTable am
left JOIN clientList y
ON y.Start <= am.StartOfMonth
AND y.End >= am.EndOfMonth
GROUP BY am.StartOfMonth

MSSQL query to get weekno from date, groupby weekno and sum sales

Is this possible in sql alone?
I have a table which contains the following rows
StoreID | Date | SalesItem |
1 | 2016-08-16 | Book |
2 | 2016-08-16 | Pen |
1 | 2016-08-15 | Pen |
1 | 2016-08-15 | Book |
The results I want would be
Store | Week | Sales
1 | 11 | 30
2 | 11 | 15
I'm using sql server 2008, the data set is much larger than the above example but that's basically what i would want to achieve in sql without processing in PHP afterwards.
What I have so far is
select [DATE], [store], count(store) as total, DATEPART(ww,DATE)
AS weeknum from [contracts] where [DATE] >= DATEADD(month, -12, GetDate())
group by [DATE], [store] order by [DATE] asc
Try the below code
SELECT Store,DATEPART(WW,Date),SUM(Sales) FROM TABLE1
GROUP BY Store, DATEPART(WW,Date)
As per edit of Question
SELECT Store,DATEPART(WW,Date),count(Sales) FROM TABLE1
GROUP BY Store, DATEPART(WW,Date)

sql - How to get the average of datediff in days between two dates of a single column

I figured this would be easy, but the only way I can get this figured out is a temp table. Basically I have 1 column called `myDate' which is a datetime column And what I want to know is the average difference in days for all these rows.
So Basically the results are this
1/1/2014
1/14/2014
1/20/2014
so basically i want to know the average is 9.5 days. 1/1 - 1/14 is 13 days and 14/20 is 6 days, so 19 / 2 is 9.5
my basic query is select myDate from myTable
The average is the maximum minus the minimum divided by one less than the number of days. So, you can get it as:
select datediff(day, min(myDate), max(myDate)) / cast(count(*) - 1 as float)
from temp;
If you wanted to be real careful, you might prevent the potential divide-by-zero error:
select (case when count(*) > 1
then datediff(day, min(myDate), max(myDate)) / cast(count(*) - 1 as float)
else 0
end)
from temp;
You don't need a temp table probably, but I'm not convinced the above method is true for all circumstances. Your requirement is to compare the date of one row to the date of the next row, but there is no indication that the 'next row date' is always greater than the previous date. If a pair of dates produce a negative result from datediff() the duration between those dates ignores the sign i.e. is the absolute value. e.g. if we calculate datediff(day,2014-01-02,2013-01-03) the result is -364, but in truth the duration is 364 because we should have flipped the date sequence in the datediff() function.
| MYDATE | NXTDATE | RAWDIFF | DAYDIFF |
|------------|------------|---------|---------|
| 2013-01-01 | 2014-01-02 | 366 | 366 |
| 2014-01-02 | 2013-01-03 | -364 | 364 |
| 2013-01-03 | 2014-01-27 | 389 | 389 |
| 2014-01-27 | 2013-01-28 | -364 | 364 |
| 2013-01-28 | 2014-01-29 | 366 | 366 |
| 2014-01-29 | 2014-06-30 | 152 | 152 |
| 2014-06-30 | (null) | (null) | (null) |
So, with dates possibly going backward and forward, measuring the average duration by a total span could be misleading.
| MIN_DT | MAX_DT | MAX_MIN_SPAN | SPAN_AVG | SUM_DAYDIFFS | COUNT | TRUE_AVG |
|------------|------------|--------------|----------|--------------|-------|----------|
| 2013-01-01 | 2014-06-30 | 545 | 90.83333 | 2001 | 6 | 333.5 |
queries used for this:
SELECT
MIN(mydate) min_dt
, MAX(mydate) max_dt
, DATEDIFF(DAY, MIN(mydate), MAX(mydate)) max_min_span
, DATEDIFF(DAY, MIN(mydate), MAX(mydate)) / (COUNT(daydiff) * 1.0) span_avg
, SUM(daydiff) sum_daydiffs
, COUNT(daydiff) count_daydiffs
, SUM(daydiff) / (COUNT(daydiff) * 1.0) true_avg
FROM (
SELECT
mydate
, ABS(DATEDIFF(DAY, mydate, LEAD(mydate) OVER (ORDER BY (SELECT 1)) )) AS daydiff
FROM mytable
) sq
;
SELECT
mydate
, lead(mydate) over(order by (select 1)) nxtdate
, DATEDIFF(DAY, mydate, LEAD(mydate) OVER (ORDER BY (SELECT 1)) ) AS rawdiff
, ABS(DATEDIFF(DAY, mydate, LEAD(mydate) OVER (ORDER BY (SELECT 1)) )) AS daydiff
FROM mytable
;
see: http://sqlfiddle.com/#!6/a7cdc/4

updates in month and day differences

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