Convert date time in SQL - sql-server

I would like to find out which user are late clock in example clock in time on 9:00Am more than 9:00am declare as late but my result show me more than 10:00Am just count as late
DECLARE #clockin as varchar
DECLARE #clockout as varchar
DECLARE #reportdate as datetime
--SET #clockin = CONVERT(108,'08:30')
SET #clockin = CONVERT(varchar(10),CAST('9:00' AS TIME),100)
SET #clockout = CONVERT(varchar(10),CAST('18:30' AS TIME),100)
SET #reportdate = month(GETDATE())
SELECT
u.showname AS showname,
l.USERID AS USERID,
u.BADGENUMBER AS BADGENUMBER,
l.CHECKTIME AS CHECKTIME,
CASE
WHEN DATEPART(HOUR, l.CHECKTIME) <= #clockin
THEN CONVERT(varchar(10), CAST(l.CHECKTIME AS TIME), 100)
ELSE 'late ' + CONVERT(varchar(100), CAST(l.CHECKTIME AS TIME), 100)
END AS Time
FROM
CHECKINOUT l
INNER JOIN
USERINFO u ON l.USERID = u.USERID
WHERE
u.showname IS NOT NULL
AND u.BADGENUMBER > 100
AND CHECKTIME >= '1 jan 2017'
AND CHECKTIME <= '31 jan 2017'
--GROUP BY l.USERID, u.showname, u.BADGENUMBER
ORDER BY
u.BADGENUMBER
Result

To compare with time not just 'hour'!
DECLARE #clockin as TIME
DECLARE #clockout as TIME
DECLARE #reportdate as datetime
SET #clockin = CAST('9:00' AS TIME)
SET #clockout = CAST('18:30' AS TIME)
SET #reportdate = month(GETDATE())
SELECT
u.showname, l.USERID, u.BADGENUMBER, l.CHECKTIME,
CASE
WHEN CAST(l.CHECKTIME AS TIME) < = #clockin
THEN CONVERT(VARCHAR(10), CAST(l.CHECKTIME AS TIME), 100)
ELSE 'late ' + CONVERT(VARCHAR(100), CAST(l.CHECKTIME AS TIME), 100)
END AS Time
FROM
CHECKINOUT l
INNER JOIN
USERINFO u ON l.USERID = u.USERID
WHERE
u.showname IS NOT NULL
AND u.BADGENUMBER > 100
AND CHECKTIME >= '1 jan 2017'
AND CHECKTIME <= '31 jan 2017'
ORDER BY
u.BADGENUMBER

All you have to do is remove the equal sign. The person arrived at nine so they are not late because that equals the start time. You can also subract 59 seconds to the check in time so 9:00:30 am doesn't show as late.
I would recommend using a separate field for late flag so people can use this data in other reports more easily in excel or whatever: if the person is late how much are they late by stuff like that
Select
u.showname, l.USERID, u.BADGENUMBER, l.CHECKTIME,
case
when datepart(HOUR,l.CHECKTIME) < #clockin

Related

ISNULL not working

