HQL query with 2 column Sub Join - sql

I have a table price:
| id | price | product_id | date | other_columns... |
I have the following query to return the latest price row for each product_id:
select p1.*
from price p1
right join (
select
p2.product_id,
p2.id,
max(p2.date)
from price p2
GROUP BY p2.product_id
) p2 ON p2.id = p1.id;
When I run Explain plan, and from running against a large table this seems to be the most efficient way of achieving this (correct me if I'm wrong!).
I need to convert this to HQL to use with Spring Data JPA. So far I have the sub query:
(SELECT p2.id, MAX(p2.date) FROM Price p2 GROUP BY p2.product)
That seems to be the easy part. How do I now join this so I can get the full latest Price for each product?
I have tried other queries e.g.
select
p1.*
from price p1
where p1.date = (
select max(p2.date)
from price p2
where p1.product_id = p2.product_id
)
Which is much easier to convert to HQL but seems to be worse performance-wise.

Related

How can I find the most expensive product in a Product table without using MAX, LIMIT, or ORDER BY in SQL Developer Oracle?

I'm supposed to find it without using those, and I can't think of anything and haven't found any information. Thanks
Use NOT EXISTS:
SELECT *
FROM product p
WHERE NOT EXISTS (
SELECT 1
FROM product x
WHERE p.price < x.price
)
You can do a self outer join on the price being lesser. Supposing you have a table products(id int, price int), you can find the id of the most expensive items using:
select p1.id
from products p1 left join products p2
on p1.price < p2.price
where p2.id is null;
Fiddle

Database query- find most expensive part

Here is my schema
Suppliers(​sid ,​sname,address)
Cata(sid,pid,cost)
Parts(pid,pname,color)
bolded are primary keys
I am trying to write a query
"Find the pids of the most expensive parts"
I am using set difference here is my query however its returning all the pids in the catalogue not the one with the highest cost
select Cata.pid
from Cata
where pid not in(
select c.pid
from Cata c, Cata f
where c.sid=f.sid AND c.pid=f.pid AND c.cost<f.cost
);
Try this one:
select c1.pid
from Cata c1
where not exists (
select c2.pid
from Cata c2
where c2.cost > c1.f.cost
);
If you are wondering what is wrong with your query, notice that the inner SELECT is returning 0 rows, because you are comparing the cost of the items with themselves, so c.cost is always equal to f.cost, so the < comparation fails, so the inner select returns 0 rows, so the "not in" condition is true for all the rows
If you want the pid with the single highest cost:
SELECT TOP 1 WITH TIES
c.pid,
c.cost
FROM
Cata AS c
ORDER BY
c.cost DESC
If you want the five highest cost pids, change the first line of that to:
SELECT TOP 5 WITH TIES
I think this is what you are looking for
SELECT
p.PID
, MAX(c.COST)
FROM
Parts p
LEFT JOIN
Cata c
ON p.PID = c.PID
GROUP BY
p.PID
ORDER BY
MAX(c.COST)
This will return you the most expensive part per PID
Good luck!
You want to
Find the pids of the most expensive parts
As you have not mentioned your requirement clearly,
I have given 2 solutions
Solution 1 : to find most expansive parts for each supplier
Solution 2 : to find most expensive part amongst all the parts
Use which ever suits you.
Solution 1:
SELECT Cata.pid FROM Cata
LEFT OUTER JOIN (SELECT Cata.sid, MAX(Cata.cost) cost FROM Cata GROUP BY Cata.sid) MostExpensive
ON Cata.sid = MostExpensive.sid AND Cata.cost = MostExpensive.cost
Query explanation:
First you should try to find what is most expensive as per cost for each sid
then once you have that got that most expensive table derived, find pids which matches the cost in the same sid.
If there is a tie between 2 parts for being most expensive, this query will return pids for both the parts.
Solution 2:
If you looking for most expansive parts across all the suppliers then query could be simplified as below.
SELECT Cata.pid FROM Cata
WHERE Cata.cost = (SELECT MAX(cost) cost FROM Cata)
Find the pids of the most expensive parts
The most expensive parts are the ones where the minimum cost is highest, i.e. you can get all other parts cheaper than these ones where you must at least pay xxx $. You get these with a top query.
select top(1) with ties
pid
from cata
group by pid
order by min(cost) desc;
Illustration:
pid | supplier A | supplier B | supplier C
----+------------+------------+-----------
p1 | 10$ | 10$ | 100$
p2 | 40$ | 50$ | 60$
Which part is the more expensive one? I can buy p1 for 10$. For p2 I must pay at least 40$. So p2 is more expensive. That supplier C wants an outrageous 100$ for p1 doesn't matter, because who would pay 100$ for something you can get for 10$? So it's the minimum prices we must compare.

Take one condition & show result from two different tables

I have these 3 data tables (quick version):
Payments:
id | datepaid | amountpaid
---------------------------
112|03/5/2017 |9000
115|03/21/2017| 800
Individuals:
id|name|lastDatePaid
--------------------
112|bob|03/2/2017
114|kary|2/3/2016
Business:
id|name|lastDatePaid
--------------------
115| Bakery Love | 05/20/2017
My question is: how would I get the result of both business name and individual name when the condition is the for each payment that was made on or after March 2, 2017?
I was able to get show result in one condition, but I don't seem to understand to get both individual and business to show up?
Want result:
112|bob
115|Bakery Love
This is my version that one result show for example Individual:
SELECT DISTINCT p1.id, i1.name
FROM Payments p1, Individuals i1
WHERE p1.datePaid >= DATE '2017-03-01' AND p1.id = i1.id;
Which this code result only to:
112|bob
Also I've read a book that this code is also equivalent, but I don't think so?
SELECT DISTINCT p1.id, i1.name
FROM Individuals i1, Payments p1
WHERE i1.id IN (SELECT DISTINCT p1.id
FROM Payments p1
WHERE p1.datePaid >= DATE '2017-03-01');
When I rewrote it to try to get the same result, I ended up getting unwanted data for some reason. Apparently, it checks the dates (lastDatePaid) in the Individual and businesses table and print without having that AND condition that it should be the id from the payments.(this is the full version of the data).
One approach you could take is to put the 'name' tables on top of each other.
Select * from individuals
Union all
Select * from business
Then you make that a sub query and join it to the payment table...
Select p.id, n.name
From
Payments p
Join
(
Select * from individuals
Union all
Select * from business) as n
On n.id = p.id
It looks like you have figured how to get the date filter to work, so I won't bother adding that.
Er, I figure it out.
I didn't need to use the JOIN statement rather this
SELECT DISTINCT p1.ID, N.name
FROM Payments p1, (SELECT i1.name, i1.ID
FROM Individuals i1
UNION ALL
SELECT b1.name, b1.ID
FROM Businesses b1) AS N
WHERE p1.datePaid >= DATE '2017-03-01' AND p1.ID = N.ID;

Explode components recursively to get total value

TL-TR: I want to get the total value of a final item that is made of others, from which I have the buying price. Problem is semi-finished items.
Consider three types of items:
Final item: It's made from raw items and/or semifinished items. These are the ones I want to get the total value.
Semifinished item: It's made from raw items and/or semifinished items.
Raw item: I have the cost of a unit of these ones.
A final item can be made, amongst other things, of a semifinished item which can be made, amongst other things, of another semifinished item and so on... on an undeterminate number of levels, until you get to all being raw items.
I know how to do this on C# but I'm interested on a pure SQL solution, that I believe is doable.
SQL Fiddle provided here:
http://sqlfiddle.com/#!6/138c3
And this is as far as I can get with the query...
SELECT BOM.output, SUM(P.price * BOM.quantity) as Total
FROM BOM
INNER JOIN
Prices P ON P.input = BOM.Input
GROUP BY BOM.output
But of course that doesn't take semifinished prices into the sum as they don't exist in prices table.
EDIT: Another attempt, but it gives an error that grouping is not allowed in recursive queries.
WITH cte_table AS (
SELECT BOM.output, SUM(P.price * BOM.quantity) as Total
FROM BOM
INNER JOIN
Prices P ON P.input = BOM.Input
GROUP BY BOM.output
UNION ALL
SELECT BOM.output, SUM(ISNULL(P.price,T.Total) * BOM.quantity) as Total
FROM BOM
LEFT JOIN
Prices P ON P.input = BOM.Input
LEFT JOIN
cte_table T ON T.output = BOM.Input
GROUP BY BOM.output
)
SELECT *
FROM cte_table
And some example of expected output (in light grey it must be calculated, in black is data):
You need to use the recursive query:
SQL Fiddle
Query 1:
with a as(
SELECT BOM.output, BOM.input, P.price * BOM.quantity as price, 1 as level,
convert(varchar(max), BOM.input) as path
FROM BOM
INNER JOIN
Prices P ON P.input = BOM.Input
UNION ALL
SELECT BOM.output, BOM.input, a.price * BOM.quantity as price, a.level + 1 as level,
a.path + '/' + bom.input
FROM a
INNER JOIN BOM ON a.output = BOM.Input)
select output, sum(price) from a
group by output
-- select * from a
Results:
| output | |
|--------|-------------------|
| Item 3 | 64.32000000000001 |
| Semi 1 | 63 |
| Semi 2 | 60.4 |

SQL query on link table where results must contain certain value

SQL Server 2005.
I've a link table of Products and Attributes associated with them. I'm doing a search along the lines of:
select distinct ProductId from productattributelink where
attributeid in (25,5,44,46)
But I want to make sure that each productid is also associated with an attributeId of 10.
So in longhand the query would be: Show me all the product Ids that have the following attributeids (25,5,44,46) but also have attributeid of 10.
I've a feeling this is really obvious but is eluding me.
select distinct p.ProductId from product p
inner join productattributelink pa1 on pa1.ProductId = p.ProductId
inner join productattributelink pa2 on pa2.ProductId = p.ProductId
where pa1.attributeid IN(25,5,44,46) and pa2.attributeid = 10
You should join the table to itself:
select distinct ProductId from productattributelink p1
JOIN productattributelink p2 ON p1.ProductId = p2.ProductId
where p1.attributeid in (25,5,44,46) AND p2.attributeid = 10