selecting from multiple tables with counter - mysql

I have two tables one holds a category with column catID,catName and the other has the catID as a foreign key, now i want to select all the total items on the second table based on their catID.
E.g. What is the total number of individual element if their category is 1,2,3,4 etc. Pls code hints will help thanks.

SELECT
c.cat_id
,count(*) as occurence
FROM category c
INNER JOIN table2 t ON (c.cat_id = t.cat_id)
GROUP BY c.cat_id
If you want the categories with occurence = 0 then do:
SELECT
c.cat_id
,count(t.cat_id) as occurence
FROM category c
LEFT JOIN table2 t ON (c.cat_id = t.cat_id)
GROUP BY c.cat_id
Links:
http://dev.mysql.com/doc/refman/5.5/en/group-by-functions.html
http://www.1keydata.com/sql/sqlgroupby.html

SELECT catName, COUNT(table2.catId) FROM table1,table2
WHERE table1.catId=table2.catId
GROUP BY catName

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.

SELECT with different values for foreign key

I have 2 tables:
Products(..., category_id)
Categories(id, name, level_1_parent_id, level_2_parent_id)
category_id is foreign key for Categories(id)
If it's first level category level_1_parent_id is NULL,
If second level category level_2_parent_id is NULL, level_1_parent_id is set,
if third level both are set.
I'm selecting products like this
SELECT *
FROM Products
WHERE category_id = ${category_id}
What I need to achieve:
Select products from child categories if its first or second level category.
So for example if I'm selecting from category with id == 1 (which is first level id) I want to select products with category_id equals 1 and other categories with level_1_parent_id == 1 and the same for second level category.
Is that possible somehow?
we can use nested query here.
SELECT * FROM Products WHERE category_id = ${category_id} or
category_id in (select distinct id from Categories where level_1_parent_id = ${category_id} or level_2_parent_id = ${category_id})
You get the category list by joining the table to itself first, then get the products associated with each of the categories found. Note the use of alias's for each of the tables in the from and join clauses.
SELECT *
FROM Categories c1
LEFT JOIN Categories c2
ON c2.level_1_parent_id = c1.id
LEFT JOIN Categories c3
ON c3.level_1_parent_id = c1.id AND c3.level_2_parent_id = c2.id
JOIN Products p
ON p.category_id = c1.id OR p.category_id = c2.id OR p.category_id = c3.id
WHERE c1.category_id = ${category_id}

SQL JOIN: Select Records from Another Table With Matching IDs

I am having trouble building a correct SQL JOIN statement to select some records from another table.
--Table Product:
ID
Name
CatID1
CatID2
and
--Table Category:
CatID
CategoryName
Product.CatID1, Product.CatID2 are referenced to Category.CatID
So I really want to select Product fields and replace Product.CatID1, Product.CatID2 with Category.CategoryName (for Product.CatID1) and Category.CategoryName (for Product.CatID2).
This obviously does not work but explains what I need:
SELECT Product.ID, Product.Name,
Category.CategoryName as Product.CatID1,
Category.CategoryName as Product.CatID2
from product, categories;
All you need is a double LEFT JOIN to categories table:
SELECT p.ID, p.Name,
c1.CategoryName as CatID1,
c2.CategoryName as CatID2
from product AS p
LEFT JOIN categories AS c1 ON p.CatID1 = c1.CatID
LEFT JOIN categories AS c2 ON p.CatID2 = c2.CatID
If there is no match for either CatID1 or CatID2, the corresponding field in the SELECT clause is going to be NULL.
SELECT Product.ID,
Product.Name,
C1.CategoryName as Product.CatID1,
C2.CategoryName as Product.CatID2
FROM Product JOIN Category C1 ON C1.CatID = CatID1
JOIN Category C2 ON C2.CatID = CatID2 ;
Use the category table twice.
What if you decide, in the future, that a product can be in 3 categories? Really, you should have a joining table for these and remove the repeating info from Product.

Pull data from 3 tables

I have 3 tables as follows :
Table 1: Product
id_product [Primary Key],added_time.
Table 2: Category
id_category [Primary Key],Category_name.
Table 3: product_category
id_category,id_product [Both Foreign Keys]
I want to pull Data as
Category_name,No Of Products in this Category,Last time when product was added to Category(Latest product added_time).
You could use this SQL:
SELECT Category.Category_name,
Count(DISTINCT Product.id_product) AS num_products,
Max(Product.added_time) last_added_time
FROM Category
LEFT JOIN product_category
ON product_category.id_category = Category.id_category
LEFT JOIN Product
ON Product.id_product = product_category.id_product
GROUP BY Category.Category_name;
Note that by using LEFT JOIN you will be certain to list all categories even those for which no products exist. If you don't want those, replace both LEFT keywords with INNER.
Note also that in standard SQL you need to GROUP BY any columns you mention in the SELECT list, unless they are aggregated, like with MAX or COUNT.
SELECT C.`Category_name`,
(SUM(IF(P.`id_product`IS NULL,0,1))) AS No_of_Products,
MAX(P.`added_time`) AS Latest_time
FROM
Category C
LEFT JOIN
product_category P_C ON C.`id_category` = P_C.`id_category`
LEFT JOIN
Product P ON P.`id_product` = P_C.`id_product`
GROUP BY C.`id_category`
Hope this helps.

How to get names of relevant ID's from 2 different tables and display them

I have 3 tables, First one has the product ID and Name, Second one has Supplier ID and name, In the 3rd one i have product ID and Supplier ID. While displaying, i want to replace the product ID and supplier ID in the 3rd table with product name and supplier name from the 1st and 2nd table respectively.
Please let me know the query for executing it.
Reference: http://dev.mysql.com/doc/refman/5.7/en/join.html
SELECT * FROM table1
INNER JOIN table2
ON table1.id=table2.id
INNER JOIN table3
ON table2.id=table3.id;
If your tables are named products_master, stockists_master, and stockist_product_offer, then you can join the tables and select any of the six columns that you want.
SELECT product_master.name, stockists_master.name
FROM products_master
INNER JOIN stockist_product_offer
ON product_master.id = stockist_product_offer.product_id
INNER JOIN stockists_master
ON stockist_product_offer.stockist_id = stockist.id;
you have to join the tables on IDs so the query is :
let s say that :
* first table : product
* second table : supplier
* third table : match
SELECT P.PRODUCTNAME
S.SUPPLIERNAME
FROM
PRODUCT P
INNER JOIN
MATCH M
ON P.PRODUCTID = M.PRODUCTID
INNER JOIN
SUPPLIER S
ON S.SUPPLIERID = M.SUPPLIERID
ORDER BY 1
;