count(distinct(col_name)) not working in my sql [duplicate] - mysql

This question already has answers here:
Query using group_concat is returning only one row
(4 answers)
Closed 2 years ago.
I am newbie in mysql, for learning i am using sample database of w3schools. in that i want to create a view which will for each supplier, list the supplier name, the count of distinct products by the supplier (PCount), the count of distinct product categories by the supplier (CCount).
here is my table structures
Suppliers Products
-------------------- ----------------------------
SupplierID ProductID
SupplierName ProductName
ContactNumber SupplierID
Address CategoryID
City Unit
PostalCode Price
Country
Phone
What i have try is
SELECT s.SupplierName, COUNT(DISTINCT(p.ProductID)) as PCount, COUNT(DISTINCT(p.CategoryID)) as CCount FROM Suppliers as s
right join Products as p
on s.SupplierID = p.SupplierID
this is only giving me single SupplierName not all the supplier details with distinct product and distinct category.
Any help would be much appreciated.

Give this a shot:
SELECT s.SupplierName,
COUNT(p1.ProductID) AS PCount,
COUNT(DISTINCT p2.CategoryID) AS CCount
FROM Suppliers s
LEFT JOIN Products p1 ON s.SupplierID=p1.SupplierID
LEFT JOIN Products p2 ON s.SupplierID=p2.SupplierID
GROUP BY s.SupplierName
ORDER BY s.SupplierName

Related

SQL LEFT JOIN with two tables - table order and performance

I got an LEFT JOIN exercise at school:
"List all category names with the number of their products."
Used were two tables from the northwind DB: products (77 rows) and categories (8 rows)
I thought the product table should come first, since the main-data (number of products) will be found there and only the 8 category names will be needed from the joined table. Our teacher argued, that the categories table needs to be the main table, but i still can't understand why.
The two queries are:
SELECT C.CategoryID, CategoryName, COUNT(ProductID) [Count]
FROM Categories C LEFT JOIN Products P
ON C.CategoryID = P.CategoryID
GROUP BY C.CategoryID, CategoryName
and
SELECT P.CategoryID, CategoryName, COUNT(ProductID) [Count]
FROM Products P LEFT JOIN Categories C
ON P.CategoryID = C.CategoryID
GROUP BY CategoryName, P.CategoryID
Can anybody explain to me why, in this case, a certain order of used tables matters in terms of theoretical performance?And if: how so? (does size matter?;))
The name of the exercise tells yo what is the first table in your case.
"List all category names with the number of their products."
So get the all category names. Category names is what you HAVE TO SHOW - ALL OF THEM. You want to show all of them regardless of the fact is there a matching CategoryID in the Products table.
For example, if you want to show all product names with number of their categories then you want to show all product names regardless if there exists matching ProductID in Categories table.
Here is the demo
This demo shows you what the two queries will return if we have 3 categories and one product. It is not the best demo in the world but it does the trick I believe.
The tables:
create table Categories (CategoryID int, CategoryName varchar(20))
create table Products (ProductID int, CategoryID int)
The data:
insert into Categories values(1, 'Cat1');
insert into Categories values(2, 'Cat2');
insert into Categories values(3, 'Cat3');
insert into Products values(1, 1);
Query1:
SELECT C.CategoryID, CategoryName, COUNT(ProductID) as Cnt
FROM Categories C
LEFT JOIN Products P ON C.CategoryID = P.CategoryID
GROUP BY C.CategoryID, CategoryName
Result1:
CategoryID CategoryName Cnt
1 Cat1 1
2 Cat2 0
3 Cat3 0
Query2:
SELECT P.CategoryID, CategoryName, COUNT(ProductID) as Cnt
FROM Products P
LEFT JOIN Categories C ON P.CategoryID = C.CategoryID
GROUP BY CategoryName, P.CategoryID
Result2:
CategoryID CategoryName Cnt
1 Cat1 1
I see in your question that you say:
"Used were two tables from the northwind DB: products (77 rows) and categories (8 rows)"
So maybe it is strange now for you how can my example be like this and yours "since the results of both queries are obviousely the same" ?
Here is the demo that will show you how it can be the same with different set of data.
As an aside, here is another way to get the desired results.
SELECT C.CategoryID, C.CategoryName
( SELECT COUNT(*)
FROM Products AS P
WHERE P.CategoryID = c.CategoryID
) AS "Count"
FROM Categories AS C
The performance will be about the same as the 'correct' LEFT JOIN formulation.
A further note: COUNT(x) does the extra check to see that x IS NOT NULL; COUNT(*) simply counts the number of relevant rows.
In some other situation, you may need COUNT(DISTINCT productID); I suspect you do not need it in this case.

