Adding between dates - sql query - sql

Currently I have a query that will get me the data from the pervious month .
I need to change thisso I can choose a selected date range that could allow me to input 2 dates and pull back all results between them.
See my query below:
select * from Table1 I
inner join Service K on I.Service_Key = K.Service_Key
inner join Status S on I.Status_Key = S.Status_Key
where K.Service_Key = '1'
and S.Status_Name = 'Closed'
and month(I.Date_Key) = (select case when Month (GETDATE())-1 = 0 then 12 else Month (GETDATE())-1 end)
and year(I.Date_Key) = (select case when Month (GETDATE()) -1 = 0 then year (GETDATE()) -1 ELSE YEAR (GETDATE()) end)
I need to be able to say where dates between dd/mm/yy and dd/mm/yy

You could declare the dates a variables:
Declare #Startdate as datetime
Declare #Enddate as datetime
set #Startdate = '01-AUG-20'
set #Enddate = '22-OCT-20'
select * from Table1 I
inner join Service K on I.Service_Key = K.Service_Key
inner join Status S on I.Status_Key = S.Status_Key
where K.Service_Key = '1'
and S.Status_Name = 'Closed'
and I.Date_Key > #Startdate
and I.Date_Key < #Enddate

A simple method is:
where K.Service_Key = '1' and
S.Status_Name = 'Closed' and
datediff(month, i.Date_key, getdate()) = 1
That version, however, cannot use an index on i.Date_Key if that is appropriate. A more index friendly version is:
where K.Service_Key = '1' and
S.Status_Name = 'Closed' and
i.Date_key < datefromparts(year(getdate()), month(getdate()), 1) and
i.Date_key >= dateadd(month, 1, datefromparts(year(getdate()), month(getdate()), 1))

Related

Query executes successfully but returns no results

