Query not displaying the week value as 0 - sql

SELECT datediff(week, dateadd(week, datediff(week, 0, dateadd(month, datediff(month, 0, EntryDate), 0)), 0), EntryDate - 1) + 1 as week,
count(UserID) as balance
FROM table_points
where right(convert(varchar, EntryDate, 106), 8)='Mar 2015'
GROUP BY datediff(week, dateadd(week, datediff(week, 0, dateadd(month, datediff(month, 0, EntryDate), 0)), 0), EntryDate - 1) + 1
When i execute this query i get result for 4th and 5th week values but not for others week. Like
week balance
4 80
5 100
In first 3 weeeks there is no values in database so it will not showing the values . Can any one bring 0 value for 1st , 2nd and 3rd week.
I want result as
week balance
1 0
2 0
3 0
4 80
5 100
can any one help me out.

Create a calendar/date table, including all possible dates/weeks, and from there left join the table_points table.
If no data is present in table_points, it will return 0 for those weeks.
If no dates are present in a table, it's impossible to select these and get a zero.
Example:
SELECT d.week, count(t.UserID)
FROM dates d left join table_points t on
d.date = t.EntryDate
where right(convert(varchar, d.date, 106), 8)='Mar 2015'
group by d.week
A date table can be very useful for many applications and could be filled like:
date week year month WeekOfMonth DayOfWeek Day Month
2015-03-01 18 2015 3 1 5 Friday March
2015-03-02 18 2015 3 1 6 Friday March
2015-03-03 18 2015 3 1 7 Sunday March
2015-03-04 19 2015 3 2 1 Monday March

This works like PSVSupporter's solution but uses a CTE to get a date list instead of using another table:
;WITH Dates AS (
SELECT
[Date] = CONVERT(DATETIME,'03/01/2015')
UNION ALL SELECT
[Date] = DATEADD(DAY, 1, [Date])
FROM
Dates
WHERE
Date < '03/31/2015'
)
SELECT
datediff(week, dateadd(week, datediff(week, 0, dateadd(month, datediff(month, 0, ds.Date), 0)), 0), ds.Date - 1) + 1 as week,
count(tp.UserID) as balance
FROM Dates ds
left join table_points tp on tp.EntryDate = ds.Date
WHERE right(convert(varchar, ds.Date, 106), 8)='Mar 2015'
GROUP BY datediff(week, dateadd(week, datediff(week, 0, dateadd(month, datediff(month, 0, ds.Date), 0)), 0), ds.Date - 1) + 1
I took CTE from https://stackoverflow.com/a/7824893/3309109

Related

Count individual days worked in a month excluding holidays and sick leaves

