Sql Query: not able to add a column from another table - sql

I am using this query currently which is running correctly:
SELECT
t.TestId,
t.Days,
t.UserId_Fk
, [Date] = Convert(date,DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckIn)))
, CheckIn = CONVERT(CHAR(5), t.CheckIn, 108)
, CheckOut = CONVERT(CHAR(5), t.CheckOut, 108)
, [Hours] = CAST(DATEDIFF(MINUTE, t.CheckIn, t.CheckOut) / 60. AS DECIMAL(10,2))
FROM (
SELECT
TestId=t.TestId,
Days=t.Days,
t.UserId_Fk
, CheckIn = t.CheckInTime
, CheckOut = r.CheckInTime
, RowNum = ROW_NUMBER() OVER (PARTITION BY t.UserId_Fk, r.CheckInTime ORDER BY 1/0)
FROM UserTime t
OUTER APPLY (
SELECT TOP 1 *
FROM UserTime t2
WHERE
t2.CheckInTime > t.CheckInTime
AND DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckInTime)) = DATEADD(dd, 0, DATEDIFF(dd, 0, t2.CheckInTime))
AND t2.LoginStatus = 'O'
ORDER BY t2.CheckInTime
) r
WHERE t.LoginStatus = 'I'
) t
WHERE t.RowNum = 1
The result is :
TestId Days UserId_Fk Date CheckIn CheckOut Hours
45 Tuesday 3 2014-05-13 11:49 11:49 0.00
I want to add another field(column) in this result Named FullName which is from another
table Users
I tried various things but was unsuccessful.
Table relations are:
Table Test
TestId int(pk)
UserId_Fk int
Days nvarchar(50)
CheckInTime datetime
LoginStatus char(1)
Table Users
UserId int(Pk)
FullName varchar(50)

First join Test & Users table and then try to select the full name of the user. You can join through userid_fk. After joining you can apply top 1 selection & other formating over that joined table.
Something like below:
SELECT
t.TestId,
t.Days,
t.UserId_Fk
, [Date] = Convert(date,DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckIn)))
, CheckIn = CONVERT(CHAR(5), t.CheckIn, 108)
, CheckOut = CONVERT(CHAR(5), t.CheckOut, 108)
, [Hours] = CAST(DATEDIFF(MINUTE, t.CheckIn, t.CheckOut) / 60. AS DECIMAL(10,2))
FROM
(SELECT *
FROM test
JOIN users
ON test.userid_fk=users.userid) t
OUTER APPLY (
SELECT TOP 1 *
FROM UserTime t2
WHERE
t2.CheckInTime > t.CheckInTime
AND DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckInTime)) = DATEADD(dd, 0, DATEDIFF(dd, 0, t2.CheckInTime))
AND t2.LoginStatus = 'O'
ORDER BY t2.CheckInTime
) r
WHERE t.LoginStatus = 'I'
) t
WHERE t.RowNum = 1
Please try few times and fix the query if there is any typo.

SELECT
t.TestId,
t.Days,
t.FullName
, [Date] = Convert(date,DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckIn)))
, CheckIn = CONVERT(CHAR(5), t.CheckIn, 108)
, CheckOut = CONVERT(CHAR(5), t.CheckOut, 108)
, [Hours] = CAST(DATEDIFF(MINUTE, t.CheckIn, t.CheckOut) / 60. AS DECIMAL(10,2))
FROM (
SELECT
FullName=Users.FullName,
TestId=t.TestId,
Days=t.Days,
t.UserId_Fk
, CheckIn = t.CheckInTime
, CheckOut = r.CheckInTime
, RowNum = ROW_NUMBER() OVER (PARTITION BY t.UserId_Fk, r.CheckInTime ORDER BY 1/0)
FROM UserTime t
Inner join Users
on t.UserId_Fk=Users.UserId
OUTER APPLY (
SELECT TOP 1 *
FROM UserTime t2
WHERE
t2.CheckInTime > t.CheckInTime
AND DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckInTime)) = DATEADD(dd, 0, DATEDIFF(dd, 0, t2.CheckInTime))
AND t2.LoginStatus = 'O'
ORDER BY t2.CheckInTime
) r
WHERE t.LoginStatus = 'I'
) t
WHERE t.RowNum = 1