The following query is used for a report, the report is still showing live data when accesssed, yet when running the query in Management Studio I am not getting any results despite the message 'query successfully completed'
I have had to declare the #Date parameter which I think I have done correctly at the top of the query.
DECLARE #Date datetime;
BEGIN
SET #Date = 27/07/2017;
END
SELECT CAST(CASE WHEN (SOTD_STWH_CODE = 'HPP SHEF') THEN DATE - (CASE
DATEPART(dw, DATE) WHEN 2 THEN 3 ELSE 1 END) ELSE DATE END AS date) AS
ShipDate,
DeFactoUser.F_SO_Transaction.SOTR_CUST_CODE,
DeFactoUser.F_SO_Transaction_Details.SOTD_HEAD_NO,
DeFactoUser.F_SO_Transaction.SOTR_DLSC_CODE,
DeFactoUser.F_SO_Transaction_Details.SOTD_STWH_CODE,
DeFactoUser.F_SO_Transaction_Details.SOTD_STRC_CODE,
DeFactoUser.F_SO_Transaction_Details.SOTD_QTY_UNITS_ORDERED,
DeFactoUser.F_SO_Transaction_Details.SOTD_QTY_UNITS_OUTSTANDING,
DeFactoUser.F_SO_Transaction_Details.SOTD_QTY_UNITS_PICKED,
DeFactoUser.F_BM_Transactions_Details.BMTD_BMTR_SYS_NO,
DeFactoUser.F_BM_Transactions_Details.BMTD_QTY_OUTSTANDING,
ISNULL(CAST(BaseOn.baseon AS varchar), '') AS BaseOn,
CASE BaseOn.baseonstat WHEN '99' THEN 'Complete' WHEN
'98' THEN 'Outstanding' WHEN '1' THEN 'open' ELSE '' END AS BaseOnStatus,
DeFactoUser.F_SL_Customers.CUST_NAME
FROM DeFactoUser.F_SL_Customers INNER JOIN
DeFactoUser.F_SO_Transaction_Details WITH (NOLOCK) INNER
JOIN
DeFactoUser.F_ST_Products WITH (NOLOCK) ON
DeFactoUser.F_SO_Transaction_Details.SOTD_STRC_CODE =
DeFactoUser.F_ST_Products.STRC_CODE INNER JOIN
DeFactoUser.F_SO_Transaction WITH (NOLOCK) ON
DeFactoUser.F_SO_Transaction_Details.SOTD_HEAD_NO =
DeFactoUser.F_SO_Transaction.SOTR_SYS_NO INNER JOIN
tbl_DFBI_Date ON
DeFactoUser.F_SO_Transaction.SOTR_PROMISED_DATE = tbl_DFBI_Date.Date ON
DeFactoUser.F_SL_Customers.CUST_CODE =
DeFactoUser.F_SO_Transaction_Details.SOTD_CUST_CODE LEFT OUTER JOIN
DeFactoUser.F_BM_Transactions INNER JOIN
DeFactoUser.F_BM_Transactions_Details ON
DeFactoUser.F_BM_Transactions.BMTR_SYS_NO =
DeFactoUser.F_BM_Transactions_Details.BMTD_BMTR_SYS_NO ON
DeFactoUser.F_SO_Transaction_Details.SOTD_SYS_NO =
DeFactoUser.F_BM_Transactions_Details.BMTD_ORDER_LINK_NUMBER LEFT OUTER JOIN
(SELECT RIGHT(SOTR_BASED_ON_REF, 7) AS link,
SOTR_STATUS AS baseonstat, SOTR_SYS_NO AS baseon
FROM DeFactoUser.F_SO_Transaction AS
F_SO_Transaction_1
WHERE (SOTR_CUST_CODE = 'h075') AND
(SOTR_BASED_ON_REF > '0')) AS BaseOn ON
CAST(DeFactoUser.F_SO_Transaction_Details.SOTD_HEAD_NO AS varchar) =
BaseOn.link
WHERE (DeFactoUser.F_ST_Products.STRC_NI_CODE = 'panelcut') AND
(DeFactoUser.F_ST_Products.STRC_ANAL1 = '1033') AND
(DeFactoUser.F_SO_Transaction_Details.SOTD_SOTR_TYPE = 10) AND
(DeFactoUser.F_SO_Transaction.SOTR_CUST_CODE <> 'h075')
AND (DeFactoUser.F_SO_Transaction.SOTR_STATUS < '99') AND (CASE WHEN
(SOTD_STWH_CODE = 'HPP SHEF')
THEN DATE - (CASE DATEPART(dw, DATE) WHEN 2 THEN 3 ELSE 1
END) ELSE DATE END <= #Date)
Any suggestions as to how i can view the results?
You need the following to initialize the date:
SET #Date = '20170727'; -- Format as YYYYMMDD which is locale neutral
What you currently have is, 27 divided by 7 divided by 2017. These are integers, so the result is 0. This number is then converted to datetime, which will not result in the date you intended to have.
You best stick to the ISO 8601 formatting of dates, or date/time values. You can read more about that in the DATETIME documentation.

SQL IN and NOT IN alternative?

I am trying to find a way to optimize my following SQL query which is taking a long time to run:
(s.StaffID in (Select sch.StaffID From Schedule sch
where sch.AccountID=#AccountID
and sch.Date Between DATEADD(day, -90, #Today) and #Today
and sch.Status<>2))
AND
(s.StaffID Not in (Select sch.StaffID From Schedule sch
where sch.AccountID=#AccountID
and sch.Date Between DATEADD(day, -90, #Today) and #Today
and sch.Status=2))
Can I replace it with another simple query which does less work?
You can use aggregation to combine the two expressions:
s.staffid in
(
select staffid
from schedule
where accountid = #accountid
and date between dateadd(day, -90, #today) and #today
group by staffid
having count(case when status <> 2 then 1 end) > 0
and count(case when status = 2 then 1 end) = 0
)
I'd move this logic into sub-query like this:
select s.StaffID
from StaffID as s inner join (
Select StaffID
From Schedule
where
AccountID=#AccountID and
Date Between DATEADD(day, -90, #Today) and #Today and
group by StaffID
having max(case when Status=2 then 2 else 1 end) = 1
) as t
on (s.StaffID = t.StaffID)
So, condition in having will filter out members who had status==2 in past 90 days

SQL Ignores Nested Case

I'm creating a Date_Dimension and have the Problem that i have to define "lastworkingdayofmonth" with Setting a flag on it.
I can handle all days but when the calculated they is a Holiday i cant get the day before to set the flag.
Please help me :)
UPDATE DATE_DIMENSION_001
SET ISLASTWORKINGDAYMONTH =
CASE WHEN ( CONVERT(VARCHAR(8), lastdayofmonth, 112) = Datekey ) AND IsWeekday = 1 AND IsHolidayAut = 0 THEN 1
WHEN ( CONVERT(VARCHAR(8), dbo.fn_LastWorkday(FullDate), 112) ) = Datekey AND IsHolidayAut = 0 THEN 1
WHEN ( CONVERT(VARCHAR(8), dbo.fn_LastWorkday(FullDate), 112) ) = Datekey AND IsHolidayAut = 1 THEN
CASE WHEN ( DATEADD(DD, -1, dbo.fn_LastWorkday(FullDate)) ) = CONVERT(DATE, Datekey) THEN 1
END
END
I think that something like this may work for you:
UPDATE dd
SET ISLASTWORKINGDAYMONTH = 1
FROM
DATE_DIMENSION_001 dd
left join
DATE_DIMENSION_001 dd_anti
on
DATEPART(year,dd.FullDate) = DATEPART(year,dd_anti.FullDate) and
DATEPART(month,dd.FullDate) = DATEPART(month,dd_anti.FullDate) and
dd_anti.FullDate > dd.FullDate and
dd_anti.IsWeekday = 1 and
dd_anti.IsHolidayAut = 0
WHERE
dd.IsWeekday = 1 and
dd.IsHolidayAut = 0 and
dd_anti.FullDate is null
That is, we locate rows which are weekdays, not holidays, and for which (via dd_anti, the LEFT JOIN and the null check in the WHERE clause) we cannot locate another row for the same month, but a later date, and is also a weekday and not a holiday.

Calculate total business working days between two dates

select count(distinct(dateadd(d, 0, datediff(d, 0,checktime)))) as workingdays
from departments,
dbo.USERINFO INNER JOIN dbo.CHECKINOUT ON
dbo.USERINFO.USERID = dbo.CHECKINOUT.USERID
where userinfo.name='Gokul Gopalakrishnan' and deptname='GEN/SUP-TBL'
and checktime>='2014-05-01' and checktime<='2014-05-30'
from the above code I am able to find total working days of employee between two dates.
workingdays
20
but now I want other column name total business days. I want to calculate total business days between two dates.
workingdays businessdays
20 21
how can i do this?
If you only want to exclude weekends then you can simply just exclude these using a conditional count by adding:
count(distinct case when datepart(weekday, getdate()) <= 5 then date end)
So your query becomes:
set datefirst 1;
select count(distinct(dateadd(d, 0, datediff(d, 0,checktime)))) as workingdays,
count(distinct case when datepart(weekday, getdate()) <= 5
then dateadd(d, 0, datediff(d, 0,checktime))
end) as weekdays
from departments,
dbo.USERINFO INNER JOIN dbo.CHECKINOUT ON
dbo.USERINFO.USERID = dbo.CHECKINOUT.USERID
where userinfo.name='Gokul Gopalakrishnan' and deptname='GEN/SUP-TBL'
and checktime>='2014-05-01' and checktime<='2014-05-30'
HOWEVER I would really recommend adding a calendar table to your database. It makes everything so easy, your query would become:
SELECT DaysWorked = COUNT(cio.Date),
WeekDaysWorked = COUNT(CASE WHEN c.IsWeekDay = 1 THEN cio.Date END),
WorkingDaysWorked = COUNT(CASE WHEN c.IsWorkingDay = 1 THEN cio.Date END),
TotalDays = COUNT(*),
TotalWeekDays = COUNT(CASE WHEN c.IsWeekDay = 1 THEN 1 END),
TotalWorkingDays = COUNT(CASE WHEN c.IsWorkingDay = 1 THEN 1 END)
FROM dbo.Calender AS c
LEFT JOIN
( SELECT DISTINCT
Date = CAST(CheckTime AS DATE)
FROM dbo.Departments AS d
CROSS JOIN dbo.userInfo AS ui
INNER JOIN dbo.CheckInOut AS cio
ON cio.UserID = ui.UserID
WHERE ui.Name = 'Gokul Gopalakrishnan'
AND d.deptname = 'GEN/SUP-TBL'
) AS cio
ON c.Date = cio.Date
WHERE d.Date >= '2014-05-01'
AND d.Date <= '2014-05-30';
This way you can define public holidays, weekends, etc. It is so much more flexible than any other solution.
EDIT
I think I misunderstood your original criteria. This should work for you with no calendar table:
SET DATEFIRST 1;
DECLARE #StartDate DATE = '2014-05-01',
#EndDate DATE = '2014-05-30';
DECLARE #Workdays INT =
(DATEDIFF(DAY, #StartDate, #EndDate) + 1)
-(DATEDIFF(WEEK, #StartDate, #EndDate) * 2)
-(CASE WHEN DATEPART(WEEKDAY, #StartDate) = 7 THEN 1 ELSE 0 END)
-(CASE WHEN DATEPART(WEEKDAY, #EndDate) = 6 THEN 1 ELSE 0 END);
SELECT WorkingDays = COUNT(DISTINCT CAST(CheckTime AS DATE)),
BusinessDays = #Workdays
FROM dbo.Departments AS d
CROSS JOIN dbo.userInfo AS ui
INNER JOIN dbo.CheckInOut AS cio
ON cio.UserID = ui.UserID
WHERE ui.Name = 'Gokul Gopalakrishnan'
AND d.deptname = 'GEN/SUP-TBL'
AND cio.CheckTime >= #StartDate
AND cio.CheckTime <= #EndDate;
following query calculate Fridays count between #FromDate and #ToDate variable
((DATEDIFF(DAY,#FromDate,#ToDate)-(6-DATEPART(dw,#FromDate)))/7)*2
Following query calculate Working day count and business day count between to date :
DECLARE #FromDate DATE = '2014-05-01',
#ToDate DATE = '2014-05-30'
SELECT COUNT(DISTINCT CAST(checktime AS Date)) as workingdays,
DATEDIFF(DAY,#FromDate,#ToDate) -
((DATEDIFF(DAY,#FromDate,#ToDate)-(6-DATEPART(dw,#FromDate)))/7)*2 AS BusinessDay
from departments,
dbo.USERINFO INNER JOIN dbo.CHECKINOUT ON
dbo.USERINFO.USERID = dbo.CHECKINOUT.USERID
where userinfo.name='Gokul Gopalakrishnan' and deptname='GEN/SUP-TBL'
and checktime>= #FromDate and checktime<=#ToDate

SQL Date Order Correction

Working on a SQL statement here and I have sort of a stupid question. Ive got this date field that spits out various dates from years and months etc. I'm trying to order them correctly but i get only the month in order. Example is:
01-05-2012
12-30-2011
12-18-2011
11-25-2011
11-24-2011
Etc.
My query is as follows:
SELECT TOP (100) PERCENT CONVERT(VARCHAR(10), A.tran_end_time, 110) AS Date
FROM dbo.ttdpur040101_CT AS A INNER JOIN
dbo.ttdpur040101_Audit AS B ON NOT (A.tran_begin_time > B.event_time_local OR
A.tran_end_time < B.event_time_local) AND (A.__$operation = 2 AND B.action_id = 'IN' OR
(A.__$operation = 3 OR
A.__$operation = 4) AND B.action_id = 'UP' OR
A.__$operation = 1 AND B.action_id = 'DL') AND B.class_type = 'U'
WHERE (B.server_principal_name = #Name)
GROUP BY CONVERT(VARCHAR(10), A.tran_end_time, 110)
ORDER BY Date
I would like to have it shown as follows:
11-24-2011
11-25-2011
12-18-2011
12-25-2011
01-08-2012
01-09-2012
etc.
Thanks
You are ordering by a Date column that has been converted to a VARCHAR(). Instead order by the original date column:
ORDER BY A.tran_end_time ASC
That's because Date is a varchar.
Try it this way:
SELECT TOP (100) PERCENT CONVERT(VARCHAR(10), A.tran_end_time, 110) AS Date
FROM dbo.ttdpur040101_CT AS A INNER JOIN
dbo.ttdpur040101_Audit AS B ON NOT (A.tran_begin_time > B.event_time_local OR
A.tran_end_time < B.event_time_local) AND (A.__$operation = 2 AND B.action_id = 'IN' OR
(A.__$operation = 3 OR
A.__$operation = 4) AND B.action_id = 'UP' OR
A.__$operation = 1 AND B.action_id = 'DL') AND B.class_type = 'U'
WHERE (B.server_principal_name = #Name)
GROUP BY CONVERT(VARCHAR(10), A.tran_end_time, 110)
ORDER BY CONVERT(DATETIME, Date, 103) ASC
SELECT CONVERT(VARCHAR(10), [Date], 110) FROM (
SELECT TOP (100) PERCENT DATEADD(dd, datediff(dd, 0, A.tran_end_time), 0) AS Date
FROM dbo.ttdpur040101_CT AS A
INNER JOIN dbo.ttdpur040101_Audit AS B ON
NOT (A.tran_begin_time > B.event_time_local OR
A.tran_end_time < B.event_time_local) AND
(A.__$operation = 2 AND B.action_id = 'IN' OR
(A.__$operation = 3 OR A.__$operation = 4) AND
B.action_id = 'UP' OR
A.__$operation = 1 AND
B.action_id = 'DL'
) AND
B.class_type = 'U'
WHERE (B.server_principal_name = #Name)
GROUP BY DATEADD(dd, datediff(dd, 0, A.tran_end_time), 0)
) t
ORDER BY [Date]
Quite important is "rounding" to date part only. Faster than converting to varchar is DATEADD(dd, datediff(dd, 0, A.tran_end_time), 0) - because it's just math that SQL Server can do much faster than varchar manipulation.