SQL filter for lowest price - sql

I have a huge table of pricing data, with the following columns
source, product, term, miles, price
The data looks something like this
LL, PH, 3, 10000, 100.00
BA, PH, 3, 10000, 200.00
LL, CH, 3, 10000, 300.00
BA, CH, 3, 10000, 400.00
I need to create a query to filter the rows to show only the line with the lowest price for each unique source/product/term/miles combination. So in the above example i'd like to end up with:
LL, PH, 3, 10000, 100.00
BA, PH, 3, 10000, 200.00
Any help appreciated. Thanks.

You can use ROW_NUMBER() for this:
SQL Fiddle
SELECT
source, product, term, miles, price
FROM(
SELECT *,
RN = ROW_NUMER() OVER(PARTITION BY source, product, term, miles ORDER BY price)
FROM [your_table]
)t
WHERE RN = 1
Or as per Coder of Code's comment, you could use MIN() and GROUP BY:
SQL Fiddle
SELECT
source, product, term, miles, price = MIN(price)
FROM [your_table]
GROUP BY source, product, term, miles

Use NOT EXISTS to return rows where no lower price exists for the same source:
select source, product, term, miles, price
from tablename t1
where not exists (select 1 from tablename t2
where t1.source = t2.source
and t2.price < t1.price)
If you want the source/product combos with lowest price, add product to the sub-select's condition:
select source, product, term, miles, price
from tablename t1
where not exists (select 1 from tablename t2
where t1.source = t2.source
and t1.product = t2.product
and t2.price < t1.price)
etc.
If there's a tie, both rows will be returned!

SELECT
source, product, term, miles, MIN(price) AS price
FROM [table_name]
GROUP BY source, product, term, miles

Related

Calculating difference in two values in the same column

I want to find the difference (the Profit & Loss) when I combine records with the same CATEGORY value (e.g. A's will be combined and C's will be combined).
I think you want conditional aggregation:
select category,
sum(iif(side = "BUY", - quantity * price, quantity * price)) as net
from t
where side in ("BUY", "SELL") -- may not be necessary
group by category;
Select category, buy.amt-sell.amt ProfitorLoss
from
(SELECT sum(price*quantity) amt, Category
FROM yourtable
WHERE side = 'BUY'
GROUP BY Category) buy,
(SELECT sum(price*quantity) amt, Category
FROM yourtable
WHERE side = 'SELL'
GROUP BY Category) sell
where buy.category = sell.category

GROUP BY after CASE WHEN

I am trying to create a table from a join and summing some fields based on id. This part is working great. I am also trying to add an additional column and using a case when statement I want to populate it.
Here is the script
CREATE TABLE TABLE1
AS
SELECT ID, IDC, SUM(AMOUNT) PRICE, SUM(COST) COST, SUM(AMOUNT-COST) PROFIT,
CASE PROFIT
WHEN PROFIT < 1000 THEN 'Low'
WHEN PROFIT < 5000 THEN 'Medium'
ELSE 'High'
END AS PROFITLEVEL
FROM
(SELECT DISTINCT ID, IDC, AMOUNT, COST
FROM ORDER_ITEMS
LEFT JOIN ORDERS
ON ID = IDC)
GROUP BY ID, IDC;
This however returns a ORA-00905 : Missing keyword error.
Any help would be appreciated
You are using the CASE in a wrong way; besides, you try to use the alias PROFIT at the same level you define it.
You need to edit you CASE and use the expression that gives the PROFIT instead of the alias PROFIT:
CREATE TABLE TABLE1 AS
SELECT ID,
IDC,
SUM(AMOUNT) PRICE,
SUM(COST) COST,
SUM(AMOUNT - COST) PROFIT,
CASE
WHEN SUM(AMOUNT - COST) < 1000 THEN 'Low'
WHEN SUM(AMOUNT - COST) < 5000 THEN 'Medium'
ELSE 'High'
END AS PROFITLEVEL
FROM (SELECT DISTINCT ID,
IDC,
AMOUNT,
COST
FROM ORDER_ITEMS LEFT JOIN ORDERS ON ID = IDC)
GROUP BY ID, IDC;
The way you tried to use the CASE is useful if you need to check single values; for example:
select level,
case level
when 1 then 'one'
when 2 then 'two'
else 'other'
end
from dual
connect by level <=3

