"First order by" in Teradata - sql

I have a problem converting SQL statement from Oracle to Teradata. In Oracle statement is that:
SELECT ar.account_no,
MAX (ah.bal_acct) KEEP (DENSE_RANK FIRST ORDER BY ah.created_t desc)
FROM ar
JOIN ah ON ah.obj_id0 = ar.poid_Id0
JOIN acc ON a.poid_id0 = ar.account_obj_Id0
WHERE acc.account_no = '1234'
AND ah.created_t <= 1434753495
GROUP BY ar.account_no
I need to do similar statement in Teradata. I tried something with
QUALIFY ROW_NUMBER() OVER( PARTITION BY max(ah.bal_acct) ORDER BY ah.created_t desc) = 1
But all the time I have error: Selected non-aggregate values must be part of the associated group.
This is what I got:
Select ar.account_no, ah.created_t, ah.bal_acct
FROM VD_REPLICA_BRM.pi_tp_acct_ar_t ar
JOIN VD_REPLICA_BRM.pi_tp_acct_ar_hist_T ah ON ah.obj_id0 = ar.poid_Id0
JOIN VD_REPLICA_BRM.pi_account_t acc ON acc.poid_id0 = ar.account_obj_Id0
WHERE acc.account_no = '00003095660515'
AND ah.created_t <= CAST('2016-10-31' AS DATE FORMAT 'YYYY-MM-DD')
QUALIFY ROW_NUMBER() OVER( PARTITION BY max(ah.bal_acct) ORDER BY ah.created_t desc) = 1
GROUP BY ar.account_no
Where do I do mistake?

I'm not sure if you can do this with qualify. An equivalent statement is:
SELECT ar.account_no, ah.created_t, ah.bal_acct
FROM (SELECT ar.account_no, ah.created_t, ah.bal_acct,
ROW_NUMBER() OVER (PARTITION BY ar.account_no ORDER BY ah.created_t DESC) as seqnum
FROM ar JOIN
ah
ON ah.obj_id0 = ar.poid_Id0 JOIN
acc
ON a.poid_id0 = ar.account_obj_Id0
WHERE acc.account_no = '1234' AND ah.created_t <= 1434753495
) t
WHERE seqnum = 1;
Duh. You can do this with QUALIFY. The issue is the GROUP BY:
SELECT ar.account_no, ah.created_t, ah.bal_acct
FROM VD_REPLICA_BRM.pi_tp_acct_ar_t ar JOIN
VD_REPLICA_BRM.pi_tp_acct_ar_hist_T ah
ON ah.obj_id0 = ar.poid_Id0 JOIN
VD_REPLICA_BRM.pi_account_t acc
ON acc.poid_id0 = ar.account_obj_Id0
WHERE acc.account_no = '00003095660515' AND
ah.created_t <= CAST('2016-10-31' AS DATE FORMAT 'YYYY-MM-DD')
QUALIFY ROW_NUMBER() OVER( PARTITION BY ar_account_no ORDER BY ah.created_t desc) = 1

Related

Select only observations with a date more recent than the 30/6/2021 (dd/mm/yyyy)

I have the following code:
Select Tbl.Fromdate, Tbl.Por, Tbl.Porname, Tbl.Bmref3
From(
Select
To_Char(P.Fromdate, 'dd-mm-yyyy') As Fromdate, P.Por, P.Porname, W.Bmref3,
, RANK() OVER (PARTITION BY P.Por ORDER BY P.fromdate DESC) AS rank
From Tmsdat.Climandatecomps W
Inner Join Tmsdat.Portfolios P On (W.Porik = P.Porik)
Where 1=1
) Tbl
Where 1=1
And Tbl.Rank = 1
;
However, I wish to select only the observations that have a Fromdate more recent than the June 30, 2021. I tried to add Tbl.Fromdate> '30-06-2021' to the WHERE clause, but I did not receive the desired results.
Do you have any suggestions?
Thank you in advance.
Best regards,
You would put the condition in the inner query:
Select To_Char(P.Fromdate, 'dd-mm-yyyy') As Fromdate, P.Por, P.Porname, W.Bmref3,
RANK() OVER (PARTITION BY P.Por ORDER BY P.fromdate DESC) AS rank
From Tmsdat.Climandatecomps W inner join
Tmsdat.Portfolios P
On (W.Porik = P.Porik)
Where p.FromDate > date '2021-06-30'

