Lets say we have a view/table hotel(hotel_n,hotel_name, room_n, price). I want to find the cheapest room. I tried group by room_n, but I want the hotels name (hotel_name) to be shown to the board without grouping it.
So as an amateur with sql(oracle 11g) I began with
select hotel_n, room_n, min(price)
from hotel
group by room_n;
but it shows the error: ORA-00979: not a GROUP BY expression. I know I have to type group by room_n, hotel_n, but I want the hotel_n to be seen in the table that I make without grouping by it!
Any ideas? thank you very much!
Aggregate functions are useful to show, well, aggregate information per group of rows. If you want to get a specific row from a group of rows in relation to the other group members (e.g., the cheapest room per room_n), you'd probably need an analytic function, such as rank:
SELECT hotel_n, hotel_name, room_n, price
FROM (SELECT hotel_n, hotel_name, room_n, price
RANK() OVER (PARTITION BY room_n ORDER BY price ASC) rk
FROM hotel) t
WHERE rk = 1
Related
This is my cars table which has 1000 rows. Each of make or manufacturer has different model and same model can have different price.
I have to output min price among all of the model of each manufacturer and i cant think of any way to do this.
Nearest to what i got is,
SELECT make, model, min(price) FROM car
GROUP BY model, make
ORDER BY make;
which outputs,527 rows
But i want min price among all of the models of each make.
HELP!!
In Postgres, I recommend distinct on for this purpose:
select distinct on (make) c.*
from cars c
order by make, price asc;
From your question it seems that you want minimum price of each make.
The following query can help in my opinion.
SELECT make,MIN(price) from car
group by make
order by make;
Assuming you need "the lowest priced Model for each Make", you can easily get the lowest price per Make according to the answers given, but that will not give you the Model name!
I'd suggest using a window function to rank the data, partitioning by Make, and ordering by Price ascending. Then simply select all rows ranked 1.
There may be a possibility that two Models within a Make may be equally low priced. In that case, you'd have two rows returned for that Make. If that's a possibility and also a problem, you'd have to engage in further processing to decide how to break the tie or consolidate the row into one (for example, by concatenating the Model names).
Use rank() window function inside a CTE to filter the minimum prices:
with cte as (
select *,
rank() over (partition by model order by price) rn
from car
)
select id, make, model, price
from cte
where rn = 1
order by make;
This will return ties in minimum price.
If you don't need ties replace rank() with row_number().
I assumed that a model name cannot be used by 2 makers. If this is not the case then change to this:
rank() over (partition by make, model order by price) rn
I think you are looking for a simple left join.
select t1.make, t1.model, t2.min_price
from car t1 left join (select make, min(price) min_price from car group by make) t2 on
t1.make=t2.make
I dont rly know how to explain my Problem, but i have a Query where i need to group by a column but on the other i need to get an avg of a column which is not grouped by.
My Code is like this:
Select SID,PID,Cost, AVG(COST)
from catalog
group by SID,PID
ORDER by SID
All Columns are in the same table.
What can i do to get the AVG(Cost) of PID?
My Question is related to an exam question which is the following: Find the SID's who charge more for some PID than the average cost of that PID.
The table has the columns SID, PID, COST. I cant upload pictures of the table because my account is new, so im sorry.
So my Problem was that i couldnt get the AVG of the PID, my next Problem because i already tried it with Partition is, that i dont know how the having clause has to look like. Do i need a sub-query for that?
You can use window functions to add an average to a row:
select SID, PID, Cost,
avg(cost) over (partition by pid) as avg_cost_for_pid
from catalog
order by sid;
My SQL table "offers" contains offers users make for products (product_ID, customer_ID, offer).
In my admin page, I want to list the products for which at least one offer exists and show the total offers existing for it.
For example,
PRODUCT #324 Total offers: 42
PRODUCT #99 Total offers: 1
etc.
My guess would be to combine a
SELECT DISTINCT product_ID FROM offers...
And in a second query, to SELECT COUNT(*) FROM offers WHERE product_ID=...
Is it the most efficient way to achieve this, or is there a way to make it inside a single query?
You can do this in one query which will get the count by grouping by the product_id:
SELECT product_ID, COUNT(*)
FROM offers
GROUP BY product_ID
As bluefeet already answered, you achieve it in single query by using group by.
(group by demo)
Another thing to mention is the order by,
select
product_id as id,
count(*) as totals
from
t
group by product_id
order by totals;
If you want to sort with the totals of hits, or if you want to sort by product_id etc.
sqlfiddle
I have to answer the following question
"For each year in the database, list the year and the total number of
movies that were released in that year, showing these totals in
decreasing order. That is, the year(s) with the largest number of
movies appear first. If some years have the same number of movies,
show these in increasing order of year."
Currently I am using the code below to get the movies to group together, but am unable to get them to sort:
Select YearReleased, count(*)
from Movies
group by YearReleased
I wish to use something to order this and am trying to make a sub query that uses the results of the first query, along the lines of:
(select * from results order by count(*))
but so far I have been unsuccessful. How do I achieve this or is there a better way of getting the results in that order?
"Unsuccessful" isn't very useful, as opposed to actual error text -- and you aren't telling us which vendor's database you're running against, so we can't test. That said, the following should work:
select
YearReleased,
count(*) as movie_count
from movies
group by YearReleased
order by movie_count desc, YearReleased;
No subqueries needed!
Validated against SQLite 3.5.9; if running against something less standards-compliant (which SQLite is, except in very explicitly documented ways), your mileage may vary.
select *
from
(
Select YearReleased, count(*) as NumReleased
from Movies
group by YearReleased
)
order by NumReleased
select * from (select YearReleased, count(*) counter
from Movies
group by YearReleased
) a order by counter
May need a syntax change depending on your sql flavour.
in first query: select yearReleased, count(*) as 'count1'
in second: order by count1
Yep, with aggregates you can just put an alias for count(*) and it can be reffered as a column.
I know I need to have (although I don't know why) a GROUP BY clause on the end of a SQL query that uses any aggregate functions like count, sum, avg, etc:
SELECT count(userID), userName
FROM users
GROUP BY userName
When else would GROUP BY be useful, and what are the performance ramifications?
To retrieve the number of widgets from each widget category that has more than 5 widgets, you could do this:
SELECT WidgetCategory, count(*)
FROM Widgets
GROUP BY WidgetCategory
HAVING count(*) > 5
The "having" clause is something people often forget about, instead opting to retrieve all their data to the client and iterating through it there.
GROUP BY is similar to DISTINCT in that it groups multiple records into one.
This example, borrowed from http://www.devguru.com/technologies/t-sql/7080.asp, lists distinct products in the Products table.
SELECT Product FROM Products GROUP BY Product
Product
-------------
Desktop
Laptop
Mouse
Network Card
Hard Drive
Software
Book
Accessory
The advantage of GROUP BY over DISTINCT, is that it can give you granular control when used with a HAVING clause.
SELECT Product, count(Product) as ProdCnt
FROM Products
GROUP BY Product
HAVING count(Product) > 2
Product ProdCnt
--------------------
Desktop 10
Laptop 5
Mouse 3
Network Card 9
Software 6
Group By forces the entire set to be populated before records are returned (since it is an implicit sort).
For that reason (and many others), never use a Group By in a subquery.
Counting the number of times tags are used might be a google example:
SELECT TagName, Count(*)
AS TimesUsed
FROM Tags
GROUP BY TagName ORDER TimesUsed
If you simply want a distinct value of tags, I would prefer to use the DISTINCT statement.
SELECT DISTINCT TagName
FROM Tags
ORDER BY TagName ASC
GROUP BY also helps when you want to generate a report that will average or sum a bunch of data. You can GROUP By the Department ID and the SUM all the sales revenue or AVG the count of sales for each month.