how to apply where condition for only one element inside the IN statement - sql

I have a SQL query which will return product list and it's respective sales. Below is the query
SELECT *
FROM sales
where sales.name IN ('product_1', 'product_2')
AND sales.product_number IN (SELECT number FROM products) where sales.name = 'product_2'
There are some unnecessary rows in product_2 which i want to filter out with the help of prod_number.
For example the output of above query is
cust_id name product_number
1 product_1 11
2 product_2 22
3 product_2 23
4 product_2 34
Now i want to filter out the product_2 rows based on it's product_number. I want product_2 only with product_number 22 and 23. I tried the above query but it's returning an error.

Use an OR condition to deal with the two cases.
SELECT *
FROM sales
WHERE (name = 'product_1' AND product_number IN (SELECT number FROM products))
OR (name = 'product_2' AND product_number IN ('22', '23'))
Since MySQL often optimizes OR poorly, you may get better results if you split this into two queries that you combine with UNION.
SELECT s.*
FROM sales AS s
JOIN products AS p ON s.product_number = p.number
WHERE s.name = 'product_1'
UNION ALL
SELECT *
FROM sales
WHERE name = 'product_2' AND product_number IN ('22', '23')

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

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

Getting products from SQL query

I'm currently working on a proprietary shopping cart system and was having a few problems with getting products out with the correct pricing.
Basically my table structure is as follows:
Products table: (Only relevant columns are represented)
----------------------------------------------------
productid | product | descr | disporder| list_price|
----------------------------------------------------
1 name desc 1 0.00
2 name desc 4 0.00
3 name desc 2 2.45
Pricing table:
----------------------------------------
priceid | productid | price | variantid|
----------------------------------------
1 1 13.91 1
2 2 54.25 4
3 2 47.23 2
Variants Table:
-------------------------------
variantid | productid | active|
-------------------------------
1 1 Y
2 2 Y
3 2 Y
So, each product can have - and in most cases does have - multiple variants. My current SQL query I have managed to create thus far is:
SELECT
products.productid, product, descr, p.price, i.image_path
FROM
products
LEFT JOIN
pricing AS p
ON
p.variantid = (SELECT variantid FROM variants
WHERE productid = products.productid LIMIT 1)
LEFT JOIN
images_T AS i
ON
i.id = products.productid
GROUP BY
products.productid
ORDER BY
products.disporder
However, my problem arises when a product does not have a variant. If a product does not have a variant associated with it, the price will be in the list_price column of the products table. How would I go about performing a check to see if a product does indeed have a variant. If not, it should effectively bypass the variants table and get the pricing from list_price within the products table.
Yes, CASE is an option, or COALESCE:
SELECT
products.productid, product, descr,
COALESCE(products.list_price, p.price) AS price,
i.image_path
...
Just join both prices and when the first is NULL the other will be selected.
The simplest way is to use a CASE in the SELECT clause, like so:
SELECT
products.productid, product, descr,
CASE
WHEN p.price IS NULL
THEN products.list_price
ELSE p.price
END AS price,
i.image_path
[...]
Since you're left-joining on pricing/variants, p.price should reliably be NULL for products with no variants.
Hopefully that's what you meant by "bypassing" the variants table. :)
You can do a full join with variants table (which will ONLY give you producs which have variants), and then UNION it with a join of producs and pricing where there exists no varian (using AND NOT EXISTS (SELECT 1 from variants WHERE p.productid=v.productid and p.variantid =v.variantid)
Otherwise, use CASE on pricing.price

What's the difference of SELECT and SELECT IN in sql?

The difference of the two statements?
Is the second statemnet faster than the first statement?
First statement :
SELECT * FROM students WHERE id = 2197176;
SELECT * FROM students WHERE id = 74877;
Second statement:
SELECT * FROM students WHERE id IN(2197176, 74877, ...)
UPDATE:
If the time complexity of first statement is m*n, will the second statement be m*n?
m: the time complexity of SELECT * FROM students WHERE id = 2197176;.
n: the amount of ids.
UPDATE:
In the following two cases, which case is faster? And why?
Assuming the table is as follows:
| ID | FLAG |
| ----------|:------:|
| 2197176 | true |
| 74877 | false |
First case:
List ids = getIds();
for(id in ids){
result = getResultFromFirstStatement(id); //one sql statement
if(result.flag) { do sth ...}
}
Second case:
List ids = getIds();
results = getResultFromSecondStament(ids); //`n` sql statements
for(r in results){
if(r.flag) { do sth ...}
}
I ran execution plan on 3 different queries.
First query: Using UNION
Second query: Using UNION ALL
Third query: Using IN
USE AdventureWorksLT2012
-- First query using UNION
SELECT ProductID, Name FROM SalesLT.Product WHERE ProductID = 716
UNION
SELECT ProductID, Name FROM SalesLT.Product WHERE ProductID = 727
UNION
SELECT ProductID, Name FROM SalesLT.Product WHERE ProductID = 770
-- Second query using UNION ALL
SELECT ProductID, Name FROM SalesLT.Product WHERE ProductID = 716
UNION ALL
SELECT ProductID, Name FROM SalesLT.Product WHERE ProductID = 727
UNION ALL
SELECT ProductID, Name FROM SalesLT.Product WHERE ProductID = 770
-- Third query using IN
SELECT ProductID, Name FROM SalesLT.Product WHERE ProductID IN(716, 727, 770)
As you can see the UNION is using 53% (Because UNION tries to delete duplicates), UNION ALL is costing 34% and IN costs 14% of whole batch
First query
SELECT * FROM students WHERE id = 2197176 ..
returns rows with an id column value equal with specific value in this case 2197176 multiple select returns union of results.
In the second query
SELECT * FROM students WHERE id IN (2197176, 74877, ...);
returns rows where the id column value equals with 2197176 or 74877 or ... .
In equal parameter result of both query are the same records, but in readability and performance second query are better.
IN (val1,val2,val3, ...) is an abbreviated form of filtering predicates inside a WHERE clause and not directly related to the select keyword.
SELECT
column,list, ...
FROM
table
JOIN othertables ON ...
WHERE
table.id IN (1,2,3)
This could be re-written as:
SELECT
column,list, ...
FROM
table
JOIN othertables ON ...
WHERE
( table.id = 1
OR table.id = 2
OR table.id = 3
)
If the time complexity of first statement is m*n, will the second statement be m*n?
m: the time complexity of SELECT * FROM students WHERE id = 2197176;.
n: the amount of ids.
No. The second statement will be the same complexity as the first, but with a larger constant for n.
HOWEVER, if you have an index on the table for ID then complexity of the first is 1 and the second is n. (Which is still the same since n = 1 in the first case.)