calculate time difference of consecutive row dates in SQL

Hello I am trying to calculate the time difference of 2 consecutive rows for Date (either in hours or Days), as attached in the image
Highlighted in Yellow is the result I want which is basically the difference of the date in that row and 1 above.
How can we achieve it in the SQL? Attached is my complex code which has the rest of the fields in it
with cte
as
(
select m.voucher_no, CONVERT(VARCHAR(30),CONVERT(datetime, f.action_Date, 109),100) as action_date,f.col1_Value,f.col3_value,f.col4_value,f.comments,f.distr_user,f.wf_status,f.action_code,f.wf_user_id
from attdetailmap m
LEFT JOIN awftaskfin f ON f.oid = m.oid and f.client ='PC'
where f.action_Date !='' and action_date between '$?datef' and '$?datet'
),
.*select *, ROW_NUMBER() OVER(PARTITION BY action_Date,distr_user,wf_Status,wf_user_id order by action_Date,distr_user,wf_Status,wf_user_id ) as row_no_1 from cte
cte2 as
(
select *, ROW_NUMBER() OVER(PARTITION BY voucher_no,action_Date,distr_user,wf_Status,wf_user_id order by voucher_no ) as row_no_1 from cte
)
select distinct(v.dim_value) as resid,c.voucher_no,CONVERT(datetime, c.action_Date, 109) as action_Date,c.col4_value,c.comments,c.distr_user,v.description,c.wf_status,c.action_code, c.wf_user_id,v1.description as name,r.rel_value as pay_office,r1.rel_value as site
from cte2 c
LEFT OUTER JOIN aagviuserdetail v ON v.user_id = c.distr_user
LEFT OUTER JOIN aagviuserdetail v1 ON v1.user_id = c.wf_user_id
LEFT OUTER JOIN ahsrelvalue r ON r.resource_id = v.dim_Value and r.rel_Attr_id = 'P1' and r.period_to = '209912'
LEFT OUTER JOIN ahsrelvalue r1 ON r1.resource_id = v.dim_Value and r1.rel_Attr_id = 'Z1' and r1.period_to = '209912'
where c.row_no_1 = '1' and r.rel_value like '$?site1' and voucher_no like '$?trans'
order by voucher_no,action_Date
The key idea is lag(). However, date/time functions vary among databases. So, the idea is:
select t.*,
(date - lag(date) over (partition by transaction_no order by date)) as diff
from t;
I should note that this exact syntax might not work in your database -- because - may not even be defined on date/time values. However, lag() is a standard function and should be available.
For instance, in SQL Server, this would look like:
select t.*,
datediff(second, lag(date) over (partition by transaction_no order by date), date) / (24.0 * 60 * 60) as diff_days
from t;

SQL DISTINCT Column with 2nd Criteria as datetime

