SELECT Statement using INTERSECT - sql

I have two tables: tblProduct which has list of Products, and tblConsumer which has consumer name with consumed product ID.
Now I need to find the name of consumers who have consumed all products from the product table.
I tried to solve this with using INTERSECT, but the problem is I have provide each productid in WHERE clause. This syntax gives the result that I wanted, but how do I write this query where I don’t need to specify each productID.
SELECT ConsumerName FROM tblConsumer WHERE ProductID= 1
INTERSECT
SELECT ConsumerName FROM tblConsumer WHERE ProductID =2
INTERSECT
SELECT ConsumerName FROM tblConsumer WHERE ProductID =3
tblProduct
---------------------------------
ProductID | Product Name
---------------------------------
1 | Mango
2 | Orange
3 | Banana
tblConsumer
---------------------------------
ConsumerName | ProductID
---------------------------------
David | 1
David | 3
David | 2
Henry | 3
Henry | 2

If you're actually wanting to list all the Products in tblProducts, then you can use NOT EXISTS...
Otherwise, if you have a list of the Products you want to check, you can do something like:
SELECT c.ConsumerName
FROM tblConsumer AS c
WHERE c.ProductID IN (1,2,3)
GROUP BY c.ConsumerName
HAVING COUNT(DISTINCT c.ProductID) = (SELECT COUNT(DISTINCT p.ProductID) FROM tblProduct WHERE p.ProductID IN (1,2,3))
;
But I think maybe you just want to use NOT EXISTS to eliminate the Consumers for whom there's a record they haven't bought.
Like this:
SELECT *
FROM tblPerson AS pn CROSS JOIN tblProduct AS pt /* Every possible combo */
WHERE NOT EXISTS (SELECT * FROM tblConsumer c
WHERE c.ConsumerName = pn.ConsumerName
AND c.ProductID = pt.ProductID)
;

I have an other small solution:
SELECT * FROM tblConsumer
WHERE NOT EXISTS (SELECT * FROM tblProduct
LEFT JOIN tblConsumer C ON tblProduct.ProductID = C.ProductID AND tblConsumer .ConsumerName = C.ConsumerName
WHERE C.ConsumerName IS NULL)
It will work if you add a new entry too. It just checks, that is there any record, where you cant make a connection between the given Consumer and a Product.

Related

JOIN Products that are IN another table

I tried to join some Products based on if they're in a table or not. I'm using MSSQL and I'm trying to do this to see if the category has some products.
simplified Query:
SELECT c.CategoryID, c.Name, p.ProductID
FROM Category AS c
JOIN Product AS p ON p.ProductID IN (
SELECT PrductID FROM exampleTable
)
ProductTable:
ProductID
CategoryID
1
1
2
1
3
2
4
4
The output I receive:
CategoryID
Name
ProductID
1
Cat1
1
1
Cat1
2
2
Cat2
3
4
Cat4
4
The expected output:
CategoryID
Name
ProductID
1
Cat1
1
2
Cat2
3
4
Cat4
4
I'm trying to only join a product if it's in the select statement and not join all products which have the same category id.
In pseudo code I'm trying to achive this:
JOIN Product AS p IF p.ProductID IN (Subquery)
Is this somehow possible?
Ed banga's answer is IMHO more elegant and perfoment but to be closer to what you proposed in your question, you can simply use a where clause.
SELECT c.CategoryID, c.Name, p.ProductID
FROM Category AS c
JOIN Product AS p ON p.CategoryID = c.CategoryID
WHERE p.ProductID IN (
SELECT PrductID FROM exampleTable
)

How to do a nested COALESCE subquery in a join for 3 different tables?

