How to select records with minimum price per group - sql

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);

Related

SQL Select Group By Min() - but select other

I want to select the ID of the Table Products with the lowest Price Grouped By Product.
ID Product Price
1 123 10
2 123 11
3 234 20
4 234 21
Which by logic would look like this:
SELECT
ID,
Min(Price)
FROM
Products
GROUP BY
Product
But I don't want to select the Price itself, just the ID.
Resulting in
1
3
EDIT: The DBMSes used are Firebird and Filemaker
You didn't specify your DBMS, so this is ANSI standard SQL:
select id
from (
select id,
row_number() over (partition by product order by price) as rn
from orders
) t
where rn = 1
order by id;
If your DBMS doesn't support window functions, you can do that with joining against a derived table:
select o.id
from orders o
join (
select product,
min(price) as min_price
from orders
group by product
) t on t.product = o.product and t.min_price = o.price;
Note that this will return a slightly different result then the first solution: if the minimum price for a product occurs more then once, all those IDs will be returned. The first solution will only return one of them. If you don't want that, you need to group again in the outer query:
select min(o.id)
from orders o
join (
select product,
min(price) as min_price
from orders
group by product
) t on t.product = o.product and t.min_price = o.price
group by o.product;
SELECT ID
FROM Products as A
where price = ( select Min(Price)
from Products as B
where B.Product = A.Product )
GROUP BY id
This will show the ID, which in this case is 3.

How to select the record with minimum value from table?

I have table BIDS, which contains a lot of columns and rows but I only want to select a row which contains lowest BIDPRICE.
Select min(Cast(Bids.BidPrice as INT)), BidBidderName from bids BidBidderName
but it throws error
Column 'bids.BidBidderName' is invalid in the select list because it
is not contained in either an aggregate function
When I put BidderName in Group by then it shows all records but I only want record which contains lowest bid price.
Here is an option that will get just the row with the lowest price.
Select top 1 BidPrice
, BidBidderName
from bids
order by Cast(BidPrice as INT)
You can use subquery:
Select BidPrice, BidBidderName from bids
where Bids.BidPrice in (Select min(Cast(b.BidPrice as INT)) from bids b)
Or INNER JOIN:
Select b1.BidPrice, b1.BidBidderName from bids b1
inner join (select Min(BidPrice) BidPrice from #bids) as b2 on b.BidPrice = b2.BidPrice
If you only want rows that have the lowest bid price one solution is to use a subquery to find the minimum price like this:
Select BidPrice, BidBidderName
from bids
where BidPrice = (select min(Cast(BidPrice as INT)) from bids)
If the BidPrice is either money or a numeric type (which it most likely should be) the cast to int is not necessary.
If you do
Select Min(BidPrice) BidPrice, BidBidderName
from bids
group by BidBibberName
you would instead get the lowest bid for every bidder.
try:
Row_Number()
;with cte1
as
(
select BidderName ,BidPrice,Row_Number() Over(order by price asc) as rn from bids
)
select * from cte1 where rn=1;
Or
Min(BidPrice) Over(PARTITION BY BidderName order by price asc)
select top 1 BidderName ,Min(BidPrice) Over(PARTITION BY BidderName order by price asc) as minBidPrice from bids

Get most expensive and cheapest items from two tables

I'm trying to get the most expensive and cheapest items from two different tables.
The output should be one row with the values for MostExpensiveItem, MostExpensivePrice, CheapestItem, CheapestPrice
I was able to get the price of the most expensive and cheapest items in the two tables with following query:
SELECT
MAX(ExtrasPrice) as MostExpensivePrice, MIN(ExtrasPrice) as CheapestPrice
FROM
(
SELECT ExtrasPrice FROM Extras
UNION ALL
SELECT ItemPrice FROM Items
) foo
How can I add the names of the items (ItemName, ExtrasName) to my output? Again, there should only be one row as the output.
Try this:
SELECT TOP 1 FIRST_VALUE(Price) OVER (ORDER BY Price) AS MinPrice,
FIRST_VALUE(Name) OVER (ORDER BY Price) AS MinName,
LAST_VALUE(Price) OVER (ORDER BY Price DESC) AS MaxPrice,
LAST_VALUE(Name) OVER (ORDER BY Price DESC) AS MaxName
FROM (
SELECT ExtrasName AS Name, ExtrasPrice AS Price FROM Extras
UNION ALL
SELECT ItemName As Name, ItemPrice AS Price FROM Items) u
SQL Fiddle Demo
TOP 1 with order by clause should work for you. Try this
SELECT *
FROM (SELECT TOP 1 ExtrasPrice,ExtrasName
FROM Extras ORDER BY ExtrasPrice Asc),
(SELECT TOP 1 ItemPrice,ItemName
FROM Items ORDER BY ItemPrice Desc)
Note: Comma can be replaced with CROSS JOIN
You can use row_number() for this. If you are satisfied with two rows:
SELECT item, price
FROM (SELECT foo.*, row_number() over (order by price) as seqnum_asc,
row_number() over (order by price) as seqnum_desc
FROM (SELECT item, ExtrasPrice as price FROM Extras
UNION ALL
SELECT item, ItemPrice FROM Items
) foo
) t
WHERE seqnum_asc = 1 or seqnum_desc = 1;
EDIT:
If you have an index on "price" in both tables, then the cheapest method is probably:
with exp as (
(select top 1 item, ExtrasPrice as price
from Extras e
order by price desc
) union all
(select top 1 i.item, ItemPrice
from Items i
order by price desc
)
),
cheap as (
(select top 1 item, ExtrasPrice as price
from Extras e
order by price asc
) union all
(select top 1 i.item, ItemPrice
from Items i
order by price asc
)
)
select top 1 *
from exp
order by price desc
union all
select top 1 *
from cheap
order by price asc;
If you want this in one row, you can replace the final query with:
select e.*, c.*
from (select top 1 *
from exp
order by price desc
) e cross join
(select top 1 *
from cheap
order by price asc
) c

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.

T-SQL Subquery Question

i have two queries.
For each tuple of query1 i want to run query2. i dont want to use cursors. i tried several approaches using subqueries.
query1:
select
distinct
category,
Count(category) as CategoryCount
from
mytable
group by
category
query2:
select
top 3
Text,
Title,
Category
from
mytable
where
Category = '1'
Category = '1' is a sample. the value should come from query1
Try this
WITH TBL AS
(
SELECT TEXT, TITLE, CATEGORY,
COUNT(*) OVER(PARTITION BY CATEGORY) AS CATEGORYCOUNT,
ROW_NUMBER() OVER(PARTITION BY CATEGORY ORDER BY (SELECT 0)) AS RC
FROM MYTABLE
)
SELECT TEXT, TITLE, CATEGORY, CATEGORYCOUNT
FROM TBL
WHERE RC <= 3
ORDER BY CATEGORY