SELECT DISTINCT not ordering correctly - sql

I have the following SQL statement:
SELECT DISTINCT ON (watch.url)
watch.url, watch.name, user_url.frequency, watch.selector, price.date
FROM watch
JOIN user_url on user_url.url = watch.url
LEFT JOIN price on price.url = watch.url
WHERE (1400575234 > price.date + user_url.frequency)
OR price.date is null
ORDER BY watch.url, price.date DESC
Where 1400575234 is the current unix timestamp. The table price holds the price of an item at different time intervals, one per row.
Currently this query will return me all the items because at some point they have had an entry which is less than the current date. Whereas I am only looking at grabbing the URL's whose price.date is less than the current time but I only want to match against the highest date for the url in the price table.
I think I need to run the order by before the select distinct works. Does anyone have any ideas?
(Hope this makes sense)

You could try using a window function instead:
SELECT url, name, frequency, selector, date
FROM (
SELECT watch.url, watch.name, user_url.frequency, watch.selector, price.date,
row_number() over (partition by watch.url order by price.date desc) as rn
FROM watch
JOIN user_url on user_url.url = watch.url
LEFT JOIN price on price.url = watch.url
WHERE (1400575234 > price.date + user_url.frequency)
OR price.date is null
) t
WHERE rn = 1
ORDER BY url, date;
Btw: date is a horrible name for a column

I've seemed to of solved it using the following
SELECT DISTINCT ON (watch.url)
watch.url, watch.name, user_url.frequency, watch.selector, p.date
FROM watch
JOIN user_url on user_url.url = watch.url
LEFT JOIN (
SELECT max(price.date) as date, url FROM price GROUP BY url
) as p ON p.url = watch.url
WHERE 1400575234 > p.date + user_url.frequency
ORDER BY watch.url
Thanks for everyones help. If you can see anyway to make the query more efficient please let me know.

Related

Getting value from MAX(Date) Row in SQL Server

I am trying to get the last supplier of an item, by using the MAX function. What I am trying to achieve is showing what the supplier name was for the row with the MAX(Date) for all the stock items (shown below as account links).
The code I am using bring up multiple dates for the same accountlink, and I am struggling to see why. My code is:
SELECT
MAX(TxDate) AS Date,
ST.AccountLink,
V.Account AS Supplier
FROM _bvSTTransactionsFull AS ST
JOIN Vendor V on ST.DrCrAccount = V.DCLink
WHERE Module = 'AP'
AND Id = 'OGrv'
GROUP BY ST.AccountLink, V.Account
ORDER BY AccountLink
But my results look like the below
Try this out
select AccountLink,Supplier,date from(SELECT
ST.AccountLink,
V.Account AS Supplier,
TxDate as [date],
row_number()over(partition by ST.AccountLink order by TxDate desc)rownum
FROM _bvSTTransactionsFull AS ST
JOIN Vendor V on ST.DrCrAccount = V.DCLink
WHERE Module = 'AP'
AND Id = 'OGrv')t
where t.rownum = 1
The group by has been removed and ranking function is used to achieve the output
You need a simple subquery to select the last supplier.
select X.supplier as LastSupplier, X.Date as lastDate, X.AccountLink
from _bvSTTransactionsFull X
where X.Date = (select max(date)
from _bvSTTransactionsFull Y
where Y.AccountLink=X.AccountLink)
The subquery extracts the last date for any accountLink, so you can use it on the outer where condition.

List values with MaxDate

Im trying to create ie query to show itens with MAX DATE, but I donĀ“t know how !
Follow the script and result:
Select
results.severity As "Count_severity",
tasks.name As task,
results.host,
to_timestamp(results.date)::date
From
tasks Inner Join
results On results.task = tasks.id
Where
tasks.name Like '%CORP 0%' And
results.severity >= 7 And
results.qod > 70
I need to show only tasks with the last date of each one.
Can you help me ?
You seem to be using Postgres (as suggested by the use of casting operator ::). If so - and I follow you correctly - you can use distinct on:
select distinct on(t.name)
r.severity, t.name as task, r.host, to_timestamp(r.date::bigint)::date
from tasks t
inner join results r on r.task = t.id
where t.name like '%corp 0%' and r.severity >= 7 and r.qod > 70
order by t.name, to_timestamp(r.date::bigint)::date desc
This guarantees one row per task only; which row is picked is controlled by the order by clause, so the above gets the row with the greatest date (time portion left apart). If there are ties, it is undefined which row is returned. You might want to adapt the order by clause to your exact requirement, if it is different than what I understood.
On the other hand, if you want top ties, then use window functions:
select *
from (
select r.severity, t.name as task, r.host, to_timestamp(r.date::bigint)::date,
rank() over(partition by t.name order by to_timestamp(r.date::bigint)::date desc) rn
from tasks t
inner join results r on r.task = t.id
where t.name like '%corp 0%' and r.severity >= 7 and r.qod > 70
) t
where rn = 1

header and details table query

I have one master table from that I get encounter ids and a text and I have a detail table, matching fields are encounter id and text. from details table, I need to fetch the latest record as per the date and time and display.
I don't know how to do it. I'm thinking that top 1 should work.
select top 1 om.txt_order_enc_id, txt_act_text_display, txt_actionDate, txt_action from order_management_data_ om
inner join order_ o on om.txt_order_enc_id = o.encounterID
and om.txt_act_text_display = o.actTextDisplay
where o.actstatus = 'ordered'
and o.actclass = 'REFR'
and o.encounterdate < '20180610'
order by o.encounterdate desc
expected result.
latest record encounter id, text, status from detail table.
First create a group by on basis of encounterID. Create row index for same. And filter out the top 1 record of each group.
; with cte as (
select row_number () (partition by o.encounterID order by o.encounterdate desc) as Slno,
om.txt_order_enc_id, txt_act_text_display, txt_actionDate, txt_action from order_management_data_ om
inner join order_ o on om.txt_order_enc_id = o.encounterID
and om.txt_act_text_display = o.actTextDisplay
where o.actstatus = 'ordered'
and o.actclass = 'REFR'
and o.encounterdate < '20180610'
)
select * from cte where Slno = 1

