How to get last 3 distinct prices based on a date column? - sql

I have a table which contains these columns;
CODE
PRICE
DATE
So what i want to do is to get last 3 distinct price values per id ordered by date column. Basically the most recent 3 distinct prices per id.
Also there is an ID column in the table. It is the primary key of the table.
Edit: As ughai said, DISTINCT doesn't work with row_number.

Select t.id , c.Price
from TableName t
CROSS APPLY (
SELECT TOP 3 Price
FROM TableName s
WHERE s.ID = t.ID
ORDER BY [DATE] DESC
) c (Price)
GROUP BY t.id , c.Price

Related

Get Max data against a ts and total count of record in single join query - POSTGRES

I have 2 tables with a foreign key. I have to get the counts of all the records in right table and the threshold value of max ts in right table.
TABLE alarm
column
Datatype
id
PK
name
varchar
TABLE alarm_data
column
Datatype
alarm_id
FK
ts
timestamp
value
int
I have to get total count of alarm_data associated with an alarm_id and the value of alarm_data with latest ts.
The expected output is
alarm_id
ts
occurance_count
1
123456
2
Queries I have used is
https://www.db-fiddle.com/f/4jyoMCicNSZpjMt4jFYoz5/7351
It is always returning multiple records as I have to add alarm_data.value in group by. It should only return 1 record with value and occurence count.
You can do it using group by to get count() and max(ts):
select a.id as alarm_id, max(ad.ts) as ts, count(1) as occurance_count
from alarm a
inner join alarm_data as ad on a.id = ad.alarm_id
group by a.id
You could use the row_number function to get the value of alarm_data with the latest ts, and the count window function to get the total count of alarm_data associated with an alarm_id.
select A.id,
A.name,
D.ts,
D.cn as occurance_count,
D.value
from alarm A join
(
select *, count(*) over (partition by alarm_id) cn,
row_number() over (partition by alarm_id order by ts desc) rn
from alarm_data
) D
on A.id = D.alarm_id
where D.rn = 1
See demo

SQLite query with LIMIT per column

I am trying to compose a query with a where condition to get multiple unique sorted columns without having to do it in multiple queries. That is confusing so here is an example...
Price Table
id | item_id | date | price
I want to query to find the most recent price of multiple items given a date. I was previously iterating through items in my application code and getting the most recent price like this...
SELECT * FROM prices WHERE item_id = ? AND date(date) < date(?) ORDER BY date(date) DESC LIMIT 1
Iterating through each item and doing a query is too slow so I am wondering if there is a way I can accomplish this same query for multiple items in one go. I have tried UNION but I cannot get it to work with the ORDER BY and LIMIT commands like this thread says (https://stackoverflow.com/a/1415380/4400804) for MySQL
Any ideas on how I can accomplish this?
Try this (based on adapting the answer):
SELECT * FROM prices a WHERE a.RowId IN (
SELECT b.RowId
FROM prices b
WHERE a.item_id = b.item_id AND date < ?
ORDER BY b.item_id LIMIT 1
) ORDER BY date DESC;
Window functions (Available with sqlite 3.25 and newer) will likely help:
WITH ranked AS
(SELECT id, item_id, date, price
, row_number() OVER (PARTITION BY item_id ORDER BY date DESC) AS rn
FROM prices
WHERE date < ?)
SELECT id, item_id, date, price
FROM ranked
WHERE rn = 1
ORDER BY item_id;
will return the most recent of each item_id from all records older than a given date.
I would simply use a correlated subquery in the `where` clause:
SELECT p.*
FROM prices p
WHERE p.DATE = (SELECT MAX(p2.date)
FROM prices p2
WHERE p2.item_id = p.item_id
);
This is phrase so it works on all items. You can, of course, add filtering conditions (in the outer query) for a given set of items.
With NOT EXISTS:
SELECT p.* FROM prices p
WHERE NOT EXISTS (
SELECT 1 FROM prices
WHERE item_id = p.item_id AND date > p.date
)
or with a join of the table to a query that returns the last date for each item_id:
SELECT p.*
FROM prices p INNER JOIN (
SELECT item_id, MAX(date) date
FROM prices
GROUP BY item_id
) t ON t.item_id = p.item_id AND t.date = p.date

Select customer with highest price of all his orders

i want to list customer id with highest sum of price of his orders. Please see graph oí orders down.
SQL DEMO
SELECT *
FROM (
SELECT "customerid", SUM("price")
FROM Orders
GROUP BY "customerid"
ORDER BY SUM("price") DESC
) T
WHERE ROWNUM <= 1
You need to group by customer_id to get all prices of each customers.
Then sum these prices filter it with max( sum(price))or get first row by descending order of sum(price).
--for Oracle
select * from (Select c.name,c.id,sum(o.price) from Customer c
inner join order o on o.customer_id=c.id
group by c.name,c.id
order by sum(o.price)desc
)where rownum =1
--For sql server and mysql
Select top 1 c.name,c.id,sum(o.price) from Customer c
inner join order o on o.customer_id=c.id
group by c.name,c.id
order by sum(o.price)desc

Efficient way to combine 2 tables and get the row with max year with preference to one of the table

I am trying to combine 2 tables (key_ratios_cnd and key_ratios_snd) both tables are identical and primary key columns for both tables are symbol and fiscal_year.
In the final result set i want the row with maximum year in both the tables for each symbol. if the row with maximum year is present in both the tables then row from key_ratios_cnd should be selected.
I come up with below SQL query to give the result. I wanted to know if their are any other way to write the query that is more optimized.
select sq2.*
from
(select sq.*,
max(id) over(partition by sq.symbol) as max_id,
max(fiscal_year) over(partition by sq.symbol) as max_year
from
( select *,'2' as id
from test.key_ratios_cnd
union all
select *,'1' as id
from test.key_ratios_snd
) as sq
) as sq2
where id = max_id and fiscal_year = max_year
order by symbol asc
I would select a row from each table first and then combine. Postgres has distinct on which is perfect for this purpose.
select distinct on (symbol) sc.*
from ((select distinct on (cnd.symbol) cnd.*, 1 as ord
from test.key_ratios_cnd cnd
order by cnd.symbol, cnd.fiscal_year desc
) union all
(select distinct on (snd.symbol) cnd.*, 2 as ord
from test.key_ratios_cnd cnd
order by snd.symbol, snd.fiscal_year desc
)
) sc
order by symbol, fiscal_year desc, ord;
To speed this up, add an index on (symbol, fiscal_year desc) to each table.

sql : Select value based on values from other columns

I have a column for price. I need to select the price based on another column called status. If status is p then select that price first else select price from other status h. I need to make sure that query selects the price if status is p first when both status P & h are available.
You can use Rank function (if your DBMS supports), which will group the rows based on product and rank the sub group rows based on status. then you can apply where clause to select first rank rows from each sub-group. the query will look like below for MS sql-server.
select price
, [status]
, product
from
(select price
, [status]
, product
, RANK() over (PARTITION BY product
order by case
when [status]='p' then 1
else 0
end desc
) as rnk
from #tableA) Q
where rnk =1
Sample Input
Output