I'm trying to get the salary of an employee and I'm not sure why ISNULL is not working here. Although the same query works when used outside subquery.
Maybe I'm implementing the Isnull function wrong.
Net salary is showing null even there is basic pay given.
DECLARE #dateFrom datetime
SET #dateFrom = '2018-03-01'
DECLARE #dateTo datetime
SET #dateTo = '2018-03-31'
Select
[Emp].ID
,[Emp].EmpCode
,[Emp].FirstName + ' ' + [Emp].LastName AS Name
,[Emp].BasicPay
,((select SUM(InstallmentAmount) from HRM.tbl_EmployeeLoanInstallment [Loan]
LEFT JOIN HRM.tbl_EmployeeLoan [EmpLoan] ON [EmpLoan].ID = [Loan].EmployeeLoanCode
where [EmpLoan].EmpCode = Emp.ID AND IsReceived != 1
AND CONVERT(date, [Loan].InstallmentDueOn) >= CONVERT(date, #dateFrom)
AND CONVERT(date, [Loan].InstallmentDueOn) <= CONVERT(date, #dateTo))) AS LoanDeduction
,( SELECT
(ISNULL([Info].[BasicPay], 0))
-
(SELECT SUM(ISNULL([Loan].InstallmentAmount, 0))
FROM [HRM].[tbl_EmployeeLoan] [EmpLoan]
FULL JOIN [HRM].[tbl_EmployeeInfo] [Info] ON [Info].[ID] = [EmpLoan].[EmpCode]
FULL JOIN [HRM].[tbl_EmployeeLoanInstallment] [Loan] ON [EmpLoan].[ID] = [Loan].[EmployeeLoanCode]
WHERE
CONVERT(date, [Loan].InstallmentDueOn) >= CONVERT(date, #dateFrom)
AND
CONVERT(date, [Loan].InstallmentDueOn) <= CONVERT(date, #dateTo)
AND
[Info].[ID] = [Emp].[ID]
GROUP BY Info.ID)
FROM
[HRM].[tbl_EmployeeInfo] [Info]
WHERE Info.ID = Emp.ID
GROUP BY [Info].[ID], [Info].[BasicPay]
) AS NetSalary
from HRM.tbl_EmployeeInfo [Emp]
Output:
412 C3-345 Ayesha Fatima 20000.00 NULL NULL
413 C3-651 Zainab Ali 20000.00 NULL NULL
414 C1343 Ahmed Abdullah 20000.00 11111.11 8888.89
415 231 Ahmed Aslam 20000.00 NULL NULL
416 FS-16 Fawaz Aslam 25000.00 NULL NULL
Are you sure that your subquery return a value? Seems to not be the case.
If you really want a value, you should catch your null value at the end of your subquery.
,ISNULL(
( SELECT
(ISNULL([Info].[BasicPay], 0))
-
(SELECT SUM(ISNULL([Loan].InstallmentAmount, 0))
FROM [HRM].[tbl_EmployeeLoan] [EmpLoan]
FULL JOIN [HRM].[tbl_EmployeeInfo] [Info] ON [Info].[ID] = [EmpLoan].[EmpCode]
FULL JOIN [HRM].[tbl_EmployeeLoanInstallment] [Loan] ON [EmpLoan].[ID] = [Loan].[EmployeeLoanCode]
WHERE
CONVERT(date, [Loan].InstallmentDueOn) >= CONVERT(date, #dateFrom)
AND
CONVERT(date, [Loan].InstallmentDueOn) <= CONVERT(date, #dateTo)
AND
[Info].[ID] = [Emp].[ID]
GROUP BY Info.ID)
, 0)
FROM
[HRM].[tbl_EmployeeInfo] [Info]

case when in sqlserver

i try to use case in for my condition to show out which is late,but after i use case when my result show out too many result.
select
grp.checktime,
--min(CONVERT(smalldatetime,l.checktime)) as clockin,
--max(CONVERT(smalldatetime,l.checktime)) as clockout,
ClockIn = case when min(cast(l.checktime as time)) <= cast(sc.StartTime as time)
then convert(varchar(100), cast(l.checktime as time), 100)
else 'Late ClockIn ' + convert(varchar(100), cast(l.checktime as time), 100)
end,
Clockout = case when max(cast(l.checktime as time)) >= cast(sc.EndTime as time)
then convert(varchar(100), cast(l.checktime as time), 100)
else 'Early ClockOut ' + convert(varchar(100), cast(l.checktime as time), 100)
end,
l.userid,
u.showname,
u.BADGENUMBER
from checkinout l
inner join userinfo u on l.userid = u.userid
inner join UserUsedsclasses uuc on u.userid = uuc.userid
inner join SchClass sc on uuc.SchId = sc.schClassid
inner join (
select distinct CONVERT(Date,checktime) as checktime
from checkinout
group by CONVERT(Date,checktime)
) as grp on grp.checktime = CONVERT(Date, l.checktime)
where uuc.SchId = 1 and u.badgenumber = 107
and u.badgenumber not in (79, 103, 78)
and l.checktime >= dateadd(month, datediff(month, 0, GETDATE() ) , 0)
and l.checktime < dateadd(month, datediff(month, 0, GETDATE ())+1, 0)
group by grp.checktime,l.userid,u.showname,u.BADGENUMBER,sc.StartTime,l.checktime,sc.EndTime
my result show me
Change your group by to group by the date of l.checktime.
select
grp.checktime,
--min(convert(smalldatetime,l.checktime)) as clockin,
--max(convert(smalldatetime,l.checktime)) as clockout,
ClockIn = case when min(cast(l.checktime as time)) <= cast(sc.StartTime as time)
then convert(varchar(100), cast(l.checktime as time), 100)
else 'Late ClockIn ' + convert(varchar(100), cast(l.checktime as time), 100)
end,
Clockout = case when max(cast(l.checktime as time)) >= cast(sc.EndTime as time)
then convert(varchar(100), cast(l.checktime as time), 100)
else 'Early ClockOut ' + convert(varchar(100), cast(l.checktime as time), 100)
end,
l.userid,
u.showname,
u.BADGENUMBER
from checkinout l
inner join userinfo u on l.userid = u.userid
inner join UserUsedsclasses uuc on u.userid = uuc.userid
inner join SchClass sc on uuc.SchId = sc.schClassid
inner join (
select distinct convert(Date,checktime) as checktime
from checkinout
group by convert(Date,checktime)
) as grp on grp.checktime = convert(Date, l.checktime)
where uuc.SchId = 1 and u.badgenumber = 107
and u.badgenumber not in (79, 103, 78)
and l.checktime >= dateadd(month, datediff(month, 0, getdate() ) , 0)
and l.checktime < dateadd(month, datediff(month, 0, getdate ())+1, 0)
group by
grp.checktime
, l.userid
, u.showname
, u.BADGENUMBER
, sc.StartTime
, convert(date, l.checktime)
, sc.EndTime

TSQL get last day of previous months upto a specified month

I need to get last day of all previous months including current month, upto a specified month. For example, I need last days of september, aug, july, june, may, april, march, feb, jan, dec 2015 like so:
temptable_mytable:
last_day_of_month
-----------------
2016-09-30
2016-08-31
2016-07-31
2016-06-30
2016-05-31
2016-04-30
2016-03-31
2016-02-30
2016-01-31
2015-12-31
I need to specify the month and year to go back to - in above case it's December 2015, but it could also be September 2015 and such. Is there a way that I can do a loop and do this instead of having to calculate separately for each month end?
Use a recursive CTE with the EOMONTH function.
DECLARE #startdate DATE = '2016-01-01'
;WITH CTE
AS
(
SELECT EOMONTH(GETDATE()) as 'Dates'
UNION ALL
SELECT EOMONTH(DATEADD(MONTH, -1, [Dates]))
FROM CTE WHERE Dates > DATEADD(MONTH, 1, #startdate)
)
SELECT * FROM CTE
with temp as (select -1 i union all
select i+1 i from temp where i < 8)
select DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+i*-1,0)) from temp
declare #LASTMONTH date = '2018-10-01';
WITH MTHS AS (
SELECT dateadd(month,month(getdate()),dateadd(year,year(getdate()) - 1900, 0)) aday
UNION ALL
SELECT DATEADD(month,1,aday) from MTHS WHERE aday <= #LASTMONTH
),
LASTDAYS AS (SELECT DATEADD(day,-1,aday) finaldayofmonth from MTHS)
select * from LASTDAYS
Here is a version that goes forward or backwards as appropriate
declare #LASTMONTH date = '2013-10-01';
WITH DIF AS (SELECT CASE WHEN
YEAR(#LASTMONTH) * 12 + MONTH(#LASTMONTH)
>= YEAR(GETDATE()) * 12 + MONTH(getdate()) THEN 1 ELSE -1 END x),
MTHS AS (
SELECT dateadd(month,month(getdate()),dateadd(year,year(getdate()) - 1900, 0)) aday
UNION ALL
SELECT DATEADD(month,(SELECT X from dif),aday) from MTHS
WHERE month(aday) != month(dateadd(month,1,#LASTMONTH)) or YEAR(aday) != YEAR(dateadd(month,1,#LASTMONTH))
),
LASTDAYS AS (SELECT DATEADD(day,-1,aday) finaldayofmonth from MTHS)
select * from LASTDAYS order by finaldayofmonth
Here's one approach, using a CTE to generate a list of incrementing numbers to allow us to then have something to select from and use in a DATEADD to go back for the appropriate number of months.
Typically, if you're doing this quite frequently, instead of generating numbers on the fly like this with the CROSS JOIN, I'd recommend just creating a "Numbers" table that just holds numbers from 1 to "some number high enough to meet your needs"
DECLARE #Date DATE = '20151201'
DECLARE #MonthsBackToGo INTEGER
SELECT #MonthsBackToGo = DATEDIFF(mm, #Date, GETDATE()) + 1;
WITH _Numbers AS
(
SELECT TOP (#MonthsBackToGo) ROW_NUMBER() OVER (ORDER BY o.object_id) AS Number
FROM sys.objects o
CROSS JOIN sys.objects o2
)
SELECT EOMONTH(DATEADD(mm, -(Number- 1), GETDATE())) AS last_day_of_month
FROM _Numbers
This should scale out no matter how far you go back or forward for your originating table or object.
SET NOCOUNT ON;
DECLARE #Dates TABLE ( dt DATE)
DECLARE #Start DATE = DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)
DECLARE #End DATE = DATEADD(YEAR, 1, #Start)
WHILE #Start <= #End
BEGIN
INSERT INTO #Dates (dt) VALUES (#Start)
SELECT #Start = DATEADD(DAY, 1, #Start)
END
; With x as
(
Select
dt
, ROW_NUMBER() OVER(PARTITION BY DATEPART(YEAR, Dt), DATEPART(MONTH, Dt) ORDER BY Dt Desc) AS rwn
From #Dates
)
Select *
From x
WHERE rwn = 1
ORDER BY Dt
This was cribbed together quick based on a couple different SO answers for the parts:
DECLARE #startdate datetime, #enddate datetime
set #startdate = '2015-12-01'
set #enddate = getdate()
;WITH T(date)
AS
(
SELECT #startdate
UNION ALL
SELECT DateAdd(day,1,T.date) FROM T WHERE T.date < #enddate
)
SELECT DISTINCT
DATEADD(
day,
-1,
CAST(CAST(YEAR(date) AS varchar) + '-' + CAST(MONTH(date)AS varchar) + '-01' AS DATETIME))
FROM T OPTION (MAXRECURSION 32767);

SQLSERVER 2008: Breaking a output for the entire day into 2 records for 12 hours

I am looking for the count of records as below.
PLANNED_SHIP_From_Date PLANNED_SHIP_To Date Total_Lines_Count ....
1) 09-04-2016 07:00:01 09-04-2016 18:59:59 165 .....
2) 09-04-2016 19:00:00 10-04-2016 07:00:00 121 .....
3) 10-04-2016 07:00:01 10-04-2016 18:59:59 165 .....
4) 10-04-2016 19:00:00 11-04-2016 07:00:00 123 .....
5) 11-04-2016 07:00:01 11-04-2016 18:59:59 234 .....
.
Currently my query is counting the records as per date.
SELECT
cast(shdr.PLANNED_SHIP_DATE as date),
SUM(sdtl_1_1.TOTAL_LINES_COUNT) AS TOTAL_LINES_COUNT
FROM
dbo.SHIPMENT_HEADER AS shdr WITH (NOLOCK)
INNER JOIN
(
SELECT
SHIPMENT_ID,
COUNT(*) AS TOTAL_LINES_COUNT
FROM
dbo.SHIPMENT_DETAIL AS SHIPMENT_DETAIL_1 WITH (NOLOCK)
WHERE
(
STATUS1 >= 401
)
AND (
DATEDIFF(day, PLANNED_SHIP_DATE, CONVERT(date, SYSDATETIME())) < 4
)
GROUP BY
SHIPMENT_ID
) AS sdtl_1_1
ON sdtl_1_1.SHIPMENT_ID = shdr.SHIPMENT_ID
WHERE
(
shdr.TRAILING_STS >= 401
)
AND (
DATEDIFF(day, shdr.PLANNED_SHIP_DATE, CONVERT(date, SYSDATETIME())) < 4
)
GROUP BY
cast(shdr.PLANNED_SHIP_DATE as date)
Try this -
DECLARE #ReportDays int = 30,
#StartHr int = 7,
#Today DATETIME2 = CAST(SYSDATETIME() AS DATE);
--http://sqlblog.com/blogs/adam_machanic/archive/2006/07/12/you-require-a-numbers-table.aspx
WITH
a AS (SELECT 1 AS i UNION ALL SELECT 1),
b AS (SELECT 1 AS i FROM a AS x, a AS y),
c AS (SELECT 1 AS i FROM b AS x, b AS y),
d AS (SELECT 1 AS i FROM c AS x, c AS y),
e AS (SELECT 1 AS i FROM d AS x, d AS y),
numbers as (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS number FROM e),
StartDates AS (
SELECT
DATEADD(
HH,
#StartHr + (n2.number * 12),
DATEADD(D, 0-n1.number, #Today)
) AS StartDT
FROM
(SELECT * FROM numbers WHERE Number BETWEEN 0 AND #ReportDays) n1
CROSS JOIN (SELECT * FROM numbers WHERE Number IN (0,1)) n2
),
DateRanges AS
(SELECT StartDT, DATEADD(hh, 12, StartDT) AS EndDT FROM StartDates),
Shipments AS
(SELECT
StartDT AS PLANNED_SHIP_From_Date,
EndDT AS PLANNED_SHIP_To_Date,
1 AS Shipment
FROM
DateRanges dr
LEFT JOIN dbo.SHIPMENT_DETAIL sd
ON sd.Status1 >=401
AND sd.PLANNED_SHIP_DATE BETWEEN dr.StartDT AND dr.EndDT)
SELECT
PLANNED_SHIP_From_Date,
PLANNED_SHIP_To_Date,
SUM(Shipment) AS TOTAL_LINES_COUNT
FROM
Shipments
ORDER BY
PLANNED_SHIP_From_Date;
What we're doing is -
Building a numbers table
Using that to pull a list of days, with two records per day
Working out the start & finish times for each time window
Joining the time windows to the records and summing
Hope that helps :-)
Add another column to your select....
CASE
WHENE DATEPART(HOUR, Planned_SHIP_DATE) < 12 THEN 'AM' ELSE 'PM'
END AS ShipPeriod
You could then add that column into a GROUPING to seperate the 'AM's from 'PM's
Of course I have assuumed you wanted AM/PM. But you can modify the CASE statement to break the hours up as you see fit.
Hope this helps
Thank you all for helping me out.
I have created a SQL query which worked for me. This query gives the count of records from morning 7 AM to 7 PM as MORNING_SHIFT count and 7PM to next day 7AM morning as EVENING_SHIFT for dates greater than 14 days in the past.
SELECT
CASE
WHEN convert(VARCHAR(50), sh.PLANNED_SHIP_DATE, 120) BETWEEN
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 07:00:00') AND
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 18:59:59')
THEN (CONCAT(cast(sh.PLANNED_SHIP_DATE as date),' ','morning_shift'))
WHEN convert(VARCHAR(50), sh.PLANNED_SHIP_DATE, 120) BETWEEN
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 00:00:00') AND
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 06:59:59')
then (CONCAT(cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date),' ','EVENING_shift'))
when
convert(VARCHAR(50), DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) , 120) BETWEEN (convert(VARCHAR(10), cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date), 120) + ' 19:00:00') AND
(convert(VARCHAR(10), cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date), 120) + ' 23:59:59')
THEN (CONCAT(cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date),' ','EVENING_shift'))
END AS 'actual_date_time', sh.PLANNED_SHIP_DATE
FROM dbo.SHIPMENT_HEADER AS sh WITH (nolock)
WHERE (shdr.TRAILING_STS >= 401) AND (DATEDIFF(day, shdr.ACTUAL_SHIP_DATE_TIME, CONVERT(date, SYSDATETIME())) < 14)
group by sh.ACTUAL_SHIP_DATE_TIME;

Getting 30 minute slots between time

I have a Start Datetime and a End Datetime.
Eg: 10:00 am - 12:00 pm
I have to create 4 slots between the, each ranging for 30 minutes.
Eg:
10:00 am-10:30 am
10:30 am-11:00 am
11:00 am-11:30 am
11:30 am-12:00 pm
This 30 minutes can vary and is not a constant. I have tried a few things but they don't seem to work. Can someone please help. Thank you.
I have tried this but i only get the slot difference not the slotfrom-slotto
SELECT
from_dt,to_dt,
DATEDIFF(mi,DATEADD(dd,DATEDIFF(dd,0,from_dt ),0),to_dt )/60 as SlotNumber
FROM
d
group by from_dt,to_dt, DATEDIFF(mi,DATEADD(dd,DATEDIFF(dd,0,from_dt ),0),to_dt )/60
thanks #dwain.c to get Reference
--Declare table
DECLARE #t TABLE
(StartTime TIME, EndTime TIME)
INSERT INTO #t
SELECT '10:00', '12:00'
-- Make CTE
;WITH CTE (n) AS (
SELECT TOP (SELECT DATEDIFF(MINUTE,StartTime,EndTime)/30
FROM #t) 30*(ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1)
FROM sys.all_columns
)
-- QUERY
SELECT
TSStart=DATEADD(minute, n, StartTime)
,TSEnd=DATEADD(minute, n + 30, StartTime)
,Timeslot=CONVERT(VARCHAR(100), DATEADD(minute, n, StartTime), 0) + ' - ' +
CONVERT(VARCHAR(100), DATEADD(minute, n + 30, StartTime), 0)
FROM #t
CROSS APPLY (
SELECT n
FROM CTE
WHERE n BETWEEN 0 AND DATEDIFF(minute, StartTime, DATEADD(minute, -30, EndTime))) a
ORDER BY TSStart

Resources