Must I use inner join if I want to use MAX() value as a "where" condition? - sql

My table is like this:
ProductID ProductName SupplierID CategoryID Unit Price
1 Chais 1 1 10 boxes x 20 bags 18
2 Chang 1 1 24 - 12 oz bottles 19
3 Aniseed Syrup 1 2 12 - 550 ml bottles 10
4 Chef Anton's
Cajun Seasoning 2 2 48 - 6 oz jars 21.35
5 Chef Anton's
Gumbo Mix 2 2 36 boxes 25
I copy it from https://www.w3schools.com/sql/sql_func_max.asp
I tried the simple version of MAX() function test, it works. But when I use the HighestPrice in the WHERE condtion as following:
SELECT
MAX(Price) AS HighestPrice,
SupplierID
FROM Products
GROUP BY SupplierID
WHERE HighestPrice>20;
The sytem report ERROR as:
Error: misuse of aggregate: MAX()
Does it mean I must use inner join to get what I want?

Following query should work:
SELECT SupplierID, MAX(Price) AS HighestPrice
FROM Products
GROUP BY SupplierID
HAVING MAX(Price) > 20;
following is the correct syntax of writing any SQL query:
SELECT column_name1,
SUM(column_name2)
FROM table_name
WHERE [CONDITION]
GROUP BY column_name1
HAVING (arithematic function condition);

Use having instead of where .
Where is always used before group by statement. It is way to filter the data which is already available with us whereas having is used after group by statement because it is applied on the data which we are in process of making.
SELECT MAX(Price) AS HighestPrice, SupplierID
FROM Products
Group By SupplierID
having MAX(Price) > 20;
Let me know in case of any queries.

Just for fun. If you specifically want to use where condition for highest price instead of having clause as given by G.arima with max function again. Do this:-
SELECT *
FROM
(
SELECT
MAX(Price) AS HighestPrice,
SupplierID
FROM Products
GROUP BY SupplierID
) a
WHERE HighestPrice>20;
Hope it helps :-)

By way of explanation of G.arima’s answer above:
When you use GROUP BY, you effectively create a new virtual table which contains only the GROUP BY fields as well as summaries.
There are two filter clauses, WHERE and HAVING, but they have a distinct role.
WHERE filters the original table. This gives you the formula FROM … WHERE …
HAVING filters the groups. This gives you the formula GROUP BY … HAVING …
What you ask is OK, but the clause is the wrong one. As G.arima says, you should use HAVING.

Related

SQL subqueries using SELECTs only

I need to write a query with subqueries using SELECT and aggregation functions only, e.g.:
select distinct m_name
from MANUFACT
where m_id in (select TOP 1 m_id
from PRODUCT
where p_id = (select p_id
from PRODUCT
where p_desc = 'Bronze Sculpture'));
The question is about query similar to this one, but using SUM(). The data I have:
Table SPERSON:
sp_id | sp_name
---------------
10 | Jones
39 | Matsu
23 | Atsuma
Table SALE:
sp_id | qty
-----------
10 | 20
23 | 30
10 | 10
39 | 20
etc.
The task is to return the sp_name s whose total number of products is <= 75.
The teacher says we're not allowed to use join, but I doubt whether is any way not to use it.
This is what I have so far:
select sp_name
from SPERSON
where sp_id in (select sp_id from SALE
where qty in (select sum(qty) group by sp_id));
Anyway, I only got the 'Each GROUP BY expression must contain at least one column that is not an outer reference' error, but can't really get the thing.
You can use correlated subquery :
SELECT q.sp_name
FROM( SELECT sp_name,
(SELECT SUM(qty) FROM sale s WHERE s.sp_id = p.sp_id ) AS qty
FROM SPERSON p
GROUP BY sp_name
) q
GROUP BY q.sp_name
HAVING SUM(q.qty) <= 75
Mostly, using correlated subqueries, which may contains a reference to the outer query and so produces different results for each row of the outer query, is not suggested. But I suggested to use it as an alternative method depending on your case for not being permitted to use JOIN. Btw, it is more straightforward to use JOIN .
You can try to approach a problem from different direction.
Create a query to calculate total quantity grouped by sp_id
SELECT s.sp_id, SUM(s.qty)
FROM SALE s
GROUP BY s.sp_id
Filter persons id which has quantity less or equal to 75
SELECT s.sp_id, SUM(s.qty)
FROM SALE s
GROUP BY s.sp_id
HAVING SUM(s.qty) <= 75
Because joins not allowed, "inject" name as a subquery
SELECT
(SELECT p.sp_name FROM SPERSON p WHERE p.sp_id = s.sp_id) AS name
FROM SALE s
GROUP BY s.sp_id
HAVING SUM(s.qty) <= 75

SQL: Is it possible to merge these two SQL statements into a single query?

I am using MS SQL Server 2014 on Windows 7.
In the database I have a table named Orders, which looks like this:
OrderID | CustomerID | OrderDate | ...
----------------------------------------
1028 90 2015-10-10
...
2416 68 2016-02-12
I needed two things:
the total number of customers
the number of customers this year.
I am a beginner in SQL, but I managed to write 2 SQL statements in my app that seem to do the job:
For requirement #1
SELECT COUNT(DISTINCT CustomerID) FROM Orders; // result = 74
For requirement #2:
SELECT COUNT(DISTINCT CustomerID) FROM Orders WHERE OrderDate >= '2016-01-01'; // result = 34
I would like to know if it's possible to merge/combine somehow the above 2 SQL statements into one single query...? Of course, I need both results: the total customers (74 in above case) and also the customers of this year (i.e. 34).
The database is a remote database, so any idea to speed-up the query performance is highly welcome :)
Use conditional aggregation:
SELECT COUNT(DISTINCT CustomerID) as Total,
COUNT(DISTINCT CASE WHEN OrderDate >= '2016-01-01' THEN CustomerID END) as Total_2016
FROM Orders;
You can combine the data horizontally as in the previous answer or you can combine them vertically using a UNION, like this, if you think you need a tabular form:
SELECT 'Total Customers' As Description, COUNT(DISTINCT CustomerID) As Number FROM Orders // total = 74
Union ALL
SELECT '2016 Customers' AS Description, COUNT(DISTINCT CustomerID) As Number FROM Orders WHERE OrderDate >= '2016-01-01'; // this_year = 34

