UNION ALL and WITH statements - tsql

I need to use two filters over one table.
I try UNION ALL but it does not work.
Is there a way to rework TSQL in order to merge both filters to get merged result data set?
Thank you!
DECLARE #TimeStart datetime
DECLARE #TimeEnd datetime
SET #TimeStart = '20180123'
SET #TimeEnd = '20180124'
;WITH A ([Machine], [TimeStart], [TimeEnd])
AS
(
SELECT machine, [СИЗА: Calib Start] as [TimeStart],[СИЗА: Calib Stop] as [TimeEnd]
FROM
(
SELECT Machine, [AtTime], [ValueString]
FROM [STC_DB].[dbo].[DATA_ACTION]
WHERE AtTime BETWEEN #TimeStart AND #TimeEnd
AND ([ValueInt] IN (16,17))
AND (ValueString LIKE '%СИЗА: Calib Start%' OR ValueString LIKE '%СИЗА: Calib Stop%' )
) d
PIVOT
(
MAX(AtTime)
FOR [ValueString] in ([СИЗА: Calib Start] , [СИЗА: Calib Stop])
) piv
)
SELECT [Machine], (SELECT FullName FROM MachineModelShortView MM WHERE MM.MachineID = A.[Machine]) AS FullName, [TimeStart], [TimeEnd] FROM A
UNION ALL--- It does not work with ;WITH coz of ;
;WITH A ([Machine], [TimeStart], [TimeEnd])
AS
(
SELECT machine, [СИЗ: Calib Start] as [TimeStart],[СИЗ: Calib Stop] as [TimeEnd]
FROM
(
SELECT Machine, [AtTime], [ValueString] FROM [STC_DB].[dbo].[DATA_ACTION]
WHERE AtTime BETWEEN #TimeStart AND #TimeEnd AND ([ValueInt] IN (15, 16)) AND (ValueString LIKE '%СИЗ: Calib Start%' OR ValueString LIKE '%СИЗ: Calib Stop%' ) AND [Action] = 80
) d
PIVOT
(
MAX(AtTime)
FOR [ValueString] in ([СИЗ: Calib Start] , [СИЗ: Calib Stop])
) piv
)
SELECT [Machine], (SELECT FullName FROM MachineModelShortView MM WHERE MM.MachineID = A.[Machine]) AS FullName, [TimeStart], [TimeEnd] FROM A

how about combining the two condition with OR and change the ValueString to just Calib Start and Calib End? Will it still give you the same result?
;WITH A ([Machine], [TimeStart], [TimeEnd])
AS
(
SELECT machine, [Calib Start] as [TimeStart],[Calib Stop] as [TimeEnd]
FROM
(
SELECT Machine,
[AtTime],
CASE WHEN ValueString LIKE '%Calib Start%' THEN 'Calib Start' ELSE 'Calib Stop' END [ValueString]
FROM [STC_DB].[dbo].[DATA_ACTION]
WHERE (
AtTime BETWEEN #TimeStart AND #TimeEnd
AND ([ValueInt] IN (16,17))
AND (ValueString LIKE '%Calib Start%' OR ValueString LIKE '%Calib Stop%' )
)
OR
(
AtTime BETWEEN #TimeStart AND #TimeEnd
AND ([ValueInt] IN (15, 16))
AND (ValueString LIKE '%СИЗ: Calib Start%' OR ValueString LIKE '%СИЗ: Calib Stop%' )
AND [Action] = 80
)
) d
PIVOT
(
MAX(AtTime)
FOR [ValueString] in ([Calib Start] , [Calib Stop])
) piv
)
SELECT [Machine],
(SELECT FullName FROM MachineModelShortView MM WHERE MM.MachineID = A.[Machine]) AS FullName,
[TimeStart],
[TimeEnd]
FROM A

Related

Convert this datetime from SQL Server to Snowflake