Oracle SQL query, getting a a maximum of a sum

Hey, guys. I'm struggling to solve one query, just cant get around it.
Basically, I got a some tables from data mart :
DimTheatre(TheatreId(PK), TheatreNo, Name, Address, MainTel);
DimTrow(TrowId(PK), TrowNo, RowName, RowType);
DimProduction(ProductionId(PK), ProductionNo, Title, ProductionDir, PlayAuthor);
DimTime(TimeId(PK), Year, Month, Day, Hour);
TicketPurchaseFact( TheatreId(FK), TimeId(FK), TrowId(FK),
PId(FK), TicketAmount);
The thing I'm trying to achieve in oracle is - I need to retrieve the most popular row type in each theatre by value of ticket sale
Thing I'm doing now is :
SELECT dthr.theatreid, dthr.name, max(tr.rowtype) keep(dense_rank last order
by tpf.ticketamount), sum(tpf.ticketamount) TotalSale
FROM TicketPurchaseFact tpf, DimTheatre dthr, DimTrow tr
WHERE dthr.theatreid = tpf.theatreid
GROUP BY dthr.theatreid, dthr.name;
It does give me the output, but the 'TotalSale' column is totally out of place, it gives much way higher numbers than they should be.. How could I approach this issue :) ?
I am not sure how MAX() KEEP () would help your case if I understand the problem correctly. But the below approach should work:
SELECT x.theatreid, x.name, x.rowtype, x.total_sale
FROM
(SELECT z.theatreid, z.name, z.rowtype, z.total_sale, DENSE_RANK() OVER (PARTITION BY z.theatreid, z.name ORDER BY z.total_sale DESC) as popular_row_rank
FROM
(SELECT dthr.theatreid, dthr.name, tr.rowtype, SUM(tpf.ticketamount) as total_sale
FROM TicketPurchaseFact tpf, DimTheatre dthr, DimTrow tr
WHERE dthr.theatreid = tpf.theatreid AND tr.trowid = tpf.trowid
GROUP BY dthr.theatreid, dthr.name, tr.rowtype) z
) x
WHERE x.popular_row_rank = 1;
You want the row type per theatre with the highest ticket amount. So join purchases and rows and then aggregate to get the total per rowtype. Use RANK to rank your row types per theatre and stay with the best ranked ones. At last join with the theatre table to get the theatre name.
select
theatreid,
t.name,
tr.trowid
from
(
select
p.theatreid,
r.rowtype,
rank() over (partition by p.theatreid order by sum(p.ticketamount) desc) as rn
from ticketpurchasefact p
join dimtrow r using (trowid)
group by p.theatreid, r.rowtype
) tr
join dimtheatre t using (theatreid)
where tr.rn = 1;

Getting Max Value From Joined Table With Certain Logic

This is my table relation :
tbl_product
-----------
product_id
tbl_product_price
-----------------
price_id
price_product_id (FK)
price_normal
price_discount
price_disc_valid_from_date
price_disc_valid_to_date
I'd like to query tbl_product, ordered by its max price DESC, which must be validated first. If the the discount date is still valid (current date between price_disc_valid_from_date AND price_disc_valid_to_date), then get the price_discount. If not valid, then get price_normal. After that I need to get max price ( either from the price_discount or price_normal), then order by that max price.
Most of the questions like this are just how to select the max column, no validation needed first on the joined table.
My question is , what is the postgres sql statement for that query ? Thanks
[EDIT]
I stuck in selecting max price from table tbl_product_price but no idea how to join with tbl_product :
SELECT
pr.price_id, pr.product_price_id,
CASE WHEN current_date BETWEEN pr.price_disc_valid_from_date AND pr.price_disc_valid_to_date
THEN pr.price_discount
ELSE pr.price_normal END AS price
FROM tbl_product_price pr
WHERE pr.price_product_id = 316
GROUP BY pr.price_id, pr.price_product_id
ORDER BY price DESC
LIMIT 1;
Can you do something like this:
SELECT
tbl_tbl_product.price_product_id,
tblMax.MaxPrice
FROM
tbl_tbl_product
JOIN
(
SELECT
tbl_product_price.price_product_id,
MAX(
CASE
WHEN now() BETWEEN
tbl_product_price.price_disc_valid_from_date
AND tbl_product_price.price_disc_valid_to_date
THEN tbl_product_price.price_discount
ELSE tbl_product_price.price_normal
END
) AS MaxPrice
FROM
tbl_product_price
GROUP BY
tbl_product_price.price_product_id
) as tblMax
ON tblMax.price_product_id=tbl_tbl_product.product_id
ORDER BY
tblMax.MaxPrice DESC
If I understand your logic correctly, this query should return products ordered by the maximum price for the product:
SELECT
tp.product_id
FROM
tbl_product tp INNER JOIN tbl_product_price tpp
ON tb.product_id = tpp.price_product_id
GROUP BY
tp.product_id
ORDER BY
MAX(CASE WHEN current_date BETWEEN tpp.price_disc_valid_from_date
AND tpp.price_disc_valid_to_date THEN
tpp.price_discount
ELSE
tpp.price_normal END) DESC