I have on just started learning SQL in SQL Server Management Studio and getting thrown into the deep end.
I just need unique DriverID that has a LogoffTime in the last 3 month, with the headings included below.
What I have so far:
SELECT
Dr.DriverName, Dr.DriverNumber, Dr.DriverID,
DL.DriverID, DL.LogoffTime,
ROW_NUMBER() OVER (PARTITION BY DL.DriverID ORDER BY DL.LogoffTime DESC) AS rn
FROM
Taxihistory.dbo.DriverLogon DL, Taxihistory.dbo.Driver Dr
WHERE
DL.DriverID = Dr.DriverID
AND DL.LogoffTime <= '20180931'
AND rn = 1
ORDER BY
DL.LogoffTime DESC;
I am currently getting this error:
Msg 207, Level 16, State 1, Line 7
Invalid column name 'rn'
In case you want to explore CTE (Common Table Expression) option, you may also be able to achieve this with CTE. You can try something like below:
WITH CTE AS (
SELECT dr.drivername,
dr.drivernumber,
dr.driverid,
dl.logofftime,
row_number() OVER (PARTITION BY dl.driverid
ORDER BY dl.logofftime DESC) AS rn
FROM taxihistory.dbo.driverlogon dl
INNER JOIN taxihistory.dbo.driver dr
ON dr.driverid = dl.driverid
WHERE dl.logofftime <= Convert(datetime, '2018-09-30') )
SELECT tbl.drivername,
tbl.drivernumber,
tbl.driverid,
tbl.logofftime
FROM CTE tbl
WHERE tbl.rn = 1
ORDER BY tbl.logofftime DESC;
You cannot use column aliases in the WHERE clause. Neither can you use row_number() there. You have to wrap the query with the row_number() in a subquery and select from that.
SELECT x.drivername,
x.drivernumber,
x.driverid,
x.logofftime
FROM (SELECT dr.drivername,
dr.drivernumber,
dr.driverid,
dl.logofftime,
row_number() OVER (PARTITION BY dl.driverid
ORDER BY dl.logofftime DESC) rn
FROM taxihistory.dbo.driverlogon dl
INNER JOIN taxihistory.dbo.driver dr
ON dr.driverid = dl.driverid
WHERE dl.logofftime <= '20180930') x
WHERE x.rn = 1
ORDER BY x.logofftime DESC;
It is also advisable to use explicit join syntax. And I do hope, that driverlogon.logofftime is not an [n][var]char but some date/time type.
You should get the logon from the last 3 months up to the current date by doing so:
SELECT Dr.DriverName, Dr.DriverNumber, Dr.DriverID, DL.DriverID, DL.LogoffTime
FROM Taxihistory.dbo.DriverLogon DL,
INNER JOIN Taxihistory.dbo.Driver Dr ON DL.DriverID = Dr.DriverID
WHERE DL.LogOffTime < DATEADD(MONTH, -3, GETDATE())
ORDER BY DL.LogoffTime DESC;

Bad performance with sql query

I have a snippet of SQL that compared the last two records and gives the datediff in seconds, however the way I have it is quite slow taking up to 20 seconds to execute depending how many controllerID's I needs to check.
What would be a more efficient way of do doing this?
select
T.controllerID,
datediff(ss, T.Max_dtReading, T1.Max_dtReading) As ElaspedTime
from
(select
controllerID,
max(dtReading) as Max_dtReading
from
ReaderData
where
CardID = 'FFFFFFF0' AND (controllerID in(2,13,28,30,37,40))
group by
controllerID) as T
outer apply
(select
max(T1.dtReading) as Max_dtReading
from
ReaderData as T1
where
T1.CardID = 'FFFFFFF0' AND (controllerID in(2,13,28,30,37,40))
and T1.controllerID = T.controllerID
and T1.dtReading < T.Max_dtReading) as T1
I might suggest conditional aggregation for this:
select controllerID,
datediff(second, max(dtReading), min(dtReading)
) As ElaspedTime
from (select controllerID, dtReading,
row_number() over (partition by controllerID order by dtReading desc) as seqnum
from ReaderData
where CardID = 'FFFFFFF0' AND
controllerID in (2, 13, 28, 30, 37, 40)
) r
where seqnum <= 2
group by controllerID
You can use ROW_NUMBER() in order to locate the records with the 2 highest dtReading values, then join these together to calculate the difference:
;WITH CTE AS (
SLEECT controllerID, dtReading,
ROW_NUMBER() OVER (PARTITION BY controllerID
ORDER BY dtReading DESC) AS rn
FROM ReaderData
WHERE CardID = 'FFFFFFF0' AND (controllerID IN (2,13,28,30,37,40))
)
SELECT c1.controllerID,
DATEDIFF(ss, c1.dtReading, c2.dtReading) AS ElaspedTime
FROM CTE c1
INNER JOIN CTE c2 ON (c1.controllerID = c2.controllerID)
AND c1.rn = 1 AND c2.rn = 2
;WITH CTE AS
(select controllerID
,dtReading
,ROW_NUMBER() OVER (PARTITION BY controllerID ORDER BY dtReading DESC) rn
from ReaderData
where CardID = 'FFFFFFF0'
AND controllerID IN (2,13,28,30,37,40)
)
select C1.controllerID
,datediff(ss, C1.dtReading, C2.dtReading) As ElaspedTime
from CTE C1
LEFT JOIN CTE C2 ON C1.controllerID = C2.controllerID
AND C1.rn = 1
AND C1.rn < C2.rn