I need to get for each user how many days of the week they worked (in a month). I have a table storing the date range in which they didn't work (sick leave) and a tally table storing workdays.
ausentismoT stores the non worked days as date ranges, the table looks like this
user ini fin --ini = start date | fin = end date
---------------------------
john 06/05/2019 06/05/2019
john 13/05/2019 13/05/2019
john 20/05/2019 24/05/2019
Tally table, storing every day of the month and marking their status as holiday:
IDCal fechaValor numDiaSemana nomDia nomMes semanaAno diaJuliano feriadoBancario feriadoNombre
---------------------------------------------------------------------------------------------
20190502 2019-05-02 00:00:00.000 4 Jueves Mayo 18 122 0 NULL
20190503 2019-05-03 00:00:00.000 5 Viernes Mayo 18 123 0 NULL
20190504 2019-05-04 00:00:00.000 6 Sábado Mayo 18 124 1 Weekend
My code, which I know the logic is wrong, I ""try"" to exclude both holidays and non worked days but the results are 0 in all columns:
SELECT T.RUT_DV,
T.USER,
DIAS_HAB_MES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C WHERE feriadoBancario=0 AND CONVERT(NVARCHAR(6),C.fechaValor,112) = CONVERT(NVARCHAR(6),GETDATE(),112)),
LUNES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C
WHERE numDiaSemana=1 AND feriadoBancario = 0 AND (FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI) AND FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN),
MARTES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C
WHERE numDiaSemana=2 AND feriadoBancario = 0 AND (FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI) AND FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN),
MIERCOLES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C
WHERE numDiaSemana=3 AND feriadoBancario = 0 AND (FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI) AND FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN),
JUEVES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C
WHERE numDiaSemana=4 AND feriadoBancario = 0 AND (FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI) AND FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN),
VIERNES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C
WHERE numDiaSemana=5 AND feriadoBancario = 0 AND (FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI) AND FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN)
FROM dotacionAD T -- BASE TABLE
LEFT JOIN ausentismoT T2 ON T.RUT_DV = REPLACE(T2.RUT_DV,'.','')
Results are this:
NOM_COL DIAS_HAB_MES LUNES MARTES MIERCOLES JUEVES VIERNES
-------------------------------------------------------------------
JOHN 20 0 0 0 0 0
For the same case it should display this:
NOM_COL DIAS_HAB_MES LUNES MARTES MIERCOLES JUEVES VIERNES
-------------------------------------------------------------------
JOHN 20 1 3 3 4 4
I believe you have done an error when copy-pasting the dateadd/datediff a second time.
At the time I write this answer, my local getdate() would return 6 June 2019.
Your first condition is:
FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI
This formula truncates the current date to month level, and also substracts one month. Thus, if I run it now, I will get 1 May 2019. All your ini are after this, so OK.
Your second condition is:
FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN
This formula truncates the current date to month level, does not substract a month, but in the end it substracts a day. Thus, if I run it now, I will get 2 June 2019. None of your fin are later than that, and that's why you get zero everywhere.
Now I'm not sure what you intend to see, but two BETWEENs seem strange. If you want the last 2 months that are in ausentismoT, I would write it like this:
FECHAVALOR >= DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0)
AND
FECHAVALOR BETWEEN T2.INI and T2.FIN
This should help get you started. It's not entirely clear if you've provided all the information though.
select
t.user, count(*) as dia_hab_mes,
count(case when numDiaSemana = 1 then 1 end) as lunes,
...
from
users as u cross join calendar as c
left outer join ausentismoT as a
on c.<date> between a.ini and a.fin and a.user = t.user
where c.<date> ... /* filter dates for desired month */
and feriadoBancario = 0
group by u.user;

SQL Middle of the Month

