How to join multi tables with case statement? - sql

How to get data from multiple tables with case on one table, I tried like below but getting error.
select login.UserNname,LastLoggedInDetails.LoggedInIP,UserType.UserType,LastLoggedInDetails.LoggedInTime,
LastLoggedInDetails.LoggedOutTime,LastLoggedInDetails.LoggedInVersion,CompanyRegistered.Comp_Name,
case
when LastLoggedInDetails.LoggedOutTime is not null then CONVERT(VARCHAR(100),DATEDIFF (hour,LastLoggedInDetails.LoggedInTime ,LastLoggedInDetails.LoggedOutTime ))+' Hours '+
CONVERT(VARCHAR(100),DATEDIFF (minute,LastLoggedInDetails.LoggedInTime ,LastLoggedInDetails.LoggedOutTime )%60) +' Minutes' as Duration
when LastLoggedInDetails.LoggedOutTime is null then 'Running...' as Duration
end
from LastLoggedInDetails
join login on LastLoggedInDetails.LastLoggedUserId = login.RegistrationId
join UserType on LastLoggedInDetails.LastLoggedUserTypeId = UserType.UserTypeId
join CompanyRegistered on LastLoggedInDetails.RegCompanyId = CompanyRegistered.Comp_Id

Here is your code for the case, formatted to be helpful:
case when LastLoggedInDetails.LoggedOutTime is not null
then CONVERT(VARCHAR(100),
DATEDIFF(hour, LastLoggedInDetails.LoggedInTime, LastLoggedInDetails.LoggedOutTime)
) + ' Hours ' +
CONVERT(VARCHAR(100),
DATEDIFF(minute, LastLoggedInDetails.LoggedInTime,
LastLoggedInDetails.LoggedOutTime
)%60
) +' Minutes' as Duration
--------------------------------^
when LastLoggedInDetails.LoggedOutTime is null
then 'Running...' as Duration
end
Formatting the code makes the problem obvious: case is an expression that can be named. The individual results from each then are not named. So, try this:
(case when LastLoggedInDetails.LoggedOutTime is not null
then CONVERT(VARCHAR(100),
DATEDIFF(hour, LastLoggedInDetails.LoggedInTime, LastLoggedInDetails.LoggedOutTime)
) + ' Hours ' +
CONVERT(VARCHAR(100),
DATEDIFF(minute, LastLoggedInDetails.LoggedInTime,
LastLoggedInDetails.LoggedOutTime
)%60
) +' Minutes'
when LastLoggedInDetails.LoggedOutTime is null
then 'Running...'
end) as Duration

select login.UserNname,LastLoggedInDetails.LoggedInIP,UserType.UserType,LastLoggedInDetails.LoggedInTime,
LastLoggedInDetails.LoggedOutTime,LastLoggedInDetails.LoggedInVersion,CompanyRegistered.Comp_Name,
case
when LastLoggedInDetails.LoggedOutTime is not null then CONVERT(VARCHAR(100),DATEDIFF (hour,LastLoggedInDetails.LoggedInTime ,LastLoggedInDetails.LoggedOutTime ))+' Hours '+
CONVERT(VARCHAR(100),DATEDIFF (minute,LastLoggedInDetails.LoggedInTime ,LastLoggedInDetails.LoggedOutTime )%60) +' Minutes'
when LastLoggedInDetails.LoggedOutTime is null then 'Running...'
end as Duration
from LastLoggedInDetails
join login on LastLoggedInDetails.LastLoggedUserId = login.RegistrationId
join UserType on LastLoggedInDetails.LastLoggedUserTypeId = UserType.UserTypeId
join CompanyRegistered on LastLoggedInDetails.RegCompanyId = CompanyRegistered.Comp_Id

Related

How to write a loop for such sql query