I have these 3 tables, And using query, have table sorted on distinct on group/product.
Now I would like to add a child table each of these 3 table with say just 1 column default_something
Query:
SELECT DISTINCT ON (pg.id, p.prod_id)
pg.group_name, p.name AS prod_name, v.version
FROM product_group pg
LEFT JOIN product p ON pg.id = p.group_id
LEFT JOIN version v ON v.prod_id = p.prod_id
ORDER BY pg.id, p.prod_id, v.version DESC;
Product Group Table
id group_name
---------------------------
1 Nice
2 Very Nice
Product table
prod_id name group_id
---------------------------
1 something 2
2 psp3 1
3. other one 2
Version Table
version_id prod_id version
---------------------------
1 2 1.0
2 2 1.1
3 3 2.3
4 1 0.1
5. 1 0.2
Product Group Child Table
pgt_child_id group_id default_something
---------------------------------
1 2 root2
2 1 root1
Product Child table
pt_child_id prod_id default_something
-------------------------------------------
1 3 override2
Version Child Table
v_child_id version_id default_something
-------------------------------------------
1 2 winner
Running the query DBFiddle I get this now...
Group_name prod_name version
---------------------------------
Nice psp3 1.1
Very Nice something 0.2
Very Nice other one 2.3
What I want is like this
Group_name prod_name version default_something
-----------------------------------------------------
Nice psp3 1.1 winner
Very Nice something 0.2. root2
Very Nice other one 2.3. override2
Basically if Version table has the field default_something.. that always wins.. If Version Table does not and if Product Table has the field default_something, that would win.. And Group Product Table basically has the lowest priority so if Version Table and Product Table does not have the field then value from Group Product Table wins.
I would assume SELECT COALESCE() would work to get the value which wins from 3 child tables.. I just have not figured out how to put that in a subquery with a join or something.
You can make just a COALESCE with with three subqueries:
SELECT DISTINCT ON (pg.id, p.prod_id)
pg.group_name, p.name AS prod_name, v.version,
COALESCE((select default_something from version_child where version_id = v.id),
(select default_something from product_child where prod_id = p.prod_id),
(select default_something from product_group_child where group_id = pg.id)
) as something
FROM product_group pg
LEFT JOIN product p ON pg.id = p.group_id
LEFT JOIN version v ON v.prod_id = p.prod_id
ORDER BY pg.id, p.prod_id, v.version DESC;
see the amended DBFiddle
or left join the three tables and make the coalesce on the default_somethings
SELECT DISTINCT ON (pg.id, p.prod_id)
pg.group_name, p.name AS prod_name, v.version,
COALESCE(v2.default_something,
p2.default_something,
pg2.default_something
) as something
FROM product_group pg
LEFT JOIN product p ON pg.id = p.group_id
LEFT JOIN version v ON v.prod_id = p.prod_id
LEFT JOIN version_child v2 ON v2.version_id = v.id
LEFT JOIN product_child p2 ON p2.prod_id = p.prod_id
LEFT JOIN product_group_child pg2 ON pg2.group_id = pg.id
ORDER BY pg.id, p.prod_id, v.version DESC;
DBFiddle

Insert Data if not exists (from 2 tables) and Update otherwise

Good day. I have 3 tables:
tblWarehouseProducts:
ProductID
ProductName
ProductCode
Quantity
tblBranchProducts:
ProductID
ProductCode
ProductCode
Quantity
Location
tblStockMoves:
ProductID
DestinationLocation
Quantity
ReferenceNumber
Basically, the process is that Branch X requests a product from Warehouse Y. Warehouse Y then creates a request order(called a Stock Move) and stores the request in tblStockMove.
Say for this case, we have a Stock Move with Reference Number XYZ:
REFERENCE NO. | PRODUCT ID | DESTINATION | QTY |
XYZ | 1 | BRANCH Y | 5 |
XYZ | 2 | BRANCH Y | 6 |
(where ProductID 1 is Coke and ProductID 2 is Pepsi.) Branch X on the other hand has this product on stock:
PRODUCT ID | PRODUCT NAME | PRODUCT CODE | QUANTITY | LOCATION |
1 | COKE | ABC123 | 6 | Branch X |
I am currently trying to check if the items from tblStockMoves exist in tblBranchProducts.
If Product 1 exists, it will add the Qty from tblStockMoves to the current Qty in tblBranchProducts. Product 2 will be added as a new entry since it is a new item.
I am using this query below but so far, all it does is update the stock of ProductID 1 while ignoring (not inserting) Product ID 2.
IF EXISTS (select ProductID, Location
from tblBranchProducts a
where Location = 'Branch X'
and a.ProductID in (select b.ProductID
from tblStockMoves b
where b.ReferenceNumber = 'XYZ'
and b.DestinationLocation = 'Branch X'))
BEGIN
UPDATE tblBranchProducts
SET Quantity = a.Quantity + b.Quantity
FROM tblBranchProducts a
INNER JOIN tblStockMoves b ON a.ProductID = b.ProductID
WHERE
b.ReferenceNumber = 'XYZ'
AND b.DestinationLocation = 'Branch X'
END
ELSE
BEGIN
INSERT INTO tblBranchProducts (ProductID, ProductName, ProductCode, Quantity, Location)
SELECT
b.ProductID, a.ProductName, a.ProductCode, b.Quantity, b.DestinationLocation
FROM
tblStockMoves b
INNER JOIN
tblWarehouseProducts a ON b.ProductID = a.ProductID
WHERE
b.ReferenceNumber = 'XYZ'
AND b.DestinationLocation = 'Branch X'
Other details such as Product Name and Product Code are pulled from tblWarehouseProducts and then inserted to tblBranchProducts.
Can anyone tell me why my query only updates the existing stock of Product 1 and not inserting Product 2?
Your answers are deeply appreciated!
You can do it dynamically for all products with out IF's , just addthe conditions required:
/*will insert all the unmatched products*/
INSERT INTO tblBranchProducts (ProductID, ProductName, ProductCode, Quantity, Location)
SELECT b.ProductID, a.ProductName, a.ProductCode, b.Quantity, b.DestinationLocation
FROM tblStockMoves b
inner join tblWarehouseProducts a on b.ProductID = a.ProductID
LEFT JOIN tblBranchProducts c ON(a.productid = b.productid)
where c.productid is null
And:
/*will update all the matching products*/
update tblBranchProducts a
INNER join tblStockMoves b on a.productid = b.productid
set a.quantity= b.qty

