Add ROW_NUMBER() function to SQL query - sql

I have the following query:
select
DISTINCT(b.org),
b.env,
b.proxy,
b."type",
b.name,
b.policytype,
b.disabled,
b."report refresh date",
b.rank,
first_value(LOWER(a."value"))
over(partition by
b.org,
b.env,
b.proxy
order by b."report refresh date" desc
rows between unbounded preceding and unbounded following) as "value"
from
(select *, DENSE_RANK() OVER (ORDER BY "report refresh date" DESC) as rank from infosec.apigee_policy_info_for_proxy) b
left join
(select * from api.apigee_product
where attribute = 'tui-api-domain') a
on a.org = b.org
and a.env = b.env
and a.proxy = b.proxy
where b.rank <=60
group by b.org,
b.env,
b.proxy,
b."type",
b.name,
b.policytype,
b.disabled,
b."report refresh date",
b.rank,
a."value"
and need to add a function in the end of the above query that calculates the row number.
For that I have the following query:
ROW_NUMBER() over (order by "report refresh date" ASC) as rowid
I'm having problems on where to put it, in the first query showned.
Can someone help?
Thank you.

I would simplify this query as :
select distinct b.org, b.env, b.proxy, b.type,b.name,
b.policytype, b.disabled, b."report refresh date", b.rank,
first_value(LOWER(a."value"))
over(partition by b.org, b.env, b.proxy order by b."report refresh date" desc
rows between unbounded preceding and unbounded following) as "value",
ROW_NUMBER() over (order by "report refresh date" ASC) as rowid
from (select *, DENSE_RANK() OVER (ORDER BY "report refresh date" DESC) as rank
from infosec.apigee_policy_info_for_proxy
) b left join
api.apigee_product a
on a.org = b.org and
a.env = b.env and
a.proxy = b.proxy and
a.attribute = 'tui-api-domain'
where b.rank <= 60;
Note : DISTINCT is not function so, removed (). Use LEFT JOIN directly instead of subquery.

Related

ETL query need some changes go get it right