I have this piece of code that works in SQL server. I'm having trouble getting it to run in snowflake. 'Datetime' is filetype DateTime in snowflake, but in SQL, it's just a date MM-DD-YYYY, so there is the 6:00 added to turn it into a datetime.
I want the end result to be a date.
Below is SQL Server:
CONVERT(DATE, TEMP.DATETIME - ISNULL((
SELECT CAST(MIN(s_first.FromTimeOfDay) AS DATETIME)
FROM Shift s_first
WHERE s_first.FromDay = s.FromDay
AND s_first.ShiftCalendarID = s.ShiftCalendarID
), CAST('6:00' AS DATETIME))) AS ProductionDate
Here is what I have in Snowflake:
to_date(TEMP.DATETIME) - ifnull(to_date((
SELECT MIN(s_first.FromTimeOfDay)
FROM Shift s_first
WHERE s_first.FromDay = s.FromDay
AND s_first.ShiftCalendarID = s.ShiftCalendarID
), (
SELECT to_date('1900-01-01 06:00:00.000')
))) AS ProductionDate
It's not liking the filetype. I get a filetype error:
invalid type [TO_DATE((SELECT MIN(S_FIRST.FROMTIMEOFDAY) AS "MIN(S_FIRST.FROMTIMEOFDAY)" FROM SHIFT AS S_FIRST WHERE (S_FIRST.FROMDAY = CORRELATION(S.FROMDAY)) AND (S_FIRST.SHIFTCALENDARID = CORRELATION(S.SHIFTCALENDARID))), (SELECT TO_DATE('1900-01-01 06:00:00.000') AS "TO_DATE('1900-01-01 06:00:00.000')" FROM (VALUES (null)) DUAL))] for parameter 'TO_DATE'
Update::
This is the original SQL that i'm trying to write in snowflake.
SELECT
e.Name AS ProductionUnit,
temp.DateTime AS DateTime,
s.Reference AS Shift,
CONVERT(TIME, temp.DateTime) AS Time,
CONVERT(DATE, temp.DateTime - ISNULL((SELECT CAST(MIN(s_first.FromTimeOfDay) AS DateTime) FROM Shift s_first WHERE s_first.FromDay = s.FromDay AND s_first.ShiftCalendarID = s.ShiftCalendarID), CAST('6:00' AS DateTime))) AS ProductionDate,
temp.ScrapReason AS ScrapReason,
temp.Quantity AS ScrapQuantity,
'Manually Registered' AS RegistrationType
FROM (SELECT
CAST(SUM(sreg.ScrapQuantity) AS int) AS Quantity,
sreas.Name As ScrapReason,
DATEADD(MINUTE, 30 * (DATEPART(MINUTE, sreg.ScrapTime) / 30), DATEADD(HOUR, DATEDIFF(HOUR, 0, sreg.ScrapTime), 0)) AS DateTime,
srer.EquipmentID AS EquipmentID
FROM qms.ScrapRegistration sreg WITH (NOLOCK)
INNER JOIN qms.ScrapReason sreas WITH (NOLOCK) ON sreas.ID = sreg.ScrapReasonID
INNER JOIN WorkRequest wr WITH (NOLOCK) ON wr.ID = sreg.WorkRequestID
INNER JOIN SegmentRequirementEquipmentRequirement srer WITH (NOLOCK) ON srer.SegmentRequirementID = wr.SegmentRequirementID
GROUP BY DATEADD(MINUTE, 30 * (DATEPART(MINUTE, sreg.ScrapTime) / 30), DATEADD(HOUR, DATEDIFF(HOUR, 0, sreg.ScrapTime), 0)), srer.EquipmentID, sreas.Name) temp
INNER JOIN Equipment e WITH (NOLOCK) ON e.ID = temp.EquipmentID
INNER JOIN ShiftCalendar sc WITH (NOLOCK) ON sc.ID = dbo.cfn_GetEquipmentShiftCalendarID(e.ID, temp.DateTime)
INNER JOIN Shift s WITH (NOLOCK) ON s.ID = dbo.cfn_GetShiftIDFromDateTime(temp.DateTime, sc.ID)
UNION
SELECT
e.Name AS ProductionUnit,
temp.DateTime AS DateTime,
s.Reference AS Shift,
CONVERT(TIME, temp.DateTime) AS Time,
CONVERT(DATE, temp.DateTime - ISNULL((SELECT CAST(MIN(s_first.FromTimeOfDay) AS DateTime) FROM Shift s_first WHERE s_first.FromDay = s.FromDay AND s_first.ShiftCalendarID = s.ShiftCalendarID), CAST('6:00' AS DateTime))) AS ProductionDate,
temp.ScrapReason AS ScrapReason,
temp.Quantity AS ScrapQuantity,
'Auto Registered' AS RegistrationType
FROM (SELECT
SUM(ISNULL(asr.ScrapQuantity, 0)) AS Quantity,
sreas.Name As ScrapReason,
DATEADD(MINUTE, 30 * (DATEPART(MINUTE, asr.ScrapTime) / 30), DATEADD(HOUR, DATEDIFF(HOUR, 0, asr.ScrapTime), 0)) AS DateTime,
srer.EquipmentID AS EquipmentID
FROM proj.AutoScrapRegistration asr WITH (NOLOCK)
INNER JOIN qms.ScrapReason sreas WITH (NOLOCK) ON sreas.ID = asr.ScrapReasonID
INNER JOIN WorkRequest wr WITH (NOLOCK) ON wr.ID = asr.WorkRequestID
INNER JOIN SegmentRequirementEquipmentRequirement srer WITH (NOLOCK) ON srer.SegmentRequirementID = wr.SegmentRequirementID
GROUP BY DATEADD(MINUTE, 30 * (DATEPART(MINUTE, asr.ScrapTime) / 30), DATEADD(HOUR, DATEDIFF(HOUR, 0, asr.ScrapTime), 0)), srer.EquipmentID, sreas.Name) temp
INNER JOIN Equipment e WITH (NOLOCK) ON e.ID = temp.EquipmentID
INNER JOIN ShiftCalendar sc WITH (NOLOCK) ON sc.ID = dbo.cfn_GetEquipmentShiftCalendarID(temp.EquipmentID, temp.DateTime)
INNER JOIN Shift s WITH (NOLOCK) ON s.ID = dbo.cfn_GetShiftIDFromDateTime(temp.DateTime, sc.ID)
So the first step is to make up some T-SQL data that to help understand hwo the old can ran.
So taking the inner most step on the original sql:
with Shift as (
select * from (values
(1, '2020-11-03', '06:30' )
) as t(ShiftCalendarID, fromday, FromTimeOfDay)
)
SELECT CAST(MIN(s_first.FromTimeOfDay) AS DATETIME) as sub
FROM Shift s_first;
we get:
sub
1900-01-01 06:30:00.000
so we can then weave temp and s together into this CTE data:
with Shift as (
select * from (
values
(1, '2020-11-03', '06:30' )
) as t(ShiftCalendarID, fromday, FromTimeOfDay)
), temp as (
select
t.ShiftCalendarID,
t.FromDay,
CAST(t.date_time AS DATETIME) as date_time
from (
values
(1, '2020-11-03', '2020-11-03 07:41:12' ),
(1, '2020-11-03', '2020-11-03 05:41:12' )
) as t(ShiftCalendarID, FromDay, date_time )
)
and run your existing sql:
select t.*
,CONVERT(DATE, t.date_time - ISNULL((
SELECT CAST(MIN(s_first.FromTimeOfDay) AS DATETIME)
FROM Shift s_first
WHERE s_first.FromDay = t.FromDay
AND s_first.ShiftCalendarID = t.ShiftCalendarID
), CAST('6:00' AS DATETIME))) AS ProductionDate
from temp as t;
which gives:
ShiftCalendarID
FromDay
date_time
ProductionDate
1
2020-11-03
2020-11-03 07:41:12.000
2020-11-03
1
2020-11-03
2020-11-03 05:41:12.000
2020-11-02
there is a subtraction of a time component from a datetime, if the min is not present a default of 6am is used.
And this code looks very much like it's a correlated subquery, so that will have it's own issues, but using the above fake data in snowflake:
so the data CTE's:
with Shift as (
select * from values
(1, '2020-11-03', '06:30' )
t(ShiftCalendarID, fromday, FromTimeOfDay)
), temp as (
select
t.ShiftCalendarID,
t.FromDay,
t.date_time::timestamp as date_time
from values
(1, '2020-11-03', '2020-11-03 07:41:12' ),
(1, '2020-11-03', '2020-11-03 05:41:12' ),
(2, '2020-11-03', '2020-11-03 05:41:12' )
t(ShiftCalendarID, FromDay, date_time )
)
and an extra help CTE to resolve the correlated subquery:
, min_times as (
select
ShiftCalendarID,
fromday,
MIN(FromTimeOfDay) as FromTimeOfDay
from Shift
group by 1,2
)
and then this expanded SQL to see all the steps:
select t.*
,nvl(mt.FromTimeOfDay::time, '06:00'::time) as sub_time
,dateadd('hour', -hour(sub_time), t.date_time) as da1
,dateadd('minute', -minute(sub_time), da1) as da2
,da2::date as ProductionDate
from temp as t
left join min_times as mt
on t.ShiftCalendarID = mt.ShiftCalendarID
and t.FromDay = mt.FromDay
gives:
SHIFTCALENDARID
FROMDAY
DATE_TIME
SUB_TIME
DA1
DA2
PRODUCTIONDATE
1
2020-11-03
2020-11-03 07:41:12.000
06:30:00
2020-11-03 01:41:12.000
2020-11-03 01:11:12.000
2020-11-03
1
2020-11-03
2020-11-03 05:41:12.000
06:30:00
2020-11-02 23:41:12.000
2020-11-02 23:11:12.000
2020-11-02
2
2020-11-03
2020-11-03 05:41:12.000
06:00:00
2020-11-02 23:41:12.000
2020-11-02 23:41:12.000
2020-11-02
so that can then be compacted (perhaps too far)..
select t.*
,dateadd('minute', -minute(nvl(mt.FromTimeOfDay::time, '06:00'::time)), dateadd('hour', -hour(nvl(mt.FromTimeOfDay::time, '06:00'::time)), t.date_time))::date as ProductionDate
from temp as t
left join min_times as mt
on t.ShiftCalendarID = mt.ShiftCalendarID
and t.FromDay = mt.FromDay
less compacted:
select ShiftCalendarID, FROMDAY, ProductionDate
from (
select t.ShiftCalendarID
,t.FROMDAY
,nvl(mt.FromTimeOfDay::time, '06:00'::time) as sub_time
,dateadd('hour', -hour(sub_time), t.date_time) as da1
,dateadd('minute', -minute(sub_time), da1) as da2
,da2::date as ProductionDate
from temp as t
left join min_times as mt
on t.ShiftCalendarID = mt.ShiftCalendarID
and t.FromDay = mt.FromDay
)
SHIFTCALENDARID
FROMDAY
PRODUCTIONDATE
1
2020-11-03
2020-11-03
1
2020-11-03
2020-11-02
2
2020-11-03
2020-11-02