I know you can set #Date to 01/01/2001 as beginning of the month.
and then call dates that are first of every month, for example:
01/01/2001
01/02/2001
01/03/2001
but how would I please if possible is always find the date in the middle of the month? I would use 15th, but issue you have is with February
I need to make analysis of sum of sales mid month
any ideas please team
you can use this formula
DECLARE #Date DATE ='20180201'
SELECT DATEADD(DAY, (DAY(EOMONTH(#Date)) / 2) - 1, #Date)
Solution:
Get the count of the days in the month and calculate the "middle" day. In the next example the count of the days (28, 29, 30 or 31) is divided by an integer divisor (2), so the result will be an integer that has any fractional part truncated. Choose your preferred method.
DECLARE #date date
SET #date = DATEFROMPARTS(2020, 2, 1)
-- 15 is the half of the month with 30 and 31 days, 14 for months with 28, 29 days
SELECT DATEDIFF(d, #date, DATEADD(month, 1, #date)) / 2
-- 16 is the half of the month with 31 days, 15 for months with 29, 30 days, 14 for month with 28 days
SELECT (DATEDIFF(d, #date, DATEADD(month, 1, #date)) + 1) / 2
Example:
WITH Months AS
(
SELECT SomeDate = DATEFROMPARTS(2018, 1, 1)
UNION ALL
SELECT DATEADD(month, 1, SomeDate)
FROM Months
WHERE DATEPART(month, SomeDate) < 12
)
SELECT
SomeDate AS FirstDate,
DATEADD(d, -1, DATEADD(month, 1, SomeDate)) AS LastDate,
DATEDIFF(d, SomeDate, DATEADD(month, 1, SomeDate)) AS DaysBetween,
DATEDIFF(d, SomeDate, DATEADD(month, 1, SomeDate)) / 2 AS HalfOfMonth1,
(DATEDIFF(d, SomeDate, DATEADD(month, 1, SomeDate)) + 1) / 2 AS HalfOfMonth2
FROM Months
Output:
FirstDate LastDate DaysBetween HalfOfMonth1 HalfOfMonth2
01/01/2018 31/01/2018 31 15 16
01/02/2018 28/02/2018 28 14 14
01/03/2018 31/03/2018 31 15 16
01/04/2018 30/04/2018 30 15 15
01/05/2018 31/05/2018 31 15 16
01/06/2018 30/06/2018 30 15 15
01/07/2018 31/07/2018 31 15 16
01/08/2018 31/08/2018 31 15 16
01/09/2018 30/09/2018 30 15 15
01/10/2018 31/10/2018 31 15 16
01/11/2018 30/11/2018 30 15 15
01/12/2018 31/12/2018 31 15 16
i have tried the following
SELECT DATEADD(dd, (datediff(DD, DATEADD(m, DATEDIFF(m, 0, GETDATE()), - 1), eomonth(getdate())) / 2), DATEADD(m, DATEDIFF(m, 0, GETDATE()), - 1)),
CEILING((datediff(DD, DATEADD(m, DATEDIFF(m, 0, GETDATE()), - 1), eomonth(getdate())) / 2.00))
An update to the answer
DECLARE #Date DATE ='2018-10-01'---'20180201'
SELECT DATEADD(DAY, CEILING((DAY(EOMONTH(#Date)) / 2.00)) - 1, #Date)
Here is a query that get start date of month and end date of month by using datediff you can find the number of day to add and subtract
Set #tdate = '02/10/2018';
Select DATEFROMPARTS(YEAR(#tdate),MONTH(#tdate),1) as startdate , dateadd(day,-1,DATEFROMPARTS(YEAR(#tdate),MONTH(#tdate)+1,1)) as enddate
Regards

calculate start date and end date from given quarter SQL

I want to get :
startdate and enddate from a given quarter from between dates
example :
range of dates : 2016-01-01 - 2016-12-31
1 (quarter) - will give me :
start date
2016-01-01
enddate
2016-03-31
2 (quarter) - will give me :
start date
2016-04-01
enddate
2016-06-30
and so on
I made it for only Quarter name and Year, modified it as your need
-- You may need to extend the range of the virtual tally table.
SELECT [QuarterName] = 'Q' + DATENAME(qq,DATEADD(QQ,n,startdate)) + ' ' + CAST(YEAR(DATEADD(QQ,n,startdate)) AS VARCHAR(4))
FROM (SELECT startdate = '01/Jan/2016', enddate = '31/DEC/2016') d
CROSS APPLY (
SELECT TOP(1+DATEDIFF(QQ,startdate,enddate)) n
FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) rc(n)
) x
Check below logic to get your answer.
DECLARE #Year DATE = convert(varchar(20),datepart(YEAR,getdate()))+'-01'+'-01'
DECLARE #Quarter INT = 4
SELECT DATEADD(QUARTER, #Quarter - 1, #Year) ,
DATEADD(DAY, -1, DATEADD(QUARTER, #Quarter, #Year))
SELECT DATEADD(QUARTER, d.q, DATEADD(YEAR, DATEDIFF(YEAR, 0,GETDATE()), 0))
AS FromDate,
DATEADD(QUARTER, d.q + 1, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), -1))
AS ToDate
FROM (
SELECT 0 UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3
) AS d(q)

Displaying start date of week in SQL

I have a SQL query that to return the number of items per week. I have a query that returns so far this:
Number of Items | Week Number
-------------------------------
100 | 18
80 | 19
120 | 20
And would like to return the following:
Number of Items | Week Beginning
-------------------------------
100 | 1st May 2017
80 | 8th May 2017
120 | 15th May 2017
What I have so far is:
SELECT COUNT(*) AS 'Number of Items', DATEPART(WEEK, Date) FROM table
where DATEPART(Year, Date) = '2017' and DATEPART(MONTH, Date) = 5
group by DATEPART(WEEK, Date)
You are talking about the 1st day of the current week:
example: select FORMAT(dateadd(ww,datediff(ww,0,getdate()),0),'dd MMM yyyy')--if you are using SQL 2012+
answer:
SELECT COUNT(*) AS 'Number of Items', FORMAT(dateadd(ww,datediff(ww,0,date_column),0),'dd MMM yyyy')
FROM table
where DATEPART(Year, Date) = '2017' and DATEPART(MONTH, Date) = 5
group by DATEPART(WEEK, Date)
As you need Monday to be the first day of the week
select DATEPART(WEEK, MyDate),DATEADD(DAY,1,(DATEADD(DAY, 1-DATEPART(WEEKDAY, MyDate), MyDate)))
from (
select '5/3/2017' MyDate
union all select '5/10/2017'
union all select '5/14/2017')A
SELECT DATEADD(DAY, DATEDIFF(DAY, 0, Date) /7*7, 0) AS StartDateOfWeek
check this if it solves
DECLARE #WeekNum INT
, #YearNum char(4);
SELECT #WeekNum = 20
, #YearNum = 2017
-- once you have the #WeekNum and #YearNum set, the following calculates the date range.
SELECT DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + #YearNum) + (#WeekNum-1), 6) AS StartOfWeek;
SELECT DATEADD(wk, DATEDIFF(wk, 5, '1/1/' + #YearNum) + (#WeekNum-1), 5) AS EndOfWeek;
thanks to http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=185440

MSSQL - Getting last 6 weeks returns last 8 weeks

I am having a problem with week numbers. The customers week starts on a Tuesday, so ends on a Monday. So I have done:
Set DateFirst 2
When I then use
DateAdd(ww,#WeeksToShow, Date)
It occasionally gives me 8 weeks of information. I think it is because it goes over to the previous year, but I am not sure how to fix it.
If I do:
(DatePart(dy,Date) / 7) - #WeeksToShow
Then it works better, but obviously doesn't work going through to previous years as it just goes to minus figures.
Edit:
My currently SQL (If it helps at all without any data)
Set DateFirst 2
Select
DATEPART(yyyy,SessionDate) as YearNo,
DATEPART(ww,SessionDate) as WeekNo,
DATEADD(DAY, 1 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate +SessionTime AS DATE)) [WeekStart],
DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate + SessionTime AS DATE)) [WeekEnd],
DateName(dw,DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate + SessionTime AS DATE))) as WeekEndName,
Case when #ConsolidateSites = 1 then 0 else SiteNo end as SiteNo,
Case when #ConsolidateSites = 1 then 'All' else CfgSites.Name end as SiteName,
GroupNo,
GroupName,
DeptNo,
DeptName,
SDeptNo,
SDeptName,
PluNo,
PluDescription,
SUM(Qty) as SalesQty,
SUM(Value) as SalesValue
From
PluSalesExtended
Left Join
CfgSites on PluSalesExtended.SiteNo = CfgSites.No
Where
Exists (Select Descendant from DescendantSites where Parent in (#SiteNo) and Descendant = PluSalesExtended.SiteNo)
AND (DATEPART(WW,SessionDate + SessionTime) !=DATEPART(WW,GETDATE()))
AND SessionDate + SessionTime between DATEADD(ww,#NumberOfWeeks * -1,#StartingDate) and #StartingDate
AND TermNo = 0
AND PluEntryType <> 4
Group by
DATEPART(yyyy,SessionDate),
DATEPART(ww,SessionDate),
DATEADD(DAY, 1 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate +SessionTime AS DATE)),
DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate + SessionTime AS DATE)),
Case when #ConsolidateSites = 1 then 0 else SiteNo end,
Case when #ConsolidateSites = 1 then 'All' else CfgSites.Name end,
GroupNo,
GroupName,
DeptNo,
DeptName,
SDeptNo,
SDeptName,
PluNo,
PluDescription
order by WeekEnd
There are two issues here, the first is that I suspect you are defining 8 weeks of data as having 8 different values for DATEPART(WEEK, in which case you can replicate the root cause of the issue by looking at what ISO would define as the first week of 2015:
SET DATEFIRST 2;
SELECT Date, Week = DATEPART(WEEK, Date)
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Which gives:
Date Week
-----------------
2014-12-29 52
2014-12-30 53
2014-12-31 53
2015-01-01 1
2015-01-02 1
2015-01-03 1
2015-01-04 1
So although you only have 7 days, you have 3 different week numbers. The problem is that DATEPART(WEEK is quite a simplistic function, and will simply return the number of week boundaries passed since the first day of the year, a better function would be ISO_WEEK since this takes into account year boundaries nicely:
SET DATEFIRST 2;
SELECT Date, Week = DATEPART(ISO_WEEK, Date)
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Which gives:
Date Week
-----------------
2014-12-29 1
2014-12-30 1
2014-12-31 1
2015-01-01 1
2015-01-02 1
2015-01-03 1
2015-01-04 1
The problem is, that this does not take into account that the week starts on Tuesday, since the ISO week runs Monday to Sunday, you could adapt your usage slightly to get the week number of the day before:
SET DATEFIRST 2;
SELECT Date, Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date))
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Which would give:
Date Week
-----------------
2014-12-29 52
2014-12-30 1
2014-12-31 1
2015-01-01 1
2015-01-02 1
2015-01-03 1
2015-01-04 1
So Monday the 29th December is now recognized as the previous week. The problem is that there is no ISO_YEAR built in function, so you will need to define your own. This is a fairly trivial function, even so I almost never create scalar functions because they perform terribly, instead I use an inline table valued function, so for this I would use:
CREATE FUNCTION dbo.ISOYear (#Date DATETIME)
RETURNS TABLE
AS
RETURN
( SELECT IsoYear = DATEPART(YEAR, #Date) +
CASE
-- Special cases: Jan 1-3 may belong to the previous year
WHEN (DATEPART(MONTH, #Date) = 1 AND DATEPART(ISO_WEEK, #Date) > 50) THEN -1
-- Special case: Dec 29-31 may belong to the next year
WHEN (DATEPART(MONTH, #Date) = 12 AND DATEPART(ISO_WEEK, #Date) < 45) THEN 1
ELSE 0
END
);
Which just requires a subquery to be used, but the extra typing is worth it in terms of performance:
SET DATEFIRST 2;
SELECT Date,
Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date)),
Year = (SELECT ISOYear FROM dbo.ISOYear(DATEADD(DAY, -1, Date)))
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Or you can use CROSS APPLY:
SET DATEFIRST 2;
SELECT Date,
Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date)),
Year = y.ISOYear
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date)
CROSS APPLY dbo.ISOYear(d.Date) y;
Which gives:
Date Week Year
---------------------------
2014-12-29 52 2014
2014-12-30 1 2015
2014-12-31 1 2015
2015-01-01 1 2015
2015-01-02 1 2015
2015-01-03 1 2015
2015-01-04 1 2015
Even with this method, by simply getting a date 6 weeks ago you sill still end up with 7 weeks if the date you are using is not a Tuesday, because you will have 5 full weeks, and a part week at the start and a part week at the end, this is the second issue. So you need to make sure your start date is a Tuesday. The following will get you Tuesday of 7 weeks ago:
SELECT CAST(DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), DATEADD(WEEK, -6, GETDATE())) AS DATE);
The logic of this is explained better in this answer, the following is the part that will get the start of the week (based on your datefirst settings):
SELECT DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), GETDATE());
Then all I have done is substitute the second GETDATE() with DATEADD(WEEK, -6, GETDATE()) so that it is getting the start of the week 6 weeks ago, then there is just a cast to date to remove the time element from it.
This will get you current week + 5 previous weeks starting tuesday:
WHERE dateadd(week, datediff(d, 0, getdate()-1)/7 - 4, 1) <= yourdatecolumn
This will show examples:
DECLARE #wks int = 6 -- Weeks To Show
SELECT
dateadd(week, datediff(d, 0, getdate()-1)/7 - 4, 1) tuesday5weeksago,
dateadd(week, datediff(d, 0, getdate()-1)/7 - 5, 1) tuesday6weeksago,
dateadd(week, datediff(d, 0, getdate()-1)/7 - 6, 1) tuesday7weeksago,
dateadd(week, datediff(d, 0, getdate()-1)/7 - #wks + 1, 1) tuesdaydynamicweeksago
Result:
tuesday5weeksago tuesday6weeksago tuesday7weeksago tuesdaydynamicweeksago
2015-01-27 2015-01-20 2015-01-13 2015-01-20