Hello guys I have a query which is working but when I remove 2 filters (2 where clauses at the end doesn't work as expected but still have to be removed from the query)
I have accounts 1000001,1000002,1000003,1000004 and 1000005
I only get 1000005 accounts, Pretty sure that it`s is about the window MAX function, but still.
I want to get the all values for the accounts.
SELECT a12.month_id,
a12.populate_id AS account_id,
LAST_VALUE(current_bal IGNORE NULLS) OVER
(PARTITION BY Populate_id ORDER BY date_id ASC ROWS
BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS avg_dly_bal
FROM (SELECT TO_CHAR(date_id, 'YYYYMM') AS month_id,
date_id,
account_id AS "account_id",
MAX(account_id) OVER (PARTITION by TO_CHAR(date_id, 'YYYYMM')) as populate_id,
current_bal
FROM (SELECT t.date_id, ad.account_id, ad.current_bal
FROM timedate t
FULL OUTER JOIN (SELECT src_extract_dt, account_id, current_bal
FROM account_dly
WHERE account_id = 1000001) ad
on t.date_id = ad.src_extract_dt
WHERE TO_CHAR(date_id, 'YYYYMM') = '201908'
order by t.date_id)) a12;
https://i.stack.imgur.com/xphVh.png

I need to write a query to mark previous record as “Not eligible ” if a new record comes in within 30 days with same POS Order ID

I have a requirement to write a query to retrieve the records which have POS_ORDER_ID in the table with same POS_ORDER_ID which comes within 30days as new record with status 'Canceled', 'Discontinued' and need to mark previous POS_ORDER_ID record as it as not eligible
Table columns:
POS_ORDER_ID,
Status,
Order_date,
Error_description
A query containing MAX() and ROW_NUMBER() analytic functions might help you such as :
with t as
(
select t.*,
row_number() over (partition by pos_order_id order by Order_date desc ) as rn,
max(Order_date) over (partition by pos_order_id) as mx
from tab t -- your original table
)
select pos_order_id, Status, Order_date, Error_description,
case when rn >1
and t.status in ('Canceled','Discontinued')
and mx - t.Order_date <= 30
then
'Not eligible'
end as "Extra Status"
from t
Demo
Please use below query,
Select and validate
select POS_ORDER_ID, Status, Order_date, Error_description, row_number()
over(partition by POS_ORDER_ID order by Order_date desc)
from table_name;
Update query
merge into table_name t1
using
(select row_id, POS_ORDER_ID, Status, Order_date, Error_description,
row_number() over(partition by POS_ORDER_ID order by Order_date desc) as rnk
from table_name) t2
on (t1.POS_ORDER_ID = t2.POS_ORDER_ID and t1.row_id = t2.row_id)
when matched then
update
set
case when t2.rnk = 1 then 'Canceled' else 'Not Eligible';

How to get the validity date range of a price from individual daily prices in SQL

I have some prices for the month of January.
Date,Price
1,100
2,100
3,115
4,120
5,120
6,100
7,100
8,120
9,120
10,120
Now, the o/p I need is a non-overlapping date range for each price.
price,from,To
100,1,2
115,3,3
120,4,5
100,6,7
120,8,10
I need to do this using SQL only.
For now, if I simply group by and take min and max dates, I get the below, which is an overlapping range:
price,from,to
100,1,7
115,3,3
120,4,10
This is a gaps-and-islands problem. The simplest solution is the difference of row numbers:
select price, min(date), max(date)
from (select t.*,
row_number() over (order by date) as seqnum,
row_number() over (partition by price, order by date) as seqnum2
from t
) t
group by price, (seqnum - seqnum2)
order by min(date);
Why this works is a little hard to explain. But if you look at the results of the subquery, you will see how the adjacent rows are identified by the difference in the two values.
SELECT Lag.price,Lag.[date] AS [From], MIN(Lead.[date]-Lag.[date])+Lag.[date] AS [to]
FROM
(
SELECT [date],[Price]
FROM
(
SELECT [date],[Price],LAG(Price) OVER (ORDER BY DATE,Price) AS LagID FROM #table1 A
)B
WHERE CASE WHEN Price <> ISNULL(LagID,1) THEN 1 ELSE 0 END = 1
)Lag
JOIN
(
SELECT [date],[Price]
FROM
(
SELECT [date],Price,LEAD(Price) OVER (ORDER BY DATE,Price) AS LeadID FROM [#table1] A
)B
WHERE CASE WHEN Price <> ISNULL(LeadID,1) THEN 1 ELSE 0 END = 1
)Lead
ON Lag.[Price] = Lead.[Price]
WHERE Lead.[date]-Lag.[date] >= 0
GROUP BY Lag.[date],Lag.[price]
ORDER BY Lag.[date]
Another method using ROWS UNBOUNDED PRECEDING
SELECT price, MIN([date]) AS [from], [end_date] AS [To]
FROM
(
SELECT *, MIN([abc]) OVER (ORDER BY DATE DESC ROWS UNBOUNDED PRECEDING ) end_date
FROM
(
SELECT *, CASE WHEN price = next_price THEN NULL ELSE DATE END AS abc
FROM
(
SELECT a.* , b.[date] AS next_date, b.price AS next_price
FROM #table1 a
LEFT JOIN #table1 b
ON a.[date] = b.[date]-1
)AA
)BB
)CC
GROUP BY price, end_date

getting difference between two invoices by ranking and subtracting one from the other

Trying to grab difference in invoices
Attempted using cte's for ranks 1 and 2, but they have a subquery in them and cant be done!
the second query looks the same, but with rank=2.
select *
from (
SELECT i.id, i.subtotal/100 as subtotal, i.created_at, i.paid_at
,RANK() OVER (PARTITION BY i.subscription_id ORDER BY i.created_at DESC) AS Rank
From Invoices i
) as r
where r.rank = 1
order by r.created_at desc;
Following the path that you are on (using row_number()/rank()), you can use conditional aggregation. Assuming you want the difference of the subtotal, then:
select sum(case when seqnum = 1 then subtotal
else - subtotal
end) as difference
from (select i.*, i.subtotal/100 as subtotal,
row_number() over (partition by i.subscription_id order by i.created_at desc) as seqnum
from Invoices i
) i
where seqnum in (1, 2)
order by r.created_at desc;

Getting the value of a previous record using ROW_NUMBER() in SQL Server

Hopefully this is easy enough for those more experienced in SQL Server.
I have a table to customer loan activity data which is updated whenever an action happens on their account. For example if their limit is increased, a new record will be created with their new limit. I want to be able to create a listing of their activity where the activity amount is their new limit subtracting whatever their previous limit was.
At the moment I have the following but I'm struggling to work out how to access that previous record.
SELECT
CUSTOMER
,LEDGER
,ACCOUNT
,H.AMOUNT - COALESCE(X.AMOUNT, 0)
FROM
dbo.ACTIVITY H WITH (NOLOCK)
LEFT OUTER JOIN
(SELECT
CUSTOMER
,LEDGER
,ACCOUNT
,ACTIVITY_DATE
,AMOUNT
,ROW_NUMBER() OVER (PARTITION BY CUSTOMER, LEDGER, ACCOUNT ORDER BY ACTIVITY_DATE ASC) AS ROW_NUMBER
FROM
dbo.ACTIVITY WITH (NOLOCK)) X ON H.CUSTOMER = X.CUSTOMER
AND H.LEDGER = X.LEDGER
AND H.ACCOUNT = X.ACCOUNT
So basically I only want to subtract x.amount if it's the previous record but I'm not sure how to do this when I don't know what day it happened.
I thought Row_Number() would help me but I'm still a bit stumped.
Hope you hear from you all soon :)
Cheers
Here's a query that will only pass through dbo.Activity ONCE
SELECT H.CUSTOMER
,H.LEDGER
,H.ACCOUNT
,MAX(H.ACTIVITY_DATE) ACTIVITY_DATE
,SUM(CASE X.I WHEN 1 THEN AMOUNT ELSE -AMOUNT END) AMOUNT
FROM (SELECT CUSTOMER
,LEDGER
,ACCOUNT
,ACTIVITY_DATE
,AMOUNT
,ROW_NUMBER() OVER (PARTITION BY CUSTOMER, LEDGER, ACCOUNT ORDER BY ACTIVITY_DATE DESC) AS ROW_NUMBER
FROM dbo.ACTIVITY WITH (NOLOCK)
) H
CROSS JOIN (select 1 union all select 2) X(I)
WHERE ROW_NUMBER - X.I >= 0
GROUP BY H.CUSTOMER
,H.LEDGER
,H.ACCOUNT
,ROW_NUMBER - X.I;
And here's the DDL/DML for some data I used to test
CREATE TABLE dbo.ACTIVITY(CUSTOMER int, LEDGER int, ACCOUNT int, ACTIVITY_DATE datetime, AMOUNT int)
INSERT dbo.ACTIVITY select
1,2,3,GETDATE(),123 union all select
1,2,3,GETDATE()-1,16 union all select
1,2,3,GETDATE()-2,12 union all select
1,2,3,GETDATE()-3,1 union all select
4,5,6,GETDATE(),1000 union all select
4,5,6,GETDATE()-6,123 union all select
7,7,7,GETDATE(),99;
Alternatives
A more traditional approach using a subquery to get the previous row:
SELECT CUSTOMER, LEDGER, ACCOUNT, ACTIVITY_DATE,
AMOUNT - ISNULL((SELECT TOP(1) I.AMOUNT
FROM dbo.ACTIVITY I
WHERE I.CUSTOMER = O.CUSTOMER
AND I.LEDGER = O.LEDGER
AND I.ACCOUNT = O.ACCOUNT
AND I.ACTIVITY_DATE < O.ACTIVITY_DATE
ORDER BY I.ACTIVITY_DATE DESC), 0) AMOUNT
FROM dbo.ACTIVITY O
ORDER BY CUSTOMER, LEDGER, ACCOUNT, ACTIVITY_DATE;
Or ROW_NUMBER() the data twice and join between them
SELECT A.CUSTOMER, A.LEDGER, A.ACCOUNT, A.ACTIVITY_DATE,
A.AMOUNT - ISNULL(B.AMOUNT,0) AMOUNT
FROM (SELECT *, RN=ROW_NUMBER() OVER (partition by CUSTOMER, LEDGER, ACCOUNT
order by ACTIVITY_DATE ASC)
FROM dbo.ACTIVITY) A
LEFT JOIN (SELECT *, RN=ROW_NUMBER() OVER (partition by CUSTOMER, LEDGER, ACCOUNT
order by ACTIVITY_DATE ASC)
FROM dbo.ACTIVITY) B ON A.CUSTOMER = B.CUSTOMER
AND A.LEDGER = B.LEDGER
AND A.ACCOUNT = B.ACCOUNT
AND B.RN = A.RN-1 -- prior record
ORDER BY A.CUSTOMER, A.LEDGER, A.ACCOUNT, A.ACTIVITY_DATE;