More than one maximum value in SQL

I need to write a query that searches for a maximum value and if there more items having the same maximum value, it would return them both.
For example, if I have in my database
Item Price
Coffee 2.50
Tea 2.50
Cola 1.50
it would give Coffee and Tea as an answer.
Thank you in advance
This is typically solved using a window function:
select item,
price
from (
select item,
price,
dense_rank() over (order by price desc) as rnk
from the_table
) t
where rnk = 1;
You didn't specify your DBMS, therefore the above is standard (ANSI) SQL.
Alternatively ...
SELECT
Item,
Price
FROM the_table
WHERE Price = (SELECT MAX(Price) FROM the_table)
Or ...
SELECT
Item,
Price
FROM the_table
WHERE NOT EXISTS
(
SELECT Price
FROM the_table st
WHERE st.Price > the_table.Price
)
Or one more ...
SELECT
Item,
Price
FROM
the_table
INNER JOIN
(
SELECT MAX(Price) MaxPrice
FROM the_table
) Match ON
the_table.Price = match.MaxPrice
Just in case windowed functions aren't available.

How to select records with minimum price per group

I'd like to select each pair of two columns in a database, but only select the entry with the lowest price. As a result, I want to output the id and the price column.
But it does not work:
My table:
id | category | type | name | price
1;"car";"pkw";"honda";1000.00
2;"car";"pkw";"bmw";2000.00
SQL:
select min(price) price, id
from cartable
group by category, type
Result:
Column "cartable.id" must be present in GROUP-BY clause or used in an aggregate function.
If you want the entry with the lowest price, then calculate the lowest price and join the information back in:
select ct.*
from cartable ct join
(select category, type, min(price) as price
from cartable
group by category, type
) ctp
on ct.category = ctp.category and ct.type = ctp.type and ct.price = ctp.price;
You can achieve this with EXISTS clause:
SELECT *
FROM cartable ct
WHERE
NOT EXISTS (
SELECT *
FROM cartable
WHERE ct.type = type and ct.category = categoery and ct.price < price)
For speed caparison can you try this:
SELECT DISTINCT ON (type, category), id, price
FROM cartable
ORDER BY price DESC
SELECT id, price
from cartable C
inner join
(
select min(price) as price , category, type
from cartable
group by category, type
)T
on T.category = C.category
and T.type = C.type
Most of the time you can't do much else than resolve to use Select - Over
select price, id
from(
select price, id, [rnk] = ROW_NUMBER() over( partition by category, type order by price)
from cartable
) as a
where [rnk]=1
Create index appropriately and performance are good.
In your example something like this:
CREATE NONCLUSTERED INDEX [foo]
ON [dbo].[cartable] ([category],[type])
INCLUDE ([price])
Maybe you can try:
select id, price from cartable
where price = (select min(price) from cartable);

SQL SUM aggragete issue

ID Title Qty
1 BMW 2
2 VW 3
I want in one SQL query to find a sum of quantity and divide it by current Qty.
For example:
SUM (Qty) = 5, so I want to compute scores by formula. 2/5 and 3/5
ID title newscores
1 BMW 2/5
1 vW 2/5
Demo
SELECT id
,title
,qty/(select sum(qty) from cars)
FROM cars
GROUP BY id
this should work
select title , sum (QTY) , t2.total, sum(QTY) / t2.total
from table , (select sum(QTY) as total from table) as t2
group by title
SELECT ID, Title, CONCAT( Qty, '/', (SELECT SUM( Qty) FROM table1) ) AS 'newscores'
FROM `table1`
select id, title, qty/(select sum(qty) from make)
from make
See SQLFiddle.
Note there is no need whatsoever for a group by clause.