I'm retrieving data from a view, and one of the columns I'm using is nvarchar(50), but is only ever N'True' or N'False', depending on the operation of a related date column in this parent view.
The following code retrieves the record ID and the column I'm looking for, YTD:
SELECT Enquiry_Number, YTD
FROM dbo.vw_SalesPO_YTD
Output:
ENQ-001 True
ENQ-002 False
ENQ-003 True
However, I'm unable to filter my results using this YTD column for some reason. If I attempt to do this:
SELECT Enquiry_Number, YTD
FROM dbo.vw_SalesPO_YTD
WHERE YTD = N'True'
Then it fails with the following error:
Arithmetic overflow error converting expression to data type datetime.
Which I don't understand because there are no datetime expressions in play in this query. Yes the True or False was determined by comparing datetimes in the parent view, but I don't understand how that might have trickled down to this subquery. Attempting the same thing in the parent view yields the same error - I'm demonstrating it this way for simplicity's sake.
However, performing a similar operation in the SELECT portion of the query works without issues:
SELECT
Enquiry_Number,
YTD,
CASE
WHEN YTD = N'True' THEN 1 ELSE 0
END As C
FROM
dbo.vw_SalesPO_YTD
Output:
ENQ-001 True 1
ENQ-002 False 0
ENQ-003 True 1
However, these 1's and 0's inherit the same flaw, where I can't use them in a WHERE clause without getting this datetime error.
I've been searching hard and am not sure how to identify the core issue. I've been reading things about Collations and type precedence, but can't understand why this behaviour is happening.
When I've checked YTD in INFORMATION_SCHEMA.COLUMNS, it confirms that this column is no different from other columns in my table: YTD is nvarchar(50), using the Latin1_General_CI_AS collation.
Related question: SQL Server Arithmetic overflow error converting expression to data type datetime
The Source of the Problem
This issue is still unsolved, but if you wish to reproduce it, this code from the parent view must be generating this issue:
CASE WHEN
Award_Date <= DATEFROMPARTS(FinancialYear - 1, 11, 1) + GETDATE() - DATEADD(year, DATEDIFF(month, '20161101', GETDATE()) / 12, '20161101')
THEN N'True'
ELSE N'False'
END
Yes this looks overly complicated. We're checking the Award_Date against its associated FinancialYear, which runs from November 1st to October 31st. Each record already knows which FinancialYear it's in. The ultimate aim is to compare TODAY's position (2016-11-30) against TODAY last year (2015-11-30), and TODAY the year before (2014-11-30), etc.
So the code takes today's date and combines it with the FinancialYear for the associated record, and spits out whether the record had occurred between the start of its financial year and the today of the same year. And it's doing this successfully, but then I can't do anything with the N'True' or N'False' it's producing.
I do not know what the type of the source YTD is.
Try using the following:
SELECT Enquiry_Number, [YTD] FROM (
SELECT Enquiry_Number, CONVERT(nvarchar(10),YTD) AS [YTD] FROM dbo.vw_SalesPO_YTD
) AS A
WHERE A.YTD = N'True'
10 is just a thump suck value. It will cut of any part of the field longer that 10. It depends on your actual field size.
SELECT *
FROM (SELECT Enquiry_Number, YTD
FROM dbo.vw_SalesPO_YTD) AS A
WHERE cast(A.YTD as varchar) = 'True'
I used the following as an example:
DECLARE #Data TABLE
(
Enquiry_Number nvarchar(10),
YTD nvarchar(50)
)
INSERT INTO #Data(Enquiry_Number, YTD)
SELECT N'ENQ-001', N'True' UNION
SELECT N'ENQ-002', N'False' UNION
SELECT N'ENQ-003', N'True'
SELECT Enquiry_Number, [YTD] FROM (
SELECT Enquiry_Number, CONVERT(nvarchar(10),YTD) AS [YTD] FROM #Data
) AS A
WHERE A.YTD = N'True'
Result:
ENQ-001 True
ENQ-003 True
There must be results in the YTD field that causes to return it as a datetime type.
Try a query like:
SELECT * FROM dbo.vw_SalesPO_YTD WHERE ISDATE(YTD)= 1
Updated Question:
Try:
ISNULL(CASE WHEN Award_Date <= DATEFROMPARTS(FinancialYear - 1, 11, 1) + GETDATE() - DATEADD(year, DATEDIFF(month, '20161101', GETDATE()) / 12, '20161101') THEN N'True' ELSE N'False' END, 'false')
Try this:- Don't add n before string
SELECT *
FROM (SELECT Enquiry_Number, YTD
FROM dbo.vw_SalesPO_YTD) AS A
WHERE A.YTD = 'True'
This is a successful workaround, not a solution per se or explanation of the core issue.
There's obviously an issue with the data coming out of the view, which will not allow YTD column's results to be operated on in a WHERE clause, and yet they can be operated on by the time the query reaches its SELECT phase.
I've created a new table which explicitly defines the YTD column as nvarchar(50), and then inserted all the records from my view into this table, which has resolved the issue. The records can then be sorted and filtered by YTD as they are supposed to.
Related
I have a query, the goal is to allow a user to pass start and end dates to select customer sales withing the range. Additionally there are two sub queries, one that gets the first order date of a customer and another that gets the last order date of a customer prior to the selected date range.
The query works fine until I add a case statement that attempts to create some customer groupings based on new customer status as well as customer reboarding status.
I have tried redesigning the subqueries a few times but I think the problem is in the case statement. Regarding the aliases the current configuration is a little confusing, the subqueries are stacked not joined individually so the naming conventions are strange but again, the query works until I try to add the case statement.
Unfortunantely, I don't know enough to see what the problem might be, so any help will be greatly appreciated. Case statement is below.
The error returned is
Operand type clash: date is incompatible with int
Code:
CASE
WHEN LAST_ORD.FIRST_ORDER BETWEEN #START_DATE AND #END_DATE
THEN 'NEW IN SELECTED PERIOD'
WHEN LAST_ORD.FIRST_ORDER <= #END_DATE - 365
THEN 'NEW IN LAST YEAR'
WHEN LAST_ORD.LAST_ORDERED < #START_DATE - 730
THEN 'REBOARDED 2+Y INACTIVE'
WHEN LAST_ORD.LAST_ORDERED < #START_DATE - 365
THEN 'REBOARDED 1+Y INACTIVE'
ELSE 'ACTIVE CUSTOMER'
END AS CUST_HIST
you need dateadd
CASE WHEN LAST_ORD.FIRST_ORDER BETWEEN #START_DATE AND #END_DATE THEN 'NEW IN SELECTED PERIOD'
WHEN LAST_ORD.FIRST_ORDER <= DATEADD(day,- 365,#END_DATE ) THEN 'NEW IN LAST YEAR'
WHEN LAST_ORD.LAST_ORDERED < DATEADD(day,- 730,#START_DATE ) THEN 'REBOARDED 2+Y INACTIVE'
WHEN LAST_ORD.LAST_ORDERED < #DATEADD(day,- 365,#START_DATE )THEN 'REBOARDED 1+Y INACTIVE'
ELSE 'ACTIVE CUS
I have a table that acts as a message log, with the two key tables being TIMESTAMP and TEXT. I'm working on a query that grabs all alerts (from TEXT) for the past 30 days (based on TIMESTAMP) and gives a daily average for those alerts.
Here is the query so far:
--goback 30 days start at midnight
declare #olderdate as datetime
set #olderdate = DATEADD(Day, -30, DATEDIFF(Day, 0, GetDate()))
--today at 11:59pm
declare #today as datetime
set #today = dateadd(ms, -3, (dateadd(day, +1, convert(varchar, GETDATE(), 101))))
print #today
--Grab average alerts per day over 30 days
select
avg(x.Alerts * 1.0 / 30)
from
(select count(*) as Alerts
from MESSAGE_LOG
where text like 'The process%'
and text like '%has alerted%'
and TIMESTAMP between #olderdate and #today) X
However, I want to add something that checks whether there were any alerts for a day and, if there are no alerts for that day, doesn't include it in the average. For example, if there are 90 alerts for a month but they're all in one day, I wouldn't want the average to be 3 alerts per day since that's clearly misleading.
Is there a way I can incorporate this into my query? I've searched for other solutions to this but haven't been able to get any to work.
This isn't written for your query, as I don't have any DDL or sample data, thus I'm going to provide a very simple example instead of how you would do this.
USE Sandbox;
GO
CREATE TABLE dbo.AlertMessage (ID int IDENTITY(1,1),
AlertDate date);
INSERT INTO dbo.AlertMessage (AlertDate)
VALUES('20190101'),('20190101'),('20190105'),('20190110'),('20190115'),('20190115'),('20190115');
GO
--Use a CTE to count per day:
WITH Tots AS (
SELECT AlertDate,
COUNT(ID) AS Alerts
FROM dbo.AlertMessage
GROUP BY AlertDate)
--Now the average
SELECT AVG(Alerts*1.0) AS DayAverage
FROM Tots;
GO
--Clean up
DROP TABLE dbo.AlertMessage;
You're trying to compute a double-aggregate: The average of daily totals.
Without using a CTE, you can try this as well, which is generalized a bit more to work for multiple months.
--get a list of events per day
DECLARE #Event TABLE
(
ID INT NOT NULL IDENTITY(1, 1)
,DateLocalTz DATE NOT NULL--make sure to handle time zones
,YearLocalTz AS DATEPART(YEAR, DateLocalTz) PERSISTED
,MonthLocalTz AS DATEPART(MONTH, DateLocalTz) PERSISTED
)
/*
INSERT INTO #Event(EntryDateLocalTz)
SELECT DISTINCT CONVERT(DATE, TIMESTAMP)--presumed to be in your local time zone because you did not specify
FROM dbo.MESSAGE_LOG
WHERE UPPER([TEXT]) LIKE 'THE PROCESS%' AND UPPER([TEXT]) LIKE '%HAS ALERTED%'--case insenitive
*/
INSERT INTO #Event(DateLocalTz)
VALUES ('2018-12-31'), ('2019-01-01'), ('2019-01-01'), ('2019-01-01'), ('2019-01-12'), ('2019-01-13')
--get average number of alerts per alerting day each month
-- (this will not return months with no alerts,
-- use a LEFT OUTER JOIN against a month list table if you need to include uneventful months)
SELECT
YearLocalTz
,MonthLocalTz
,AvgAlertsOfAlertingDays = AVG(CONVERT(REAL, NumDailyAlerts))
FROM
(
SELECT
YearLocalTz
,MonthLocalTz
,DateLocalTz
,NumDailyAlerts = COUNT(*)
FROM #Event
GROUP BY YearLocalTz, MonthLocalTz, DateLocalTz
) AS X
GROUP BY YearLocalTz, MonthLocalTz
ORDER BY YearLocalTz ASC, MonthLocalTz ASC
Some things to note in my code:
I use PERSISTED columns to get the month and year date parts (because I'm lazy when populating tables)
Use explicit CONVERT to escape integer math that rounds down decimals. Multiplying by 1.0 is a less-readable hack.
Use CONVERT(DATE, ...) to round down to midnight instead of converting back and forth between strings
Do case-insensitive string searching by making everything uppercase (or lowercase, your preference)
Don't subtract 3 milliseconds to get the very last moment before midnight. Change your semantics to interpret the end of a time range as exclusive, instead of dealing with the precision of your datatypes. The only difference is using explicit comparators (i.e. use < instead of <=). Also, DATETIME resolution is 1/300th of a second, not 3 milliseconds.
Avoid using built-in keywords as column names (i.e. "TEXT"). If you do, wrap them in square brackets to avoid ambiguity.
Instead of dividing by 30 to get the average, divide by the count of distinct days in your results.
select
avg(x.Alerts * 1.0 / x.dd)
from
(select count(*) as Alerts, count(distinct CAST([TIMESTAMP] AS date)) AS dd
...
I know that
count(*) - will returns the total count of all rows including nulls.
count(colName) - will returns the total count of all rows in which colName is not null.
Today one of my college got an issue with count() in SQL. He was trying to get the count of rows from a view after applying some date filter.
View Return Data structure
[Year] VARCHAR(4)
,[Month] VARCHAR(4)
,AType VARCHAR(20)
,PActualsID INT
,EID VARCHAR(12)
,CID INT
,CGId INT
,EMargin NUMERIC(17,3)
,Period DATETIME
,PLID INT
,PCID INT
,PSID INT
,VPID INT
,VSID INT
,STID INT
Query 1
SELECT * from vw_ActualAllocation_New
where EntityId = '442105' and
Period >= '01-Jan-2017' AND Period < '01-Jan-2018'
This returns around 94 records.
Query 2
SELECT Count(*) from vw_ActualAllocation_New
where EID = '442105' and
Period >= '01-Jan-2017' AND Period < '01-Jan-2018'
This returns an error
Msg 241, Level 16, State 1, Line 1 Conversion failed when converting
date and/or time from character string.
Query 3
SELECT Count(EMargin) from vw_ActualAllocation_New
where EID = '442105' and
Period >= '01-Jan-2017' AND Period < '01-Jan-2018'
This returns me count as 94.
Please note that EMargin is a NUMERIC datatype and all other types
such as int and varchar returns the same error.
Please share your thoughts on difference between these two behaviors.
SQL Server Environment: Microsoft SQL Server 2012 (Build 7601: Service Pack 1) (Hypervisor)
UPDATE - View Code
CREATE VIEW [dbo].[vw_ActualAllocation_New]
SELECT D.Year, D.Month, A.AType, A.PAID, D.EntityID, D.CustomerID
,B.CGId, SUM(A.EBITRMargin) AS EBITRMargin
,CONVERT(DATETIME,D.Month + '-01-' + D.Year) AS Period, D.PLID, D.PCID
,D.PSID, D.VPID, D.VSID,D.STID
FROM dbo.AAllocations AS A
INNER JOIN dbo.PActuals AS D ON D.PActualsID = A.PActualsID AND D.Active = 1
INNER JOIN dbo.Customer AS B ON D.CustomerID = B.CustomerID AND D.EntityID =
B.EntityID
INNER JOIN dbo.AStatus AS C ON A.ASID = C.ASID
WHERE (A.Active = 1) AND (C.Active = 1) AND (C.Reference = 'Actuals') AND
(C.Status = 1)
GROUP BY D.Year, D.Month, A.AType, A.PAID, D.EntityID, D.CustomerID, B.CGId,
D.PLID, D.PCID, D.PSID, D.VPID, D.VSID, D.STID
Update on Conclusion
Reached a conclusion as suggested by Gordon, and if you feels that you may have another thoughts, please post it here
Also I tried with the data from view, into a new table and its working fine. Issue happens while accessing directly from view. The view generation happens with lot of data and impossible to post it here because of its huge size and privacy agreements. Thanks for understanding my limitations and helping me
The most likely cause of the problem is this line of code:
CONVERT(DATETIME, D.Month + '-01-' + D.Year) AS Period
In SQL Server, you should never use CONVERT() from a string to a date without specifying the format or using standard formats (YYYYMMDD is preferred by SQL Server but I consider YYYY-MM-DD to be acceptable as well).
In older versions of SQL Server, you can do:
CONVERT(DATE, d.Year + RIGHT('00' + D.Month, 2) + '01') as period
This conversion will always work. In newer versions, use datefromparts():
DATEFROMPARTS(d.Year, d.Month, 1) as Period
Why is this happening? I speculate that the date format is being interpreted as DD-MM-YYYY instead of MM-DD-YYYY. In other words, what you think is Feb 1st is really Jan 2nd.
Further, the period values for entity '442105' all convert to a reasonable dates. The WHERE clause filters out the bad values. The problem is with other entities and the issue, as Damien points out is where the values get evaluated in the execution engine.
I need to get a count of records in an unrelated table, based on the row values in a query with some moderately complex joins. All data is on one server in a single SQL 2012 database, on several different tables.
I am recreating ticket movement history for a single ticket at a time, from audit records and need to calculate business days for the spans in rows created by the joins. Tickets are moved around between areas (ASSIGNMENT), and there are guidelines on how long it should be at any one area. The ticket may go to the same area multiple times with each time restarting the time count.
I need to consider company holidays in the business day calculations. After looking at several solutions for business day calculations on SE I decided to go with a company calendar table (dbo.UPMCCALENDARM1) and count the dates between spans. Seemed like a great idea...
I can't figure out how to use the row values as parameters for the date count query.
The query below has working solutions with a Variable and with a Cross Join, but it only works with hard coded dates, if I try to use the field values it does not work, because they are not part of the sub query and can not be bound.
-- between DV_im_Audit_ASSIGNMENT.Time and Detail.RESOLVED_TIME
In theory I could probably get there using this full query in the sub query to get the date count, but this is as short as I can make it and still get clean data. It is a pretty heavy lift for an on demand report, that would be my last option. So I want to reach out to UPMCCALENDARM1 as each occurrence of DV_im_Audit_ASSIGNMENT.Time and Detail.RESOLVED_TIME are listed.
Can it be done? If so how?
declare #NonBus integer
set #NonBus = '0'
set #NonBus = (select Count(UPMCCALENDARM1.DATE) as NonBus
from dbo.UPMCCALENDARM1
where UPMC_BUSINESS_DAY = 'f'
and UPMCCALENDARM1.DATE
between '2015-08-01' and '2015-08-31'
-- between DV_im_Audit_ASSIGNMENT.Time and Detail.RESOLVED_TIME
)
select DV_im_Audit_ASSIGNMENT.Incident_ID
, DV_im_Audit_ASSIGNMENT.Old_ASSIGNMENT
, DV_im_Audit_ASSIGNMENT.New_ASSIGNMENT
, DV_im_Audit_ASSIGNMENT.Time as Assign_Time
, B.Time as Reassign_Time
, Detail.OPEN_TIME
, Cal.NonBus
, NonBus
, Detail.RESOLVED_TIME
, A.rownumA
, B.rownumB
from dbo.DV_im_Audit_ASSIGNMENT
--Get RownumA as a select join so I can work with it here, else get an invalid column name 'rownumA' error
left join(select Incident_ID
, Old_ASSIGNMENT
, New_ASSIGNMENT
, [Time]
, rownumA = ROW_NUMBER() OVER (ORDER BY DV_im_Audit_ASSIGNMENT.Incident_ID, DV_im_Audit_ASSIGNMENT.Time)
from dbo.DV_im_Audit_ASSIGNMENT
where Incident_ID = ?
) as A
on DV_im_Audit_ASSIGNMENT.Incident_ID = A.Incident_ID
and DV_im_Audit_ASSIGNMENT.New_ASSIGNMENT = A.New_ASSIGNMENT
and DV_im_Audit_ASSIGNMENT.Time = A.Time
--Get time assigned to next group, is problomatic when assigned to the same group multiple times.
left join(select Incident_ID
, Old_ASSIGNMENT
, New_ASSIGNMENT
, [Time]
, rownumB = ROW_NUMBER() OVER (ORDER BY DV_im_Audit_ASSIGNMENT.Incident_ID, DV_im_Audit_ASSIGNMENT.Time)
from dbo.DV_im_Audit_ASSIGNMENT
where Incident_ID = ?
) as B
on DV_im_Audit_ASSIGNMENT.Incident_ID = B.Incident_ID
and DV_im_Audit_ASSIGNMENT.New_ASSIGNMENT = B.Old_ASSIGNMENT
and DV_im_Audit_ASSIGNMENT.Time < B.Time
and rownumA = (B.rownumB - 1)
--Get current ticket info
left join (select Incident_ID
, OPEN_TIME
, RESOLVED_TIME
from dbo.DV_im_PROBSUMMARYM1_Detail
where Incident_ID = ?
) as Detail
on DV_im_Audit_ASSIGNMENT.Incident_ID = Detail.Incident_ID
--Count non-bussiness days. This section is in testing and does not use dataview as a source.
-- this gets the date count for one group of dates, need a different count for each row based on assign time.
cross join (Select Count(UPMCCALENDARM1.DATE) as NonBus
from dbo.UPMCCALENDARM1
where UPMC_BUSINESS_DAY = 'f'
and UPMCCALENDARM1.DATE
between '2015-08-01' and '2015-08-30'
-- between DV_im_Audit_ASSIGNMENT.Time and Detail.RESOLVED_TIME
) as Cal
--Get data for one ticket
where DV_im_Audit_ASSIGNMENT.Incident_ID = ?
ORDER BY DV_im_Audit_ASSIGNMENT.Incident_ID, DV_im_Audit_ASSIGNMENT.Time
Results
FYI - I am running this SQL through BIRT 4.2, I believe there are few SQL items that will not pass through BIRT
Following the suggestion by #Dominique I created a custom scalar function (using the wizard in SSMS), I used default values for the dates as I had started by playing with stored procedure and that made it easier to test. This problem requires a function as it will return a value per row, where a stored procedure will not.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: James Jenkins
-- Create date: September 2015
-- Description: Counts Business Days for UPMC during a span of dates
-- =============================================
CREATE FUNCTION dbo.UPMCBusinessDayCount
(
-- Add the parameters for the function here
#StartDate date = '2015-08-01',
#EndDate date = '2015-08-31'
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE #BusDay int
-- Add the T-SQL statements to compute the return value here
SELECT #BusDay = Count(UPMCCALENDARM1.DATE)
from dbo.UPMCCALENDARM1
where UPMC_BUSINESS_DAY = 't'
and UPMCCALENDARM1.DATE between #StartDate and #EndDate
-- Return the result of the function
RETURN #BusDay
END
GO
After the function is created in the database I added these two lines to my select statement, and it works perfectly.
--Custom function counts business days on UPMCCALENDARM1
, dbo.UPMCBusinessDayCount(DV_im_Audit_ASSIGNMENT.Time, Detail.RESOLVED_TIME) as BusDay
I can use this function for any span that has date data in this (or any query on the database). I will probably be removing the default dates as well as adding a third parameter to count non-business days (UPMC_BUSINESS_DAY = 'f'). But as it is the problem is solved.
I have a table dbo.X with DateTime column Y which may have hundreds of records.
My Stored Procedure has parameter #CurrentDate, I want to find out the date in the column Y in above table dbo.X which is less than and closest to #CurrentDate.
How to find it?
The where clause will match all rows with date less than #CurrentDate and, since they are ordered descendantly, the TOP 1 will be the closest date to the current date.
SELECT TOP 1 *
FROM x
WHERE x.date < #CurrentDate
ORDER BY x.date DESC
Use DateDiff and order your result by how many days or seconds are between that date and what the Input was
Something like this
select top 1 rowId, dateCol, datediff(second, #CurrentDate, dateCol) as SecondsBetweenDates
from myTable
where dateCol < #currentDate
order by datediff(second, #CurrentDate, dateCol)
I have a better solution for this problem i think.
I will show a few images to support and explain the final solution.
Background
In my solution I have a table of FX Rates. These represent market rates for different currencies. However, our service provider has had a problem with the rate feed and as such some rates have zero values. I want to fill the missing data with rates for that same currency that as closest in time to the missing rate. Basically I want to get the RateId for the nearest non zero rate which I will then substitute. (This is not shown here in my example.)
1) So to start off lets identify the missing rates information:
Query showing my missing rates i.e. have a rate value of zero
2) Next lets identify rates that are not missing.
Query showing rates that are not missing
3) This query is where the magic happens. I have made an assumption here which can be removed but was added to improve the efficiency/performance of the query. The assumption on line 26 is that I expect to find a substitute transaction on the same day as that of the missing / zero transaction.
The magic happens is line 23: The Row_Number function adds an auto number starting at 1 for the shortest time difference between the missing and non missing transaction. The next closest transaction has a rownum of 2 etc.
Please note that in line 25 I must join the currencies so that I do not mismatch the currency types. That is I don't want to substitute a AUD currency with CHF values. I want the closest matching currencies.
Combining the two data sets with a row_number to identify nearest transaction
4) Finally, lets get data where the RowNum is 1
The final query
The query full query is as follows;
; with cte_zero_rates as
(
Select *
from fxrates
where (spot_exp = 0 or spot_exp = 0)
),
cte_non_zero_rates as
(
Select *
from fxrates
where (spot_exp > 0 and spot_exp > 0)
)
,cte_Nearest_Transaction as
(
select z.FXRatesID as Zero_FXRatesID
,z.importDate as Zero_importDate
,z.currency as Zero_Currency
,nz.currency as NonZero_Currency
,nz.FXRatesID as NonZero_FXRatesID
,nz.spot_imp
,nz.importDate as NonZero_importDate
,DATEDIFF(ss, z.importDate, nz.importDate) as TimeDifferece
,ROW_NUMBER() Over(partition by z.FXRatesID order by abs(DATEDIFF(ss, z.importDate, nz.importDate)) asc) as RowNum
from cte_zero_rates z
left join cte_non_zero_rates nz on nz.currency = z.currency
and cast(nz.importDate as date) = cast(z.importDate as date)
--order by z.currency desc, z.importDate desc
)
select n.Zero_FXRatesID
,n.Zero_Currency
,n.Zero_importDate
,n.NonZero_importDate
,DATEDIFF(s, n.NonZero_importDate,n.Zero_importDate) as Delay_In_Seconds
,n.NonZero_Currency
,n.NonZero_FXRatesID
from cte_Nearest_Transaction n
where n.RowNum = 1
and n.NonZero_FXRatesID is not null
order by n.Zero_Currency, n.NonZero_importDate