Compare datetime on select with date only - sql

I want to compare two datetimes based upon if their date is shared.
This works:
SELECT *
FROM XXX
WHERE CAST(LoadDateLAG AS DATE) = CAST(LoadDateLEAD AS DATE)
However, I wanted to actually get the result as an extra column:
SELECT
CAST(LoadDateLAG AS DATE) = CAST(LoadDateLEAD AS DATE)
, *
FROM XXX
The latter doesn't work as SQLServer complains that the syntax is invalid.
Any suggestions?
The result should be as follows:
LoadDateLAG | LoadDateLEAD | (LoadDateLAG = LoadDateLEAD) [as bit]
I need this functionality to compress a historized table
- remove unnecessary entries (e.g., only keep the last entry per day).

SQL Server 2012+
SELECT IIF(CAST(LoadDateLAG AS DATE) = CAST(LoadDateLEAD AS DATE),1,0),* FROM XXX

You can use CASE WHEN:
SELECT
LoadDateLAG, LoadDateLEAD,
CASE WHEN CAST(LoadDateLAG AS DATE) = CAST(LoadDateLEAD AS DATE) THEN 1 ELSE 0 END AS isDateEquals
FROM XXX
-- WHERE CAST(LoadDateLAG AS DATE) = CAST(LoadDateLEAD AS DATE)
In case you also want to show the DATE values too (instead of DATETIME), you can use the following SELECT:
SELECT
CAST(LoadDateLAG AS DATE) AS LoadDateLAG,
CAST(LoadDateLEAD AS DATE) AS LoadDateLEAD,
CASE WHEN CAST(LoadDateLAG AS DATE) = CAST(LoadDateLEAD AS DATE) THEN 1 ELSE 0 END AS isDateEquals
FROM XXX
-- WHERE CAST(LoadDateLAG AS DATE) = CAST(LoadDateLEAD AS DATE)
In case you want to show the DATE values (instead of 1 or 0) if equals, you can use the following SELECT:
SELECT
LoadDateLAG, LoadDateLEAD,
CASE WHEN CAST(LoadDateLAG AS DATE) = CAST(LoadDateLEAD AS DATE) THEN CAST(LoadDateLAG AS DATE) ELSE NULL END AS equalsDate
FROM XXX
-- WHERE CAST(LoadDateLAG AS DATE) = CAST(LoadDateLEAD AS DATE)
demo: http://sqlfiddle.com/#!18/30b0e/11/1

Related

How to combine 2 SQL statements into one table

I have 2 SQL statements to look up successful transactions and failed transactions.
SELECT COUNT (code_reseller) as trx_success, kode_reseller
FROM transaksi
where status = '20' AND CAST (date_entri AS DATE) = CAST (GETDATE() AS DATE)
group by code_reseller
ORDER BY trx_success DESC
AND
SELECT COUNT (code_reseller) as trx_fail, kode_reseller
FROM transaksi
where status > '20' AND CAST (date_entri AS DATE) = CAST (GETDATE() AS DATE)
group by code_reseller
ORDER BY trx_fail DESC
How to combine into one table with 3 columns result with code_reseller, trx_success and trx_fail?
Use conditional aggregation and combine the queries:
SELECT
kode_reseller,
COUNT(CASE WHEN status = '20' THEN 1 END) AS trx_success,
COUNT(CASE WHEN status > '20' THEN 1 END) AS trx_fail
FROM transaksi
WHERE
CAST(date_entri AS DATE) = CAST(GETDATE() AS DATE)
GROUP BY
kode_reseller;
The strategy here is to move the filtering on the status column which previously appeared in the two WHERE clauses into the conditional counts in the SELECT clause. The restriction on date_entri can stay there, since both queries have it.
As suggested by #Dale k, you can do it like this.
You cannot add order by inside, so create an alias table and give order by condition.
SELECT *
FROM
(
SELECT COUNT (code_reseller) as trx_success, kode_reseller
FROM transaksi
WHERE status = '20' AND CAST (date_entri AS DATE) = CAST (GETDATE() AS DATE)
GROUP BY code_reseller
UNION ALL
SELECT COUNT (code_reseller) as trx_fail, kode_reseller
FROM transaksi
WHERE status > '20' AND CAST (date_entri AS DATE) = CAST (GETDATE() AS DATE)
GROUP BY code_reseller
) a
ORDER BY a.trx_success DESC --here we get first select query table' column name and datatype and no of column will be same required in union/union all

group by issue in sql

