Query GROUP BY and COUNT - sql

I'm new to SQL and taking COURSERA's "SQL for Data Science" course.I have the following question in a summary assignment:
Show the number of orders placed by each customer and sort the result by the number of orders in descending order.
Having failed to write the correct code, the answer would be as follows (of course one of several options):
SELECT *
,COUNT (InvoiceId) AS number_of_orders
FROM Invoices
GROUP BY CustomerId
ORDER BY number_of_orders DESC
I am still having trouble understanding the query logic. I would appreciate your assistance in understanding this query.

I seriously hope that Coursera isn't giving you the query you cited above as the recommended answer. It won't run on most databases, and even in cases such as MySQL where it might run, it is not completely correct. You should be using this version:
SELECT CustomerId, COUNT (InvoiceId) AS number_of_orders
FROM Invoices
GROUP BY CustomerId
ORDER BY number_of_orders DESC;
A basic rule of GROUP BY is that the only columns available for selection are those which appear in the GROUP BY clause. In addition to these columns, aggregates of any column(s) may also appear in the select. The version I gave you above follows these rules, and is ANSI compliant, meaning it would run on any database.

When you say SELECT * it represents ALL COLUMNS. But you are grouping by only CustomerId which is wrong in SQL.
Specify the other columns in the group section that you want to show
The script should be something like
SELECT CustomerName, DateEntered
,COUNT (InvoiceId) AS number_of_orders
FROM Invoices
GROUP BY CustomerId, CustomerName, DateEntered
ORDER BY number_of_orders DESC

Related

"Joining" 2 different selects on the same table?

I have a table of orders with products, each product has their own shipping date. How can I retrieve the orders so it shows the fastest shipping date?
For example:
Order Product Ship date
1 phone 02/03/2019
1 charger 02/07/2019
2 printer 03/01/2019
What would be the sql query to retrieve the following?
Order Product Ship date
1 phone 02/03/2019
1 charger 02/03/2019
2 printer 03/01/2019
I.e on order 1, all ship dates are 02/03/2019 since it's the earliest.
I tried this:
SELECT order,
product,
(SELECT ship_date FROM Tracking ORDER BY ship_date ASC) tbl ON tbl.order = t.order
FROM Tracking t
But I'm getting the error:
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
Considering the error message I believe this is for SQL Server and thus window functions to be available.
You could use the windowed version of min() to get the minimum shipping date for an order.
SELECT [order],
[product],
min([ship date]) OVER (PARTITION BY [order]) [ship date]
FROM tracking;
To get rid of the "The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified." message, you can do that by adding "SELECT TOP 100 PERCENT" to the sub-query.
But I'd suggest looking into the RANK and DENSE_RANK functions as they're probably going to be more helpful
I am not sure that i understand what you are trying to achieve here. Well if you want just to query this table ordered by shipping date, i think something like this would work:
SELECT * FROM Tracking ORDER BY ship_date ASC;
You are making it very complicated. The query is pretty simple:
select * from my_table group by shipdate order by shipdate asc

Count(), max(),min() fuctions definition with many selects

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

I am getting too many solutions when I need only one

I use a query that returns the name of the city with the highest number of orders placed.
This is what I have:
SELECT MAX(o.OrderID) AS [Number of Orders], od.ShipCity
FROM Orders o, [Order Details] od
GROUP BY o.ShipCity
ORDER BY [Number of Orders] DESC
I got all of the cities and their orders instead of just the one city with the most orders.
What happened?
Yeah, there's a couple of things wrong with your query. First, you're getting the max order id , which is presumably some autoincrement column. It's like Karl's answer is first, mine is second, SELECT MAX(answerid) FROM this_discussion = 2.... but that doesn't mean I have more answers than he does.
Rnofx5 is also right... you need to tell your table what to join ON, cause right now it's creating a Cartesian Product. If you're not sure what that is, for now accept that it's a horrible, evil, wicked thing to do and then Google it after we're done fixing the query.
So, we have orders and order details. Presumably orders does not contain City, so we need order details
SELECT count(o.OrderID), od.ShipCity
FROM orders AS o
INNER JOIN [Order Details] AS od
ON o.{a varible that both Orders and Order Details have in common} = .{a varible that both Orders and Order Details have in common}
GROUP BY od.ShipCity
ORDER BY count(o.OrderID) DESC
LIMIT 1;
Okay, so we're joining Orders with Order Details. In order to do that, we need to associate every order with something in Order Details. I don't know your schema, but from the sounds of it probably each order has a corresponding record in Order Details. In that case, you join these two tables using their ID. Something like
ON o.OrderID = od.OrderID
Now, we are counting all of the orders associated with a particular city... and we sorting them by our count, in descending order. And then we are keeping only the very first record that's returned (LIMIT 1)
Depending on your SQL implementation, you may need TOP 1 instead of LIMIT 1. You tagged mysqli, so presumably this is MySQL and in that case you'd want LIMIT not TOP. But be aware that that's a syntax variation you may encounter at some point
You are getting the highest orderID (MAX) per ship city rather then the count.
You instead need COUNT(o.OrderID)
And in MySQL you need to use LIMIT 1 on the end to get only the top most result.

SQL grouping results in a select

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

How to use results of one sql query within a sub-query

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.