Join 3 tables using a single Query

I have 3 tables, retailer,product and manufacturer.I will pass retailerID to the query and it should return the manufacturer Details.
criteria:
1)from the given input (retailerID) fetch productID from the retailer table.
2)Using productID get the manufacturerID from product table.
3)Get the complete details of manufacturer from manufacturer table using manufacturerID.
Can anyone help me to solve this.Thanks in advance.
Based on the description of your question, I understood that this is your requirement:
select *
from manufacturer
where manufacturerID = (
select manufacturerID
from Product
where productID = (
select productID
from retailer
where retailerID=#retailerID)
)
Above query is written in subquery format, which can easily be converted into join format:
select *
from Manufacturer m
join Product p on m.manufacturerID = p.manufacturerID
join retailer r on r.ProductID = p.ProductID
where r.RetailerID = #retailerID

SQL query to retrive data [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
For these relations:
Customer(CID, Name, City, State),
Order(OID, CID, Date), and
Product(PID, ProductName, Price)
LineItem(LID, OID,PID, Number, TotalPrice),
where CID is a customer id and is a key for Customer, OID is an order id and is a key for Order, and LID is a line item id and is a key for LineItem. In addition the attribute CID of Order is a foreign key referring to the CID of Customer, that is, for each CID c of Order there is exactly one tuple of Customer whose CID attribute is c. The OID of LineItem is a foreign key referring to the OID of Order. There are several line items for the same order, a line item refers to a product and contains the quantity ordered for the product.
What is the query for:
List the products bought by all the customers of 'mycity'
#Edit
This is what I've tried so far:
Select ProductName
from Product
where PID in (
select PID
from LineItem
where OID in(
Select OID
from Order
where CID in(
select CID from customer where city='mycity'
)
)
);
This query however will return all the products bought by all customers from mycity. And the question requires only those products that everyone from 'mycity' have bought.
Not sure how to implement "All in" condition
#Edit2: Finally solved it :) Can someone please verify??
SELECT ProductName FROM Product
INNER JOIN LineItem ON LineItem.PID=Product.PID
INNER JOIN `Order` ON Order.OID=LineItem.OID
INNER JOIN Customer ON Order.CID=Customer.CID
WHERE Customer.City='mycity'
I think this should work
This query is solved in 2 parts: Create a view and query that view
Create view hview as (SELECT distinct count(distinct Customer.CID) as
uniquecustomer, count(distinct Customer.name), product.pid, product.Productname
FROM myorder
INNER JOIN Customer ON myorder.CID = Customer.CID
INNER JOIN LineItem ON myorder.OID = LineItem.oid
INNER JOIN Product ON Product.PID = LineItem.PID
where Customer.city = 'mycity'
group by Product.PID);
select productname from product where pid in(
select PID from hview where uniquecustomer in( SELECT count(distinct Customer.CID)
FROM myorder
INNER JOIN Customer ON myorder.CID = Customer.CID
INNER JOIN LineItem ON myorder.OID = LineItem.oid
INNER JOIN Product ON Product.PID = LineItem.PID
where Customer.city = 'mycity'));
Logic Used: create a view of items with distinct owners from mycity.
Query that view to find items that have distinct owners equal to number of distinct customers in mycity. Every item that has a distinct number of owners equal to the number of distinct customers of mycity are the products that are bought by everyone in mycity.
*myorder is the table name I used instead of order since thats a reserve word.
Better version in a single query:
select p1.productname from Product p1, myorder s1, lineitem l1, customer c1
where l1.pid=p1.pid
and l1.OID=s1.oid
and c1.cid=s1.cid
and c1.city='mycity'
group by p1.ProductName
having count(distinct c1.cid)=(select count(1) from customer c2 where c2.city='mycity');

Inverse of Inner join (Intersect) with multiple foreign keys

Hi I want to get opposite of intersect from two tables.
I have a sale table and purchase table. What I want to do is get all purchases ids where not included in the sales table.
sale table
sale_id (pk)
product_id (fk)
purchase_id (fk)
purchase table
product_id (fk)
purchase_id (pk)
SELECT DISTINCT purchase_id
, product_id
FROM
purchase
INNER JOIN sale
USING (purchase_id, product_id);
Here is an example:
If I run the above code, this will be the result.
purchase_id product id
1 1
1 2
1 4
2 1
2 3
Now I want to get:
purchase_id product id
1 3
2 2
In short I want to get inverse of above code. Thanks in advance.
Okay, I think I understand better now.
This should return any entry in purchase that have no matching entry in sales.
SELECT
`purchase`.`purchase_id`, `purchase`.`product_id`
FROM `purchase`
LEFT JOIN `sale` ON `sale`.`purchase_id` = `purchase`.`purchase_id` AND `sale`.`product_id` = `purchase`.`product_id`
WHERE
`sale`.`sale_id` IS NULL
ORDER BY
`purchase`.`purchase_id`, `purchase`.`product_id`
If you want to get all the purchases that have no related values in the sales table, you can use a LEFT JOIN:
select
p.purchase_id
from
purchase as p
left join sale as s on p.purchase_id = s.purchase_id
where
s.purchase_id is null;
"Unilateral" joins (LEFT JOIN, RIGHT JOIN) are useful when you want to get data from a table even if data in another related table does not exist. Of course, that means that you can filter data from one table when there's no related data in a second table.
Hope this helps.
Looking at your updated question and your comment, I think that you want all the possible combinations not used.
You'll need to split this in two steps:
First you need all the possible combinations of purchase_id and sale_id values (the "cartesian product" of both the sets).
Then you need to get all the combinations already used.
Finally you need to exclude all the combinations already used.
This can be done using subqueries.
Step 1.
select distinct p.purchase_id, s.product_id from purchase as p, sale as s;
Step 2. (Your query)
select distinct
purchase_id, product_id
from
purchase as p
inner join sale as s
on (p.purchase_id = s.purchase_id and p.product_id = s.product_id);
Step 3. Put it all together
select
a.*
from
(select distinct p.purchase_id, s.product_id from purchase as p, sale as s) as a
left join (
select distinct
purchase_id, product_id
from
purchase as p
inner join sale as s
on (p.purchase_id = s.purchase_id and p.product_id = s.product_id)
) as e on (a.purchase_id = e.purchase_id and a.product_id = e.product_id)
where
e.purchase_id is null and e.product_id is null;

How can I write this query to filter the results properly?

I have 3 tables I am wanting to join:
equipment
equipmentNo
assetNo
subCategoryNo
doNo
userNo
locationNo
isocNo
emergency
ariNo
makeNo
modelNo
serial
kitNo
purchaseDate
purchasePrice
comments
surplused
employees
userNo
fname
lname
doNo
emergency
subcategories
subCategoryNo
subCategory
categoryNo
replacementCycle
I need to get a set of data that includes all of the equipment information ordered by 'doNo' and 'lname' from employees which are linked by 'userNo' and the equipment 'subCategoryNo' needs to be only those from subcategories where 'categoryNo' equals 2.
I got this far before getting lost and confused.
SELECT equipment.*, employees.lname, employees.fname
FROM equipment
LEFT JOIN employees
USING (userNo)
ORDER BY equipment.doNo, employees.lname;
I could not figure out how to limit this to only 'categoryNo' 2;
SELECT equipment.*, employees.lname, employees.fname
FROM equipment
LEFT JOIN employees USING (userNo)
JOIN subcategories USING(subCategoryNo)
WHERE subcategories.categoryNo=2
ORDER BY equipment.doNo, employees.lname;