How to sum the numbers of a column in a secondary table with SQL

I have a Table Owners
Owner product
Jhon product1
Jhon product2
Jhon product3
Chris product4
Another Table: Products
Product QuantitySold
Product1 3
Product2 5
Product3 2
Product4 7
How do I do a SQL to come up with the following result:
Name of Owner
Number of products
QuantitySold
NameOfOwner NumberOfProducts QuantitySold
Jhon 3 10 (3+5+2)
Chris 1 7
I tried:
select Owners.owner, count(distinct Owners.product) as NumberOfProducts, sum(Product.QuantitySold) as QuantitySold from Owners O, Products P
group by O.owner
But that returns the total of quantitySold for any owner (17 = 3+5+2+7) multiple by the number of products.
NameOfOwner NumberOfProducts QuantitySold
Jhon 3 51 = 3 * 17 (3+5+2+7)
Chris 1 17 = 1 * 17 (3+5+2+7)
Thank you very much
select o.Name, count(o.Name) NumberOfProducts, sum(QuantitySold) QuantitySold from #Owner o inner join #Product p on p.Name=o.Product
Group By o.Name
You have to use a inner join (or other kind of join):
select owner, count(a.product) nr_of_products, sum(quantity) Qnt_Sold from Owners inner join Products on Owners.product = Products.product group by owner
Different SQL JOINs:
INNER JOIN: Returns all rows when there is at least one match in BOTH tables
LEFT JOIN: Return all rows from the left table, and the matched rows from the right table
RIGHT JOIN: Return all rows from the right table, and the matched rows from the left table
FULL JOIN: Return all rows when there is a match in ONE of the tables
select a.owner as NameOfOwner, count(a.Product) as NumberOfProducts,sum(QuantitySold) as QuantitySold from Owners as a
INNER JOIN Products on a.Product = Products.Product group by a.owner
Pretty much a repeat here of the other answers, but including a run on Sql Fiddle.
SELECT o.owner as Owner, count(o.owner) as NumberofProducts, sum(p.quantitySold) as Quantity
FROM Owners o
inner Join Products p
on o.product = p.product
Group by o.owner

check if the column value exists in subquery

i have 3 tables Product Category and ProductCategory.
Product table:
ProductID ProductName
1 P1
2 P2
3 P3
Category table:
CategoryID CategoryName
1 C1
2 C2
3 C3
ProductCategory:
ProductID CategoryID
1 1
1 2
1 3
2 3
3 1
3 2
I need a query which returns products which fall under more than 1 categories. Based on the table data above the result would be:
ProductID ProductName
1 P1
3 P3
So i wrote a query to fetch all the ProductID's which have more than one CategoryID's as below:
select ProductID,count(CategoryID)
from ProductCategory
group by Productid
having count(CategoryID)>1)
But when i try to display product details using the below query i get an error:
select *
from Product
where ProductID in (
select ProductID,count(CategoryID)
from ProductCategory
group by Productid
having count(CategoryID)>1))
Is my query wrong? How do i get the required product details which fall in more than one categories?
Remove the COUNT() in the subquery. The result of the subquery when used on IN clause must have only one returned column.
SELECT *
FROM Product
WHERE ProductID IN
(
SELECT ProductID
FROM ProductCategory
GROUP BY Productid
HAVING count(CategoryID) > 1
)
SQLFiddle Demo
or by using JOIN
SELECT a.*
FROM Product a
INNER JOIN
(
SELECT ProductID
FROM ProductCategory
GROUP BY Productid
HAVING count(CategoryID) > 1
) b ON a.ProductID = b.ProductID
SQLFiddle Demo
You can try use CROSS APPLY Operator in SQL Server
SELECT DISTINCT C.ProductID,C.ProductName,A.CategoryID,A.Total
FROM Product C
CROSS APPLY (
Select CA.CategoryID,Total=COUNT(*)
From ProductCategory CA
Where C.ProductID=CA.ProductID
Group By CA.CategoryID Having COUNT(*)>1
) AS A
ORDER BY A.Total DESC
Take a look: http://explainextended.com/2009/07/16/inner-join-vs-cross-apply/