Left joining table to unpivoted version of itself

Hi I have the following code, I wanted to ask if it is okay to Left join a table to an unpivoted version of itself as shown in the code below.
with physician_diag as (
SELECT baseentityid, eventdate,locationid,teamid,average_muac,child_age,child_gender,physician_diagnosis, dignosis_data
FROM [VITAL_DWH].[vr].[event_physician_visit]
UNPIVOT
(dignosis_data FOR physician_diagnosis IN
(
well_baby,
severe_pneumonia) )
AS unpvt )
,
final as (
select *, dense_rank() OVER (PARTITION BY baseentityid ORDER BY eventdate) AS rn from (
select distinct
v.baseentityid, cast(v.eventdate as date) as eventdate, v.locationid, v.teamid,
p.physician_diagnosis, p.dignosis_data,
v.average_muac, v.child_age , v.child_gender
FROM [VITAL_DWH].[vr].[event_physician_visit] v
left join physician_diagnosis p on p.baseentityid=v.baseentityid and p.eventdate=v.eventdate
)
Can't I achieve the same result without left joining, as is shown below -
with physician_diag as (
SELECT baseentityid, eventdate,locationid,teamid,average_muac,child_age,child_gender,physician_diagnosis, dignosis_data
FROM [VITAL_DWH].[vr].[event_physician_visit]
UNPIVOT
(dignosis_data FOR physician_diagnosis IN
(
well_baby,
severe_pneumonia
)
)
AS unpvt
),
final as (
-- Final
select *, dense_rank() OVER (PARTITION BY baseentityid ORDER BY eventdate) AS rn from (
select * from physician_diag
) F
In the second analysis,
select count(distinct baseentityid) from final
gives 9104
In the first analysis,
select count(distinct baseentityid) from final
gives 9107
I was confused as to why there is a difference.

SUM OVER PARTITION to calculate running total

I am trying to modify my query to include a running total for each county in my report. Below is my working query with an attempt to use SUM OVER PARTITION commented out:
SELECT DATEPART(MONTH, r.received_date) AS [MonthID] ,
DATENAME(MONTH, r.received_date) AS [Month] ,
o.name AS [CountyName] ,
rsc.description AS [Filing] ,
COUNT(r.id) AS [Request_Total] ,
CAST (AVG(CAST (DATEDIFF(HOUR, received_date, completion_date) AS DECIMAL(8,2))) / 24 AS DECIMAL(8,2)) AS [Total_Time_Days]
--SUM(r.id) OVER (PARTITION BY o.name) AS [TotalFilings]
FROM dbo.requests AS [r]
INNER JOIN dbo.organizations AS [o] ON o.id = r.submitted_to_organiztion_id
INNER JOIN dbo.request_status_codes AS [rsc] ON rsc.code = r.request_status_code
WHERE r.submitted_to_organiztion_id < 68
AND r.request_type_code = 1
AND CAST(r.received_date AS DATE) >= '01/01/2016'
AND CAST(r.received_date AS DATE) <= '06/30/2016'
AND o.name = 'Alachua'
GROUP BY DATENAME(MONTH, r.received_date) ,
DATEPART(MONTH, r.received_date) ,
o.name ,
rsc.description
ORDER BY DATEPART(MONTH, r.received_date) ,
CountyName ,
Filing;
And the results look correct:
Perhaps I am misusing the SUM PARTITION BYbut my end goal is to add an additional column that will sum the filing types for each county by month.
For example, the additional column for the month of January should be 13,654 while February should be 14,238 and so on.
Could I get some advice on how to get this query working correctly? Thanks,
Not sure this is the best way or more efficient, but I was able to create a sub-query to obtain the results I wanted. I do believe a CTE or use of a Windows function would be better, but I haven't been able to get it to work. Here is my query however:
SELECT X.[MonthID] ,
X.[Month] ,
X.[CountyName] ,
X.[Filing] ,
X.[Avg_Time_Days] ,
SUM(X.Request_Total) AS [Total_Requests]
FROM ( SELECT DATEPART(MONTH, r.received_date) AS [MonthID] ,
DATENAME(MONTH, r.received_date) AS [Month] ,
o.name AS [CountyName] ,
rsc.description AS [Filing] ,
COUNT(r.id) AS [Request_Total] ,
CAST (AVG(CAST (DATEDIFF(HOUR, received_date,
completion_date) AS DECIMAL(8, 2)))
/ 24 AS DECIMAL(8, 2)) AS [Avg_Time_Days]
--, SUM(r.id) OVER (PARTITION BY o.name, rsc.description) AS [TotalFilings]
FROM dbo.requests AS [r]
INNER JOIN dbo.organizations AS [o] ON o.id = r.submitted_to_organiztion_id
INNER JOIN dbo.request_status_codes AS [rsc] ON rsc.code = r.request_status_code
WHERE r.submitted_to_organiztion_id < 68
AND r.request_type_code = 1
AND CAST(r.received_date AS DATE) >= '01/01/2016'
AND CAST(r.received_date AS DATE) <= '06/30/2016'
--AND o.name = 'Alachua'
GROUP BY DATENAME(MONTH, r.received_date) ,
DATEPART(MONTH, r.received_date) ,
o.name ,
rsc.description
--, r.id
--ORDER BY DATEPART(MONTH, r.received_date) ,
-- CountyName ,
-- Filing
) AS X
GROUP BY X.[MonthID] ,
X.[Month] ,
X.[CountyName] ,
X.[Filing] ,
X.[Avg_Time_Days]
ORDER BY X.[MonthID] ,
X.[Month] ,
X.[CountyName] ,
X.[Filing];

Check value for every month in a year in T-sql using cursor

I need a example of a cursor for my meter system, where the system reads the meter every month.
The cursor needs to check, that every meter has a reading registered in the current year. For meters with missing readings, an estimated value is added, such that the daily consumption is like the daily comsumption in the previous period plus 15%. In no previous period exiss, the above Kwh value is used.
How about something like this. (The MonthSeed table could become a real table in your database)
declare #MonthSeed table (MonthNumber int)
insert into #MonthSeed values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
-- assumes declared table "Reading" with fields ( Id int, [Date] datetime, MeterNo varchar(50), Consumption int )
select
m.MeterNo,
r.Date,
calculatedConsumption = isnull(r.Consumption, -- read consumption
isnull((select max(r2.Consumption) Consumption from Reading r2 where datepart(month, r2.Date) = (m.MonthNumber - 1) and r2.MeterNo = m.MeterNo) * 1.15, -- previous consumption + 15%
9999)) -- default consumption
from
(select distinct
MeterNo,
MonthNumber
from
Reading, #MonthSeed) m
left join
Reading r on r.MeterNo = m.MeterNo and datepart(month, r.Date) = m.monthNumber
EDIT FOLLOWING COMMENTS - EXAMPLE OF ADDING MISSING READINGS
As commented need to include an insert before the select insert into Reading (MeterNo, Date, Consumption) and making use of the left join to the reading table include a check for the reading id to be null ie missing where r.Id is null.
I noticed that this would result in null date entries when inserting into the reading table. So I included a date aggregate in the main sub-select Date = dateadd(month, monthnumber, #seeddate); the main select was amended to show a date for missing entries isnull(r.Date, m.Date),
I've calculated the #SeedDate to be the 1st of the current month one year ago but you may want to pass in an earlier date.
declare #MonthSeed table (MonthNumber int)
insert into #MonthSeed values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
-- assumes declared table "Reading" with fields ( Id int, [Date] datetime, MeterNo varchar(50), Consumption int )
declare #SeedDate datetime = (select dateadd(month, datediff(month, 0, getdate())-12, 0)) -- this month, last year
insert into Reading (MeterNo, Date, Consumption)
select
m.MeterNo,
isnull(r.Date, m.Date),
calculatedConsumption =
isnull(r.Consumption, -- read consumption
isnull(1.15 * (select max(r2.Consumption) Consumption
from Reading r2
where datepart(month, r2.Date) = (m.MonthNumber - 1)
and r2.MeterNo = m.MeterNo), -- previous consumption + 15%
9999)) -- default consumption
from
(select distinct
MeterNo,
MonthNumber,
Date = dateadd(month, monthnumber, #seeddate)
from
Reading
cross join
#MonthSeed) m
left join
Reading r on r.MeterNo = m.MeterNo and datepart(month, r.Date) = m.monthNumber
where
r.Id is null
select * from Reading
(The following assumes SQL Server 2005 or later.)
Scrounge around in here and see if there's anything of value:
declare #StartDate as Date = '2012-01-01'
declare #Now as Date = GetDate()
declare #DefaultConsumption as Int = 2000 -- KWh.
declare #MeterReadings as Table
( MeterReadingId Int Identity, ReadingDate Date, MeterNumber VarChar(10), Consumption Int )
insert into #MeterReadings ( ReadingDate, MeterNumber, Consumption ) values
( '2012-01-13', 'E154', 2710 ),
( '2012-01-19', 'BR549', 650 ),
( '2012-02-15', 'E154', 2970 ),
( '2012-02-19', 'BR549', 618 ),
( '2012-03-16', 'BR549', 758 ),
( '2012-04-11', 'E154', 2633 ),
( '2012-04-20', 'BR549', 691 )
; with Months ( Month ) as (
select #StartDate as [Month]
union all
select DateAdd( mm, 1, Month )
from Months
where Month < #Now
),
MeterNumbers ( MeterNumber ) as (
select distinct MeterNumber
from #MeterReadings )
select M.Month, MN.MeterNumber,
MR.MeterReadingId, MR.ReadingDate, MR.Consumption,
Coalesce( MR.Consumption, #DefaultConsumption ) as [BillableConsumption],
( select Max( ReadingDate ) from #MeterReadings where MeterNumber = MN.MeterNumber and ReadingDate < M.Month ) as [PriorReadingDate],
( select Consumption from #MeterReadings where MeterNumber = MN.MeterNumber and ReadingDate =
( select Max( ReadingDate ) from #MeterReadings where MeterNumber = MN.MeterNumber and ReadingDate < M.Month ) ) as [PriorConsumption],
( select Consumption from #MeterReadings where MeterNumber = MN.MeterNumber and ReadingDate =
( select Max( ReadingDate ) from #MeterReadings where MeterNumber = MN.MeterNumber and ReadingDate < M.Month ) ) * 1.15 as [PriorConsumptionPlus15Percent]
from Months as M cross join
MeterNumbers as MN left outer join
#MeterReadings as MR on MR.MeterNumber = MN.MeterNumber and DateAdd( dd, 1 - DatePart( dd, MR.ReadingDate ), MR.ReadingDate ) = M.Month
order by M.Month, MN.MeterNumber

How to exclude nights from a TSQL query?

I'm writing a TSQL query to find the next available datetime from a list of appointments. So far what I've managed to get working does find the gaps in a time query but I can't seem to find a great way to exclude nights (after 7pm lets say).
;WITH CTE
AS ( SELECT
ID,StartAptDate,EndAptDate,
RowNumber = ROW_NUMBER() OVER( ORDER BY StartAptDate ASC )
FROM Appointments WHERE StylistId = 1 AND StartAptDate > CAST( CONVERT( CHAR(8), GetDate(), 112) AS DATETIME)
)
SELECT FirstApptAvail = min( a.EndAptDate )
FROM CTE a
INNER JOIN CTE b
ON a.RowNumber = b.RowNumber - 1
WHERE datediff( minute, a.EndAptDate, b.StartAptDate) >= 15 AND ...
A little pseudo code for the ... would be something like this
(a.StartAptDate < GETDATE #7pm AND a.StartAptDate > GETDATE + 1 #8am)
The part I can't seem to get right is constructing the right side of each comparison. I need to exclude anything that might be returned between 7pm that night - 8am the next morning.
Thank you in advance
Thanks for the quick feedback - it looks like I was able to get the desired result using the BETWEEN statement mentioned in the comments above. I first made the startdate and enddate in question time specific (meaning the date part was 1900 / 01 / 01 so it didn't matter) This way I could use the time ONLY to compare with.
;WITH CTE
AS ( SELECT
ID,StartAptDate,EndAptDate,
RowNumber = ROW_NUMBER() OVER( ORDER BY StartAptDate ASC )
FROM Appointments WHERE StylistId = 1 AND StartAptDate > CAST( CONVERT( CHAR(8), GetDate() - 5, 112) AS DATETIME)
)
SELECT FirstApptAvail = min( a.EndAptDate )
FROM CTE a
INNER JOIN CTE b
ON a.RowNumber = b.RowNumber - 1
WHERE datediff( minute, a.EndAptDate, b.StartAptDate) >= 15 AND (CAST ( CONVERT( CHAR(8), a.StartAptDate, 108) AS DATETIME) BETWEEN '1900-01-01 07:59:59' AND '1900-01-01 18:59:59' AND CAST ( CONVERT( CHAR(8), a.EndAptDate, 108) AS DATETIME) BETWEEN '1900-01-01 07:59:59' AND '1900-01-01 18:59:59')