i'm trying to get in a new column the sessions who are between 08:00 and 18:00. You can see my last CASE in the CTE. For each date there should be a new column "TotalRestrictedSessions" which indicate how many session were on that particular date. If there are none, in this case i have to write 0. I suspect that my problem is when i convert the DATE?
WITH ParkeonCTE
AS
(
SELECT
OccDate = CONVERT(DATE, OC.LocalStartTime),
TotalOccSessions = COUNT(OC.SessionId),
AuthorityId,
TotalOccDuration = ISNULL(SUM(OC.DurationMinutes),0),
TotalNumberOfOverstay = SUM(CAST(OC.IsOverstay AS INT)),
TotalMinOfOverstays = ISNULL(SUM(OC.OverStayDurationMinutes),0),
(CASE
WHEN OC.OspId IS NULL THEN 'OffStreet' ELSE 'OnStreet'
END
) AS ParkingContextType,
(CASE
WHEN CAST(OC.LocalStartTime AS TIME) >= '08:00:00' AND CAST(OC.LocalStartTime AS TIME) <=
'18:00:00'
THEN COUNT(OC.SessionId)
END
) AS TotalRestrictedSessions
FROM Analytics.OccupancySessions AS OC
WHERE OC.AuthorityId IS NOT NULL
GROUP BY CONVERT(DATE,OC.LocalStartTime), OC.AuthorityId,OC.OspId
)
SELECT OC.OccDate,
OC.ParkingContextType,
OC.AuthorityId,
OC.TotalRestrictedSessions,
SUM(OC.TotalOccSessions) AS TotalOccSessions,
AVG(OC.TotalOccDuration) AS AvgOccMinutesDuration, -- wrong
SUM(OC.TotalOccDuration) AS TotalOccDuration,
SUM(OC.TotalNumberOfOverstay) AS TotalNumberOfOverstay,
SUM(OC.TotalMinOfOverstays) AS TotalMinOfOverstays,
CAST(AVG(OC.TotalMinOfOverstays) AS decimal(10,2)) AS AvgMinOfOverstays -- wrong
FROM ParkeonCTE AS OC
GROUP BY OC.OccDate, OC.AuthorityId, OC.ParkingContextType
ORDER BY OC.OccDate DESC
You just need to move your aggregation outside of your CASE expression, called conditional aggregation.
SUM(CASE
WHEN CAST(OC.LocalStartTime AS TIME) >= '08:00:00'
AND CAST(OC.LocalStartTime AS TIME) <= '18:00:00'
THEN 1
ELSE 0
END
) AS TotalRestrictedSessions
Generally, you should include the current query results and your desired results in your question to make it easier to figure out where the issues are.

SQL Server Yesterdays Count

I am trying to get a count of all of yesterdays rows. The query i have runs good but does not pick up null values. Is there a way i can query a count of null and non null values?
Here is my code:
SELECT dateadd(day,datediff(day,0,GETDATE())-1,0) as Received_Date,
COUNT(*) as Enrollments_Completed
FROM Table CD,
CCMDB.dbo.ResolutionLetterDetails RD
WHERE CD.ccid = RD.ccid
and CompletedDate >= DATEADD(d,DATEDIFF(d,1,getdate()),0)
and CompletedDate < DATEADD(d,DATEDIFF(d,0,getdate()),0)
AND CatID in('cat0014')
AND IncomingType <> 'RITS'
AND status = 'Completed'
Convert your CompletedDate to a date with no time and make it equal yesterdays date with no time (from GETDATE()) and use correct JOIN code.
SELECT dateadd(day,datediff(day,0,GETDATE())-1,0) as Received_Date,
COUNT(*) as Enrollments_Completed
FROM Table CD
LEFT JOIN CCMDB.dbo.ResolutionLetterDetails RD ON CD.ccid = RD.ccid
WHERE dateadd(day,datediff(day,1,CompletedDate),0) = dateadd(day,datediff(day,1,GETDATE()),0)
AND CatID IN ('cat0014')
AND IncomingType != 'RITS'
AND status = 'Completed'
Return NULLs:
SELECT dateadd(day,datediff(day,0,GETDATE())-1,0) as Received_Date,
COUNT(*) as Enrollments_Completed
FROM Table CD
LEFT JOIN CCMDB.dbo.ResolutionLetterDetails RD ON CD.ccid = RD.ccid
WHERE dateadd(day,datediff(day,1,CompletedDate),0) = dateadd(day,datediff(day,1,GETDATE()),0)
AND (CatID IN ('cat0014') OR CatID IS NULL)
AND (IncomingType != 'RITS' OR IncomingType IS NULL)
AND (status = 'Completed' OR status IS NULL)
I would fix your query and do:
SELECT CAST(DATEADD(day, -1, GETDATE()) as DATE) as Received_Date,
COUNT(*) as Enrollments_Completed
FROM Table CD JOIN
CCMDB.dbo.ResolutionLetterDetails RD
ON CD.ccid = RD.ccid
WHERE CompletedDate >= CAST(DATEADD(day, -1, GETDATE()) as DATE) AND
CompletedDate < CAST(GETDATE() as DATE) AND
CatID IN ('cat0014') AND
IncomingType <> 'RITS' AND
status = 'Completed';
For the date part, you could also do:
CAST(CompletedDate as DATE) = CAST(DATEADD(day, -1, GETDATE()) as DATE)
This version is even index-safe in SQL Server (although not necessarily in other databases).
Notes:
The DATE data type considerably simplifies your calculations.
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
You should qualify all column names so you (and anyone reading the query) knows what table the column comes from.