Related

How to get value 0 if the result of sql select except statement return no records?

I have a problem with the SQL Except statement, in my case, I select two columns and one column can have values and the others cannot have because the count of the first SQL statement equals the count of the second SQL after the except statement.
Result that I got :
GroupId absences
1 3
Expected result
GroupId absences
1 3
2 0
How can I do in this case?
select
groupId,
(case when groupId = null then 0 else COUNT(*) end) as absence
from (
select
groupId,
COUNT(*) as absences1
from (
select distinct
MONTh,
DAY,
e.groupId
from employee_c c,
holiday hl,
employee e,
groups,
Get_Calendar_Date(
DATEADD(MONTH, DATEDIFF(MONTH, 0, CAST(DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AS datetime)) + #Month - 1, 0),
DATEADD(MONTH, DATEDIFF(MONTH, -1, CAST(DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AS datetime)) + #Month-1, -1)
)
where DATENAME(DD, Weekday) IN (
select WorkingdayId+1
from timetable s,
groups ds,
grouptime de
where dd.groupId = ds.groupId
and dd.groupId = de.groupId
and s.timetableId = de.timetableId
and de.groupId = ds.groupdId)
and DATEPART(MM,hl.startDate) = #Month
and c.isActive=1
except
(select Month,
Day,
d.departmentId
from department d,
Get_Calendar_Date(
DATEADD(MONTH, DATEDIFF(MONTH, 0, CAST(DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AS datetime)) + #Month - 1, 0),
DATEADD(MONTH, DATEDIFF(MONTH, -1, CAST(DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AS datetime)) + #Month - 1, -1)
),
holiday hle,
employee_c c,
employee e
where datepart(MM,hle.startDate) = #Month
and cast(Date as date) between hle.startDate and hle.endDate
and c.isActive=1
and d.groupId =e.groupId
and c.employeeId=e.employeeId
and c.isActive=1
)
) sc
group by Month,Day,groupId
) s
group by groupId

SQL Query | Summarize TimeSeries

Wondering if anyone can help me out. I have a simple table with the following fields.
ID (int),
TimeStamp (DateTime),
Status (NvarChar)
I need to produce a table with a Count of all Status' for the last 2 hours in 10 minute slots like the example provided. The idea is to produce a Google Line Chart in a dashboard where it will refresh every 10 minutes.
Example:
Table
any help would be appreciated.
José
you could create your time slots with a recursive cte and join to that.
with cte as (
select DATETIMEFROMPARTS(datepart(year,getdate()), datepart(month,getdate()), datepart(day,getdate()), datepart(hour, getdate()), floor((datepart(minute, getdate()) - 9) / 10) * 10, 0, 0) as startDT,
DATETIMEFROMPARTS(datepart(year,getdate()), datepart(month,getdate()), datepart(day,getdate()), datepart(hour, getdate()), floor((datepart(minute, getdate()) + 9) / 10) * 10, 0, 0) as endDT
union all
select DATEADD(minute, -10, startDT),
DATEADD(minute, -10, endDt)
from cte
where DATEADD(minute, -130, getdate()) < DATEADD(minute, -10, startDT)
)
select endDt as [Period],
count(case when [Status] = 'OK' then 1 end) as Status_OK,
count(case when [Status] <> 'OK' then 1 end) as Status_NOK
from cte
left join myTable on [TimeStamp] >= startDT and [TimeStamp] < endDT
group by endDT
if you prefer to use dateadd then
;with cte as (
select dateadd(minute, datediff(minute, 0, getdate()) / 10 * 10, 0) as startDT,
dateadd(minute, datediff(minute, 0, getdate()) / 10 * 10 + 10, 0) as endDT
union all
select dateadd(minute, -10, startDT),
dateadd(minute, -10, endDt)
from cte
where dateadd(minute, -130, getdate()) < dateadd(minute, -10, startDT)
)
select endDt as [Period],
count(case when [Status] = 'OK' then 1 end) as Status_OK,
count(case when [Status] <> 'OK' then 1 end) as Status_NOK
from cte
left join myTable on [TimeStamp] >= startDT and [TimeStamp] < endDT
group by endDT

SQL Server Group BY weekly clause blank if no data

No. 1 Query group by weekly
SELECT
DATEADD(week, DATEDIFF(week, 0, DailyDate), 0) AS WeekStart,
SUM(Soil) AS TotalSoil,
SUM(Rock) AS TotalRock,
SUM(Concrete) AS TotalConcrete,
SUM(Steel) AS TotalSteel,
SUM(MovementPiles) AS TotalMovementPiles,
SUM(Total) AS OverallTotal
FROM
BplPjtRevenueStreams
WHERE
DailyDate > '2016-11-28 00:00:00.000'
AND DailyDate < '2016-12-05 00:00:00.000'
AND Project_Id = 5
GROUP BY
DATEADD(week, DATEDIFF(week, 0, DailyDate), 0)
No. 2 query which have empty data in the table since table has no project_Id = 6 yet
SELECT
DATEADD(week, DATEDIFF(week, 0, DailyDate), 0) AS WeekStart,
SUM(Soil) AS TotalSoil,
SUM(Rock) AS TotalRock,
SUM(Concrete) AS TotalConcrete,
SUM(Steel) AS TotalSteel,
SUM(MovementPiles) AS TotalMovementPiles,
SUM(Total) AS OverallTotal
FROM
BplPjtRevenueStreams
WHERE
DailyDate > '2016-11-28 00:00:00.000'
AND DailyDate < '2016-12-05 00:00:00.000'
AND Project_Id = 6
GROUP BY
DATEADD(week, DATEDIFF(week, 0, DailyDate), 0)
May I know if I want to do something like this for the No. 2 query?
Week Start TotalSoil TotalRock TotalConcrete TotalSteel TotalMovementPiles OverallTotal
1 2016-11-28 00:00:00.000 NULL NULL NULL NULL NULL NULL
1 2016-12-05 00:00:00.000 NULL NULL NULL NULL NULL NULL
Is it possible to do like this if it's empty result in the table?
DECLARE
#Project_Id int = 6,
#RangeFrom datetime = '2016-11-28 00:00:00.000',
#RangeTo datetime = '2016-12-05 00:00:00.000'
;WITH Numbers AS
(
SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) t(Value)
), Weeks AS
(
-- All weeks start from year 2000, Monday
SELECT DATEADD(WEEK, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), '1999-12-27') AS DateValue
FROM Numbers a CROSS JOIN Numbers b CROSS JOIN Numbers c CROSS JOIN Numbers d
), Data AS
(
-- This is your query
SELECT
DATEADD(week, DATEDIFF(week, 0, DailyDate), 0) AS WeekStart,
SUM(Soil) AS TotalSoil,
SUM(Rock) AS TotalRock,
SUM(Concrete) AS TotalConcrete,
SUM(Steel) AS TotalSteel,
SUM(MovementPiles) AS TotalMovementPiles,
SUM(Total) AS OverallTotal
FROM
BplPjtRevenueStreams
WHERE
DailyDate > #RangeFrom
AND DailyDate < #RangeTo
AND Project_Id = #Project_Id
GROUP BY
DATEADD(week, DATEDIFF(week, 0, DailyDate), 0)
)
SELECT
CAST(w.DateValue AS datetime) AS WeekStart,
d.TotalSoil,
d.TotalRock,
d.TotalConcrete,
d.TotalSteel,
d.TotalMovementPiles,
d.OverallTotal
FROM Weeks w LEFT OUTER JOIN Data d ON w.DateValue = CAST(d.WeekStart AS date)
WHERE
w.DateValue BETWEEN CAST(#RangeFrom AS date) AND CAST(#RangeTo AS date)

SQL Query must start from SELECT, it starts FROM WITH - can't make over

In my CRM system I am able to paste own SQL Queries. Add query form has a limit - it doesn't accept queries not starting from SELECT statement.
I have a query which starts from WITH statement and I have no idea how to change it to start from SELECT statement.
;WITH dRange(d) AS
(
SELECT TOP (DATEDIFF(DAY, Convert(date, getdate()+1), GETDATE()+31)+1)
DATEADD(DAY, n-1, Convert(varchar(10), GETDATE()+1,120))
FROM (SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.objects) AS x
), possible(ds, de) AS
(
SELECT DATEADD(MINUTE, 30*rn, DATEADD(HOUR, 9, dRange.d)),
DATEADD(MINUTE, 30*rn + 60, DATEADD(HOUR, 9, dRange.d))
FROM (SELECT TOP (720/30) rn = ROW_NUMBER() OVER
(ORDER BY [object_id])-1 FROM sys.objects) AS x
CROSS JOIN dRange
)
SELECT CONVERT(VARCHAR(16), p.ds, 121) AS 'Start', CONVERT(VARCHAR(16), p.de, 121) AS 'End'
FROM possible AS p
WHERE p.de <= DATEADD(HOUR, 16, DATEADD(DAY, DATEDIFF(DAY, 0, p.de), 0))
Maybe it is possible to wrap it inside SELECT statement somehow?
Seems like an arcane problem but you can structure the query as nested subqueries. In your case, I think this looks like:
SELECT CONVERT(VARCHAR(16), p.ds, 121) AS 'Start', CONVERT(VARCHAR(16), p.de, 121) AS 'End'
FROM (SELECT DATEADD(MINUTE, 30*rn, DATEADD(HOUR, 9, dRange.d)),
DATEADD(MINUTE, 30*rn + 60, DATEADD(HOUR, 9, dRange.d))
FROM (SELECT TOP (720/30) rn = ROW_NUMBER() OVER (ORDER BY [object_id])-1 FROM sys.objects
) AS x CROSS JOIN
(SELECT TOP (DATEDIFF(DAY, Convert(date, getdate()+1), GETDATE()+31)+1)
DATEADD(DAY, n-1, Convert(varchar(10), GETDATE()+1,120))
FROM (SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.objects
) AS x
) dRange
) p
WHERE p.de <= DATEADD(HOUR, 16, DATEADD(DAY, DATEDIFF(DAY, 0, p.de), 0))
Thanks to Gordon I find the answer
SELECT CONVERT(VARCHAR(16), p.ds, 121) AS 'Start', CONVERT(VARCHAR(16), p.de, 121) AS 'End'
FROM (SELECT DATEADD(MINUTE, 30*rn, DATEADD(HOUR, 9, dRange.d)) as ds,
DATEADD(MINUTE, 30*rn + 60, DATEADD(HOUR, 9, dRange.d)) as de
FROM (SELECT TOP (720/30) rn = ROW_NUMBER() OVER (ORDER BY [object_id])-1 FROM sys.objects
) AS x CROSS JOIN
(SELECT TOP (DATEDIFF(DAY, Convert(date, getdate()+1), GETDATE()+31)+1)
DATEADD(DAY, n-1, Convert(varchar(10), GETDATE()+1,120)) as d
FROM (SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.objects
) AS x
) dRange
) AS p
WHERE p.de <= DATEADD(HOUR, 16, DATEADD(DAY, DATEDIFF(DAY, 0, p.de), 0))

SQL GROUP BY or JOIN

I am using SQL 2008 and just cannot get this query to work. I have a table with flight price details in it. There are many rows for each day for each route and I want to return the lowest price per day for the route and also the DateAdded (the datetime that the row was added). I am almost there as I seem to have managed to get the lowest price per day returned but I can't seem to get the correct dateadded to be returned. The code below seems to work to return the lowest price per day but I think I need some sort of join to also return the DateAdded?
ALTER PROCEDURE [dbo].[FlightInfoLowestPricePerDay]
(
#AirportFrom varchar(5),
#AirportTo varchar(5)
)
AS
select DATEADD(dd, 0, DATEDIFF(dd, 0, TimeDeparture)) as FlightDate, MIN(Price) as MinPrice
from FlightInfo
where AirportFrom = #AirportFrom and AirportTo = #AirportTo
AND TimeDeparture > DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
Group By DATEADD(dd, 0, DATEDIFF(dd, 0, TimeDeparture))
Order by FlightDate ASC
I have tried things such as the code below but I do not fully understand joins yet so have been struggling for quite a while although I'm sure I'm missing something very simple!
ALTER PROCEDURE [dbo].[FlightInfoLowestPricePerDay]
(
#AirportFrom varchar(5),
#AirportTo varchar(5)
)
AS
select DATEADD(dd, 0, DATEDIFF(dd, 0, fi1.TimeDeparture)) as FlightDate, MIN(fi1.Price) as MinPrice, fi2.DateAdded
from FlightInfo
fi1 join FlightInfo fi2 on fi1.Price = fi2.Price
where fi1.AirportFrom = #AirportFrom and fi1.AirportTo = #AirportTo
AND fi1.TimeDeparture > DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
Group By DATEADD(dd, 0, DATEDIFF(dd, 0, fi1.TimeDeparture))
Order by FlightDate ASC
Add fi2.DateAdded in Group By
ALTER PROCEDURE [dbo].[FlightInfoLowestPricePerDay]
(
#AirportFrom varchar(5),
#AirportTo varchar(5)
)
AS
select DATEADD(dd, 0, DATEDIFF(dd, 0, fi1.TimeDeparture)) as FlightDate, MIN(fi1.Price) as MinPrice, Cast(Convert(varchar(20),fi2.DateAdded,101) as datetime) DateAdded
from FlightInfo
fi1 join FlightInfo fi2 on fi1.Price = fi2.Price
where fi1.AirportFrom = #AirportFrom and fi1.AirportTo = #AirportTo
AND fi1.TimeDeparture > DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
Group By DATEADD(dd, 0, DATEDIFF(dd, 0, fi1.TimeDeparture)),Cast(Convert(varchar(20),fi2.DateAdded,101) as datetime)
Order by FlightDate ASC
OK I decided to simplify it a bit as I've wasted too much time on this already so now I am passing a specific date into the query and running the query multiple times to get the results I need:
ALTER PROCEDURE [dbo].[FlightInfoLowestPriceDateAddedForSpecificDate]
(
#AirportFrom varchar(5),
#AirportTo varchar(5),
#Date datetime
)
AS
select top 1 *
from FlightInfo
where AirportFrom = #AirportFrom and AirportTo = #AirportTo
AND DATEADD(dd, 0, DATEDIFF(dd, 0, TimeDeparture)) = DATEADD(dd, 0, DATEDIFF(dd, 0, #Date))
Order by Price asc
You want to use window function for this. One way is with row_number():
select flightDate, price
from (select DATEADD(dd, 0, DATEDIFF(dd, 0, TimeDeparture)) as FlightDate, fi.*,
ROW_NUMBER() over (partition by airportFrom, airportTo, DATEADD(dd, 0, DATEDIFF(dd, 0, TimeDeparture)) order by price) as seqnum
from FlightInfo fi
where AirportFrom = #AirportFrom and AirportTo = #AirportTo and
TimeDeparture > DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
) fi
where seqnum = 1
If you are using more recent versions of SQL Server, then you can take advantage of the date data type:
select flightDate, price
from (select cast(TimeDeparture as date) as FlightDate, fi.*,
ROW_NUMBER() over (partition by airportFrom, airportTo, cast(TimeDeparture as date) order by price) as seqnum
from FlightInfo fi
where AirportFrom = #AirportFrom and AirportTo = #AirportTo and
TimeDeparture > cast(getdate() as date)
) fi
where seqnum = 1
You can two sub queries (one that gets the small prices per day and the second one the DateAdded)
SELECT f1.FlightDate, f1.MinPrice, f2.DateAdded From
(
SELECT
DATEADD(dd, 0, DATEDIFF(dd, 0, fi1.TimeDeparture)) as FlightDate,
MIN(fi1.Price) as MinPrice
FROM FlightInfo fi1
WHERE fi1.AirportFrom = #AirportFrom and fi1.AirportTo = #AirportTo
AND fi1.TimeDeparture > DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
Group By
DATEADD(dd, 0, DATEDIFF(dd, 0, fi1.TimeDeparture))
) f1
INNER JOIN
(
SELECT DISTINCT
DATEADD(dd, 0, DATEDIFF(dd, 0, fi2.DateAdded)) AS DateAdded,
Price FROM FlightInfo fi2
WHERE fi2.AirportFrom = #AirportFrom and fi2.AirportTo = #AirportTo
AND fi2.TimeDeparture > DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
) f2 ON f2.Price = f1.MinPrice