I need to write such query:
SELECT CAST (date_time_column AS DATE) as 'Date',
AVG(CASE WHEN FORMAT(date_time_column, 'HH:mm') = '00:00' then my_values ELSE NULL end) as '00:00',
........
AVG(CASE WHEN FORMAT(date_time_column, 'HH:mm') = '23:59' then my_values ELSE NULL end) as '23:59'
FROM table
where date_time_column > '2021-08-12'
GROUP BY CAST (date_time_column AS DATE)
What is a way to avoid writing 1440 lines in a query?
Try the below method (Change the variables to match your table and field)
/*Generate all minutes in a day in a string variable*/
Declare #timeRange varchar(max)=null
declare #startdate Datetime='2021-08-12 00:00';
; WITH cte AS
(
SELECT 1 i, #startdate AS resultDate
UNION ALL
SELECT i + 1, DATEADD(minute, i, #startdate )
FROM cte
WHERE DATEADD(minute, i, #startdate ) < DateAdd(day,1,#startdate)
)
SELECT #timeRange=Coalesce(#timeRange +',' + '['+Format(resultDate,'HH:mm')+']','['+Format(resultDate,'HH:mm')+']') FROM cte
OPTION (MAXRECURSION 2000);
/* (Change These variables to match your table & fields */
declare #filterQuery varchar(300)=' where {date_time_column}>''2021-01-01''';
declare #dateTimeColumn varchar(30)='{date_time_column}';
declare #valueColumn varchar(30)='{value_column}';
declare #myTable varchar(20)='{my_table}';
/*Generate Pivot Query */
DECLARE #query AS NVARCHAR(MAX);
set #query= '
SELECT *
FROM (SELECT Cast('+ #dateTimeColumn +' as Date) Resultdate,
       FORMAT(' + #dateTimeColumn + ', ''HH:mm'') DateMinute,
       ' + #valueColumn + ' FROM ' + #myTable + ' ' + #filterQuery +'
     ) FormattedData
PIVOT( AVG('+ #valueColumn + ')  
    FOR DateMinute IN ('+ #timeRange +')
) AS pivotTable
';
/*Execute Generated Query*/
execute(#query)
What you want to do is to return your data in rows, not columns. That is a row for every minute rather than a column for every minute.
Try it something like this:
WITH
cteNums AS
(
Select TOP (1440) ROW_NUMBER() OVER(order by (Select Null)) - 1 as num
From sys.all_columns
Order By num
)
, cteMinutes AS
(
Select FORMAT(CAST(num/cast(1440.0 as real) as DATETIME), N'HH:mm') as Minutes
From cteNums
)
select CAST(t.date_time_column AS DATE) as 'Date',
m.Minutes,
AVG(CASE WHEN FORMAT(t.date_time_column, 'HH:mm') = m.Minute then t.my_values ELSE NULL end) as AvgValues
FROM cteMinutes m
LEFT JOIN [table] t ON m.Minutes = FORMAT(t.date_time_column, 'HH:mm')
where t.date_time_column > '2021-08-12'
GROUP BY CAST(t.date_time_column AS DATE), m.Minutes
ORDER BY CAST(t.date_time_column AS DATE), m.Minutes
;
I cannot, of course, test this as no test data or table definitions were provided.

PIVOT Attendance

I have an attendance table with the result as shown below
I need to get the result in below format:
Below is sample PIVOT query I used. Please help me with a query to get the desired result.
CREATE TABLE #Temp
(
[empcode] varchar(15),
[empDesc] nvarchar(300),
[hrlog_Date] date,
[hrlog_in] datetime,
[hrlog_Out] datetime,
[hrlog_Latein] datetime,
[hrlog_EarlyOut] datetime,
)
DECLARE #Start datetime,#End datetime,#DList varchar(2000),#Sql varchar(max),#Sql1 varchar(max);
SET #Start=#StartDate;
SET #End=#EndDate;
INSERT INTO #Temp
Select h.emp_code,e.emp_desc as emp_Desc,h.hrlog_Date, CONVERT(datetime,h.hrlog_in, 105) as hrlog_in
,CONVERT(datetime,h.hrlog_out,105) as hrlog_out
,
case when cast(h.hrlog_in as time)> cast('8:45' as time) then
cast(h.hrlog_Date as NVARCHAR(50))+' ' +CAST(DATEDIFF(second, cast('8:45' as time), cast(h.hrlog_in as time) ) / 60 / 60 % 24 AS NVARCHAR(50))+ ':' +
CAST(DATEDIFF(second,cast('8:45' as time), cast(h.hrlog_in as time) ) / 60 % 60 AS NVARCHAR(50))
else cast(h.hrlog_Date as nvarchar(50)) +' 0:00' end
mrngLate
,case when cast(h.hrlog_out as time) < cast('17:15' as time) then
cast(h.hrlog_Date as NVARCHAR(50))+' ' +CAST(DATEDIFF(second, cast(h.hrlog_out as time), cast('17:15' as time) ) / 60 / 60 % 24 AS NVARCHAR(50))+ ':' +
CAST(DATEDIFF(second, cast(h.hrlog_out as time),cast('17:15' as time) ) / 60 % 60 AS NVARCHAR(50))
else cast(h.hrlog_Date as nvarchar(50)) +' 0:00' end EvenEarly
from HRDailyLog h INNER JOIN FTEmployee e ON h.emp_code=e.Emp_Code
LEFT OUTER JOIN sys_CostCenterDep c ON e.sys_ccdepcode = c.sys_ccDepCode
LEFT OUTER JOIN FTJobDesc j ON e.job_code = j.Job_code
LEFT OUTER JOIN sysDep d ON j.sys_depcode = d.Sys_Depcode
LEFT OUTER JOIN HrShift s ON e.SFT_Code = s.SFT_Code
Where (h.hrlog_date between #Start and #End and e.SFT_Code is not null)
and CASE WHEN #sftCode = '-1' then #sftCode else e.SFT_Code end= #sftCode
and CASE WHEN #depCode = '-1' then #depCode else d.Sys_Depcode end= #depCode
and h.sys_bRcode = #brCode
SELECT DATEADD(dd,number,#Start) AS Date INTO #Date
FROM master..spt_values
WHERE type='p'
AND DATEADD(dd,number,#Start)<=#End
SELECT #DList=LEFT(dl.Dates,LEN(dl.Dates)-1)
FROM
(SELECT CAST(Date as varchar(11)) + ','
FROM #Date
FOR XML PATH('')
)dl(Dates)
SET #Sql='SELECT * FROM (
SELECT d.Date as dateIn ,t.empcode as empcode,t.empDesc as empDesc,(CONVERT(nvarchar(5),t.hrlog_in, 108)+'' to ''+CONVERT(nvarchar(5),t.hrlog_Out, 108)) as hrlog_in
FROM #Date d
LEFT JOIN #Temp t
ON CONVERT(nvarchar(10), t.hrlog_in, 111)=d.Date
)tm
PIVOT (MIN(hrlog_in) FOR dateIn IN ([' + REPLACE(#DList,',','],[')+ ']))p
WHERE empcode IS NOT NULL'
EXEC(#Sql)

How to CONCATENATE 2 time datatypes in sqlserver 2008?

I'm trying to concatenate two time which is start_time AND end_time and I get this error: Incorrect syntax near '+'. What I'm missing? Here is my query
SELECT schedule.sid AS [ID],
doctor.dlname + ',' + doctor.dfname + ' ' + doctor.dmname AS [Physician],
schedule.sday AS [Day],
start_time + '-' + end_time , <----I get the error here
doctor.rate AS [Rate] ,schedule.sstatus AS [Status]
FROM schedule INNER JOIN doctor ON schedule.did = doctor.did
Try this... You need to CAST start_time and end_time first before concatenating them as only string datatype is allowed to be concatenated.
SELECT schedule.sid AS [ID],
doctor.dlname + ',' + doctor.dfname + ' ' + doctor.dmname AS [Physician],
schedule.sday AS [Day],
CAST(start_time AS VARCHAR) + '-' + CAST(end_time AS VARCHAR),
doctor.rate AS [Rate] ,schedule.sstatus AS [Status]
FROM schedule
INNER JOIN doctor
ON schedule.did = doctor.did
Alternatively... you can use CONVERT too...
SELECT schedule.sid AS [ID],
doctor.dlname + ',' + doctor.dfname + ' ' + doctor.dmname AS [Physician],
schedule.sday AS [Day],
CONVERT(VARCHAR, start_time) + '-' + CONVERT(VARCHAR, end_time),
doctor.rate AS [Rate] ,schedule.sstatus AS [Status]
FROM schedule
INNER JOIN doctor
ON schedule.did = doctor.did
SELECT schedule.sid AS [ID]
,doctor.dlname + ',' + doctor.dfname + ' ' + doctor.dmname AS [Physician]
,schedule.sday AS [Day]
,CAST(start_time AS VARCHAR(8)) + '-' + CAST(end_time AS VARCHAR(8)) <----I get the error here
,doctor.rate AS [Rate]
,schedule.sstatus AS [Status]
FROM schedule INNER JOIN doctor
ON schedule.did = doctor.did
start_time is Time/Datetime datatype and '-' is a string which is varchar datatype. to concatenate two values you have to get them in the same datatype. Simply convert your concertinaing columns into character datatype.
Converting your time fields to VARCHAR(8) will return a string something like 23:13:05.

In IF statement with dates see whether a NULL exists

I have this query and i see if the AUD_CloseDate is > than todays date. Now i imagine these would be a NULL somewhere in AUD_CloseDate so in this statement i also want to check if there is a NULL value in AUD_CloseDate and if there is assign value 1900\01\01
SELECT ([Target Status] + '' + CAST(COUNT(*) AS NVARCHAR(255)) + ' of ' + CAST(#Total AS NVARCHAR(255))) AS TargetStatus, CAST(COUNT(*) AS FLOAT)/CAST(#Total AS FLOAT) AS [Count]
FROM (
SELECT CASE WHEN CONVERT(DATETIME,CONVERT(CHAR(10),DATEADD(DAY,0,t2.AUD_CloseDate), 101)) < CONVERT(DATETIME,CONVERT(CHAR(10),DATEADD(DAY,0,GETDATE()), 101))AND t1.[Status] in ('Open','Closed')
THEN 'Over Due: '
ELSE 'On Time: ' END AS [Target Status]
FROM #tmp1 t1 INNER JOIN dbo.Audit t2
ON t1.AUD_ID = t2.AUD_ID
WHERE t2.AUD_Deleted = 0
AND t2.AUD_LeadAuditor IN (SELECT ID FROM [dbo].[fx_SplitCommaSeperatedValues] (#LeadAssessor))
AND t2.AUD_Year = #Year
AND AUD_Quarter IN (SELECT ID FROM [dbo].[fx_SplitCommaSeperatedValues] (#Quarter)))DER
COALESCE is ANSI-compliant. Same syntax as ISNULL: COALESCE(t2.AUD_CloseDate,'19000101')
Why about a ISNULL() statement ?
ISNULL(t2.AUD_CloseDate,'19000101')
In you example :
SELECT ([Target Status] + '' + CAST(COUNT(*) AS NVARCHAR(255)) + ' of ' + CAST(#Total AS NVARCHAR(255))) AS TargetStatus, CAST(COUNT(*) AS FLOAT)/CAST(#Total AS FLOAT) AS [Count]
FROM (
SELECT CASE WHEN CONVERT(DATETIME,CONVERT(CHAR(10),DATEADD(DAY,0,ISNULL(t2.AUD_CloseDate,'19000101')), 101)) < CONVERT(DATETIME,CONVERT(CHAR(10),DATEADD(DAY,0,GETDATE()), 101))AND t1.[Status] in ('Open','Closed')
THEN 'Over Due: '
ELSE 'On Time: ' END AS [Target Status]
FROM #tmp1 t1 INNER JOIN dbo.Audit t2
ON t1.AUD_ID = t2.AUD_ID
WHERE t2.AUD_Deleted = 0
AND t2.AUD_LeadAuditor IN (SELECT ID FROM [dbo].[fx_SplitCommaSeperatedValues] (#LeadAssessor))
AND t2.AUD_Year = #Year
AND AUD_Quarter IN (SELECT ID FROM [dbo].[fx_SplitCommaSeperatedValues] (#Quarter)))DER
Use ISNULL function
ISNULL(AUD_CloseDate, '1900-01-01')
You are also:
adding 0 days to date
casting it to char(10)
, then casting again to date... Why?
You can achieve the same result withou these conversions, like this example:
SELECT
CASE
WHEN ISNULL(#a, '2014-01-29 13:50') < GETDATE()
THEN 'Over Due: '
ELSE 'On Time: '
END
Results 'Over due:'
SELECT
CASE
WHEN ISNULL(#a, '2014-01-29 15:00') < GETDATE()
THEN 'Over Due: '
ELSE 'On Time: '
END
Results 'On Time:'
** Now is 13:55 :)

SQL SUM() function ignoring WHERE clause and CASE statement

SELECT u.FirstName + ' ' + u.LastName as 'User',
COUNT(*) as 'Number of Calls',
CONVERT(varchar(4), SUM(CASE WHEN c.FromTime BETWEEN #FromDate AND #ToDate
THEN DATEDIFF(mi, c.FromTime, c.ToTime) ELSE 0 END) / 60) + ':' +
CASE WHEN SUM(CASE WHEN c.FromTime BETWEEN #FromDate AND #ToDate
THEN DATEDIFF(mi, c.FromTime, c.ToTime) ELSE 0 END) % 60 < 10 THEN '0' ELSE '' END +
CONVERT(varchar(2), SUM(DATEDIFF(mi, c.FromTime, c.ToTime)) % 60) as 'Total Time Spent',
CONVERT(varchar(4), AVG(DATEDIFF(mi, c.FromTime, c.ToTime)) / 60) + ':' +
CASE WHEN AVG(DATEDIFF(mi, c.FromTime, c.ToTime)) % 60 < 10 THEN '0' ELSE '' END +
CONVERT(varchar(2), AVG(DATEDIFF(mi, c.FromTime, c.ToTime)) % 60) as 'Average Call Time'
FROM Calls c
JOIN Users u ON u.UserID = c.TakenBy
WHERE c.FromTime BETWEEN #FromDate AND #ToDate
GROUP BY u.UserID, u.FirstName, u.LastName
ORDER BY u.FirstName + ' ' + u.LastName
The preceding SQL query returns the correct "Number of Calls" but the "Total Time" and "Average Time" are always the same regardless of the # of calls (which is obviously wrong).
I've read and tried to implement using the CASE WHEN __ Then value ELSE 0 inside SUM but it still returns an incorrect value.
The only way I can get this query to return correct results is if I completely strip out all other info, e.g.
SELECT SUM(DATEDIFF(mi, FromTime, ToTime)) FROM Calls WHERE c.FromTime BETWEEN...
How can I still use my JOIN and GROUP BY and get the aggregate functions to give me the results I want?
Thanks for any and all help!
You're probably better off with a subquery, e.g. in the SELECT part, add something like (SELECT SUM(...) FROM ... WHERE ...) AS total_sum.