Between date condition is not working in SQL Server

I have a data as below,
Trying to run below query but returning 0 rows,
Below query should return highlighted row data as shown above.
Can anybody please explain me, what i'm missing?
select * from Flt_OperativeFlight_SchedulePeriods
where
(
(cast('2018-04-05' as date) between cast(ScheduleStartDate as date) and cast(ScheduleEndDate as date) )
or
(cast('2018-04-11' as date) between cast(ScheduleStartDate as date) and cast(ScheduleEndDate as date) )
)
and CarrierCode='SQ' and FlightNumber='0004'
You could re-write as:
select *
from Flt_OperativeFlight_SchedulePeriods
where CarrierCode='SQ' and FlightNumber='0004' and
(ScheduleStartDate >= '2018-04-05' and ScheduleEndDate <= '2018-04-11')
It happens because
'2018-04-05' < '2018-04-06'
and
'2018-04-11' > '2018-04-10'
As variant maybe it is what you want
select *
from Flt_OperativeFlight_SchedulePeriods
where CarrierCode='SQ' and FlightNumber='0004' and
(
(ScheduleStartDate between '20180405' and '20180411')
or (ScheduleEndDate between '20180405' and '20180411')
)
You can try this
SELECT *
FROM `Flt_OperativeFlight_SchedulePeriods`
WHERE ScheduleStartDate >= '2018-04-05' AND ScheduleEndDate <= '2018-04-11'
AND CarrierCode='SQ' and FlightNumber='0004'
Seems like you want to get overlapping periods, then you need this logic:
start_1 <= end_2 and end_1 >= start_2
For your query:
where
(
cast('2018-04-05' as date) <= cast(ScheduleEndDate as date)
and
cast('2018-04-11' as date) >= cast(ScheduleStartDate as date)
)
Depending on your logic you might have to < or >

Need to calc start and end date from single effective date