Select multiple rows from a table where field is the max date

I have a table called Product. I need to select all product records that have the MAX ManufatureDate.
Here is a sample of the table data:
Id ProductName ManufactureDate
1 Car 01-01-2015
2 Truck 05-01-2015
3 Computer 05-01-2015
4 Phone 02-01-2015
5 Chair 03-01-2015
This is what the result should be since the max date of all the records is 05-01-2015 and these 2 records have this max date:
Id ProductName ManufactureDate
2 Truck 05-01-2015
3 Computer 05-01-2015
The only way I can think of doing this is by first doing a query on the entire table to find out what the max date is and then store it in a variable #MaxManufatureDate. Then do a second query where ManufactureDate=#MaxManufactureDate. Something tells me there is a better way.
There are 1 million+ records in this table:
Here is the way I am currently doing it:
#MaxManufactureDate = select max(ManufactureDate) from Product
select * from Product where ManufactureDate = #MaxManufactureDate
If figure this is a lot better then doing a subselect in a where clause. Or is this the same exact thing as doing a subselect in a where clause? I am not sure if the query gets ran for each row regardless or if sqlserver stored the variable value in memory.
select * from product
where manufactureDate = (select max(manufactureDate) from product)
The inner select-statements selects the maximum date, the outer all products which have the date.
You can use a subQuery
SELECT *
FROM Product
WHERE ManufactureDate = (
SELECT ManufactureDate
FROM Product
ORDER BY ManufactureDate
LIMIT 1
);`
You may need to use ASC or DESC to collect the right order
Try this pattern:
SELECT Id, ProductName, ManufactureDate
FROM (
SELECT Id, ProductName, ManufactureDate, MAX(ManufactureDate)OVER() AS MaxManufactureDate
FROM Product P
) P
WHERE P.MaxManufactureDate = P.ManufactureDate
Essentially, use a window function to get the data you're looking for in the inline view, then use the where clause in the outer query to match them.

How can I SELECT the max row in a table SQL?

I have a little problem.
My table is:
Bill Product ID Units Sold
----|-----------|------------
1 | 10 | 25
1 | 20 | 30
2 | 30 | 11
3 | 40 | 40
3 | 20 | 20
I want to SELECT the product which has sold the most units; in this sample case, it should be the product with ID 20, showing 50 units.
I have tried this:
SELECT
SUM(pv."Units sold")
FROM
"Products" pv
GROUP BY
pv.Product ID;
But this shows all the products, how can I select only the product with the most units sold?
Leaving aside for the moment the possibility of having multiple products with the same number of units sold, you can always sort your results by the sum, highest first, and take the first row:
SELECT pv."Product ID", SUM(pv."Units sold")
FROM "Products" pv
GROUP BY pv."Product ID"
ORDER BY SUM(pv."Units sold") DESC
LIMIT 1
I'm not quite sure whether the double-quote syntax for column and table names will work - exact syntax will depend on your specific RDBMS.
Now, if you do want to get multiple rows when more than one product has the same sum, then the SQL will become a bit more complicated:
SELECT pv.`Product ID`, SUM(pv.`Units sold`)
FROM `Products` pv
GROUP BY pv.`Product ID`
HAVING SUM(pv.`Units sold`) = (
select max(sums)
from (
SELECT SUM(pv2.`Units sold`) as "sums"
FROM `Products` pv2
GROUP BY pv2.`Product ID`
) as subq
)
Here's the sqlfiddle
SELECT SUM(pv."Units sold") as `sum`
FROM "Products" pv
group by pv.Product ID
ORDER BY sum DESC
LIMIT 1
limit 1 + order by
The Best and effective way to this is Max function
Here's The General Syntax of Max function
SELECT MAX(ID) AS id
FROM Products;
and in your Case
SELECT MAX(Units Sold) from products
Here is the Complete Reference to MIN and MAX functions in Query
Click Here

How to add a user defined column with a single value to a SQL query

I currently have a SQL query that produces a table with around 10M rows. I would like to append this table with another column that has the same entry for all 10M rows.
As an example consider the following toy query
SELECT PRODUCT_ID, ORDER_QUANTITY
FROM PRODUCT_TABLE
GROUP BY SALES_DAY
And say that is produces the following table
PRODUCT_ID ORDER_QUANTITY`
1 10
2 12
3 14
How can I change this query so that it produces the following table, where every entry in USER_VALUE is 999.
PRODUCT_ID ORDER_QUANTITY USER_VALUE
1 10 999
2 12 999
3 14 999
I realize that there may be several answers here... but I suppose that it would help to know the method that would be produce the table with the smallest file size (I assume this would require specifying the type of data beforehand).
Like this:
SELECT PRODUCT_ID, ORDER_QUANTITY, 999 as USER_VALUE
FROM PRODUCT_TABLE
GROUP BY SALES_DAY
You can pass it in the SELECT, for example:
SELECT PRODUCT_ID, ORDER_QUANTITY, 999 AS USER_VALUE
FROM PRODUCT_TABLE
GROUP BY SALES_DAY
you can use
SELECT PRODUCT_ID, ORDER_QUANTITY, user_value=999
FROM PRODUCT_TABLE
GROUP BY SALES_DAY