Return first result only for each unique result

I am having some trouble with duplicating results in SQL Server 2005. I have previously used the ROW NUMBER function to display my query results, but I cannot get the query below to only display rownum 1:
SELECT *
FROM (SELECT l.insbilleddate, l.pickupdate, l.patientname, l.inscompanyname AS Payor, l.tripid,
l.sales, l.cost, l.sales-l.cost AS Profit, l.profitpct AS 'Profit Pct', u.pUPFName + ' ' +
u.pUPLName AS Dispatcher, ROW_NUMBER() OVER (PARTITION BY l.tripid ORDER BY d.trDispatchDate
ASC) AS rownum
FROM pUsersPrinters u
INNER JOIN TranslationDispatch d
INNER JOIN v_OLAPdataTR l ON d.trTripid = l.tripid ON u.pUP_id = d.trDispatchedBy
GROUP BY l.insbilleddate, l.pickupdate, l.patientname, l.inscompanyname, l.tripid, l.sales,
l.cost, l.profitpct, u.pUPFName, u.pUPLName, d.trDispatchDate
HAVING l.insbilleddate >= '6/1/2014' And l.insbilleddate < '7/1/2014' AND l.cost > '0' AND
l.profitpct < '30') q1
WHERE rownum = 1
ORDER BY q1.profitpct
The TranslationDispatch table adds a line each time a user dispatches a trip. If a trip needs to be reassigned the database does not overwrite the original dispatcher, instead it adds another line with the userID, tripID, and dispatch date. The d.trTripid = l.tripid comparison causes the trip to show for each dispatcher that marks it.
As an example, results show as:
TripID trDispatchedBy trDispatchDate
1234 Carlos 6/25/2014 10:00
1234 Tim 6/25/2014 10:02
...but I only want to display Carlos, as he dispatched the trip first.
EDIT: I've adjusted the query above with the help of #Vulcronos to make it work, by adding a table alias (q1) and making the rownum = '1' into rownum = 1 to correctly display my final result.
I would try:
ROW_NUMBER () OVER ( PARTITION BY l.insbilleddate, l.pickupdate, l.patientname,
l.inscompanyname, l.tripid, l.sales, l.cost, l.profitpct, u.pUPFName, u.pUPLName,
d.trDispatchDate ORDER BY trDispatchDate ASC)
This should give you a row number of one on every groups earliest dispatch date. Then you can wrap your whole query in:
select *
from (my_query)
where rownum = 1
How about adding "TOP 1" to the outside query
SELECT TOP 1 *
FROM(SELECT L.Insbilleddate,
L.Pickupdate,
L.Patientname,
L.Inscompanyname AS Payor,
L.Tripid,
L.Sales,
L.Cost,
L.Sales - L.Cost AS Profit,
L.Profitpct AS 'Profit Pct',
U.Pupfname + ' ' + U.Puplname AS Dispatcher,
ROW_NUMBER()OVER(PARTITION BY L.Tripid ORDER BY D.Trdispatchdate ASC)AS Rownum
FROM Pusersprinters U
INNER JOIN Translationdispatch D
INNER JOIN V_Olapdatatr L ON D.Trtripid = L.Tripid ON U.Pup_Id = D.Trdispatchedby
GROUP BY L.Insbilleddate,
L.Pickupdate,
L.Patientname,
L.Inscompanyname,
L.Tripid,
L.Sales,
L.Cost,
L.Profitpct,
U.Pupfname,
U.Puplname,
D.Trdispatchdate
HAVING L.Insbilleddate >= '6/1/2014'
AND L.Insbilleddate < '7/1/2014'
AND L.Cost > '0'
AND L.Profitpct < '30') A
ORDER BY A.Profitpct;