I am trying to write SQL to calculate the start and end date from a single date called effective date for each item. Below is a idea of how my data looks. There are times when the last effective date for an item will be in the past so I want the end date for that to be a year from today. The other two items in the table example have effective dates in the future so no need to create and end date of a year from today.
I have tried a few ways but always run into bad data. Below is an example of my query and the bad results
select distinct tb1.itemid,tb1.EffectiveDate as startdate
, case
when dateadd(d,-1,tb2.EffectiveDate) < getdate()
or tb2.EffectiveDate is null
then getdate() +365
else dateadd(d,-1,tb2.EffectiveDate)
end as enddate
from #test tb1
left join #test as tb2 on (tb2.EffectiveDate > tb1.EffectiveDate
or tb2.effectivedate is null) and tb2.itemid = tb1.itemid
left join #test tb3 on (tb1.EffectiveDate < tb3.EffectiveDate
andtb3.EffectiveDate <tb2.EffectiveDate or tb2.effectivedate is null)
and tb1.itemid = tb3.itemid
left join #test tb4 on tb1.effectivedate = tb4.effectivedate \
and tb1.itemid = tb4.itemid
where tb1.itemID in (62741,62740, 65350)
Results - there is an extra line for 62740
Bad Results
I expect to see below since the first two items have a future end date no need to create an end date of today + 365 but the last one only has one effective date so we have to calculate the end date.
I think I've read your question correctly. If you could provide your expected output it would help a lot.
Test Data
CREATE TABLE #TestData (itemID int, EffectiveDate date)
INSERT INTO #TestData (itemID, EffectiveDate)
VALUES
(62741,'2016-06-25')
,(62741,'2016-06-04')
,(62740,'2016-07-09')
,(62740,'2016-06-25')
,(62740,'2016-06-04')
,(65350,'2016-05-28')
Query
SELECT
a.itemID
,MIN(a.EffectiveDate) StartDate
,MAX(CASE WHEN b.MaxDate > GETDATE() THEN b.MaxDate ELSE CONVERT(date,DATEADD(yy,1,GETDATE())) END) EndDate
FROM #TestData a
JOIN (SELECT itemID, MAX(EffectiveDate) MaxDate FROM #TestData GROUP BY itemID) b
ON a.itemID = b.itemID
GROUP BY a.itemID
Result
itemID StartDate EndDate
62740 2016-06-04 2016-07-09
62741 2016-06-04 2016-06-25
65350 2016-05-28 2017-06-24
This should do it:
SELECT itemid
,effective_date AS "Start"
,(SELECT MIN(effective_date)
FROM effective_date_tbl
WHERE effective_date > edt.effective_date
AND itemid = edt.itemid) AS "End"
FROM effective_date_tbl edt
WHERE effective_date <
(SELECT MAX(effective_date) FROM effective_date_tbl WHERE itemid = edt.itemid)
UNION ALL
SELECT itemid
,effective_date AS "Start"
,(SYSDATE + 365) AS "End"
FROM effective_date_tbl edt
WHERE 1 = ( SELECT COUNT(*) FROM effective_date_table WHERE itemid = edt.itemid )
ORDER BY 1, 2, 3;
I did this exercise for Items that have multiple EffectiveDate in the table
you can create this view
CREATE view [VW_TESTDATA]
AS ( SELECT * FROM
(SELECT ROW_NUMBER() OVER (ORDER BY Item,CONVERT(datetime,EffectiveDate,110)) AS ID, Item, DATA
FROM MyTable ) AS Q
)
so use a select to compare the same Item
select * from [VW_TESTDATA] as A inner join [VW_TESTDATA] as B on A.Item = B.Item and A.id = B.id-1
in this way you always minor and major Date
I did not understand how to handle dates with only one Item , but it seems the simplest thing and can be added to this query with a UNION ALL, because the view not cover individual Item
You also need to figure out how to deal with Item with two equal EffectiveDate
you should use the case when statement..
[wrong query because a misunderstand of the requirements]
SELECT
ItemID AS Item,
StartDate,
CASE WHEN EndDate < Sysdate THEN Sysdate + 365 ELSE EndDate END AS EndDate
FROM
(
SELECT tabStartDate.ItemID, tabStartDate.EffectiveDate AS StartDate, tabEndDate.EffectiveDate AS EndDate
FROM TableItems tabStartDate
JOIN TableItems tabEndDate on tabStartDate.ItemID = tabEndDate.ItemID
) TableDatesPerItem
WHERE StartDate < EndDate
update after clarifications in the OP and some comments
I found a solution quite portable, because it doesn't make use of partioning but endorses on a sort of indexing rule that make to correspond the dates of each item with others with the same id, in order of time's succession.
The portability is obviously related to the "difficult" part of query, while row numbering mechanism and conversion go adapted, but I think that it isn't a problem.
I sended a version for MySql that it can try on SQL Fiddle..
Table
CREATE TABLE ITEMS
(`ItemID` int, `EffectiveDate` Date);
INSERT INTO ITEMS
(`ItemID`, `EffectiveDate`)
VALUES
(62741, DATE(20160625)),
(62741, DATE(20160604)),
(62740, DATE(20160709)),
(62740, DATE(20160625)),
(62740, DATE(20160604)),
(62750, DATE(20160528))
;
Query
SELECT
RESULT.ItemID AS ItemID,
DATE_FORMAT(RESULT.StartDate,'%m/%d/%Y') AS StartDate,
CASE WHEN RESULT.EndDate < CURRENT_DATE
THEN DATE_FORMAT((CURRENT_DATE + INTERVAL 365 DAY),'%m/%d/%Y')
ELSE DATE_FORMAT(RESULT.EndDate,'%m/%d/%Y')
END AS EndDate
FROM
(
SELECT
tabStartDate.ItemID AS ItemID,
tabStartDate.StartDate AS StartDate,
tabEndDate.EndDate
,tabStartDate.IDX,
tabEndDate.IDX AS IDX2
FROM
(
SELECT
tabStartDateIDX.ItemID AS ItemID,
tabStartDateIDX.EffectiveDate AS StartDate,
#rownum:=#rownum+1 AS IDX
FROM ITEMS AS tabStartDateIDX
ORDER BY tabStartDateIDX.ItemID, tabStartDateIDX.EffectiveDate
)AS tabStartDate
JOIN
(
SELECT
tabEndDateIDX.ItemID AS ItemID,
tabEndDateIDX.EffectiveDate AS EndDate,
#rownum:=#rownum+1 AS IDX
FROM ITEMS AS tabEndDateIDX
ORDER BY tabEndDateIDX.ItemID, tabEndDateIDX.EffectiveDate
)AS tabEndDate
ON tabStartDate.ItemID = tabEndDate.ItemID AND (tabEndDate.IDX - tabStartDate.IDX = ((select count(*) from ITEMS)+1) )
,(SELECT #rownum:=0) r
UNION
(
SELECT
tabStartDateSingleItem.ItemID AS ItemID,
tabStartDateSingleItem.EffectiveDate AS StartDate,
tabStartDateSingleItem.EffectiveDate AS EndDate
,0 AS IDX,0 AS IDX2
FROM ITEMS AS tabStartDateSingleItem
Group By tabStartDateSingleItem.ItemID
HAVING Count(tabStartDateSingleItem.ItemID) = 1
)
) AS RESULT
;