I'm a newbie with sql and I've managed to select rows with relationship to many tables with the sql below. I now have a forth table with items that are "children" to the model. There is a relation between "id" in the models table (526 rows) and "model_id" in the items table (1505 rows). I would now want to count the items in the items table that have the same model_id as the id in the models table and output them as Items_in_model.
SELECT models.id AS Id, categories.name AS Category, models.category_name
AS CategoryName, manufacturers.name AS Manufacturer, models.model AS Model,
models.day_price AS dayprice, models.week_price AS weekprice
FROM
models, categories, manufacturers
WHERE models.category=categories.id AND
models.manufacturer=manufacturers.id
ORDER BY CategoryName ASC
I got the counting working "standalone" with this sql
SELECT COUNT(items.id) AS Count FROM items WHERE items.model_id
LIKE 2
I've tried many different approaches but this is the only one that didn't give me an error but only outputs one row (of 526) and the count is (1505 as in all items)
SELECT models.id AS Id, categories.name AS Category,
models.category_name AS CategoryName, COUNT(items.id) AS Count,
manufacturers.name AS Manufacturer, models.model AS Model,
COUNT(DISTINCT(items.id)) AS ModelCount, models.day_price AS dayprice,
models.week_price AS weekprice
FROM
models, categories, manufacturers, items
WHERE models.category=categories.id AND
models.manufacturer=manufacturers.id AND models.id=items.model_id
ORDER BY CategoryName ASC
Thanks in advance!
Your goal is not 100% clear, but here is my guess:
SELECT m.id AS Id,
c.name AS Category,
m.category_name AS CategoryName,
manufacturers.name AS Manufacturer,
m.model AS Model,
COUNT(i.id) AS ModelCount,
m.day_price AS dayprice,
m.week_price AS weekprice
FROM models m
LEFT JOIN categories c
ON m.category=c.id
LEFT JOIN manufacturers
ON m.manufacturer=manufacturers.id
LEFT JOIN items i
ON m.id=i.model_id
GROUP BY m.id
UPDATE Not sure about your new question, But I doubt you need extra JOIN. Try this way:
SELECT m.id AS Id,
c.name AS Category,
m.category_name AS CategoryName,
manufacturers.name AS Manufacturer,
m.model AS Model,
COUNT(i.id) AS ModelCount,
SUM(IF(i.reservable = 1,1,0)) AS ModelReservableCount,
m.day_price AS dayprice,
m.week_price AS weekprice
FROM models m
LEFT JOIN categories c
ON m.category=c.id
LEFT JOIN manufacturers
ON m.manufacturer=manufacturers.id
LEFT JOIN items i
ON m.id=i.model_id
GROUP BY m.id
Related
I am trying to develop an enquiry management system for an institute.
I have 3 tables in mysql db.
leads_course_category table keeps course categories and has the columns: category_id, category_name, category_created_time, category_deleted.
leads_course_details table stores courses under categories and has the columns: course_id, course_category_id, course_name.
leads_enquiry_details table stores enquiry details and has the columns: enquiry_id, enquiry_name, leads_course_details_course_id, enquiry_deleted
I need to find the number of enquiries for each category.
I tried the following query:
SELECT category_name,COUNT(*) as COUNT
FROM leads_course_category
RIGHT JOIN leads_course_details
on category_id=leads_course_details.course_category_id
RIGHT JOIN `leads_enquiry_details`
on leads_course_details.course_id= leads_enquiry_details.leads_course_details_course_id
WHERE leads_enquiry_details.enquiry_deleted=1
GROUP BY leads_course_category.category_id
This query skips all the categories having null values, but I need to show that as count of zero.
Please help me to resolve this.
The condition enquiry_deleted = 1 must be moved to the ON clause:
select c.category_name, count(ed.enquiry_id) count
from leads_course_category c
left join leads_course_details cd on c.category_id = cd.course_category_id
left join leads_enquiry_details ed on cd.course_id = ed.leads_course_details_course_id and ed.enquiry_deleted = 1
group by c.category_id, c.category_name
So I have a product/categories/brands structure where a products categories are identified by a column containing a comma separated list of category IDs, i.e. 101,105,108, as well as a brand ID column.
I'm trying to get a list of all the products, replace the category IDs with a comma separated list of category names, and also the brand name.
I have the following query that works:
SELECT
productid AS product_id,
prodname AS name,
prodcode AS code,
proddesc AS description,
prodprice AS price,
GROUP_CONCAT(c.catname)
FROM
products p,
categories c
WHERE
FIND_IN_SET(c.categoryid, p.prodcatids)
GROUP BY p.productid
However when I try and left join as follows to also get the brand name, it breaks and says that column p.prodbrandid doesn't exist (it does).
SELECT
productid AS product_id,
prodname AS name,
prodcode AS code,
proddesc AS description,
prodprice AS price,
b.brandname AS brand,
GROUP_CONCAT(c.catname)
FROM
products p,
categories c
LEFT JOIN
brands b ON p.prodbrandid = b.brandid
WHERE
FIND_IN_SET(c.categoryid, p.prodcatids)
GROUP BY p.productid
Any pointers to what I'm missing would be greatly appreciated!
From the advice in the comments:
SELECT
p.productid AS product_id,
p.prodname AS name,
p.prodcode AS code,
p.proddesc AS description,
p.prodprice AS price,
b.brandname AS brand,
GROUP_CONCAT(c.catname)
FROM
products p
INNER JOIN categories c on FIND_IN_SET(c.categoryid, p.prodcatids) > 0
LEFT JOIN brands b ON p.prodbrandid = b.brandid
GROUP BY p.productid
It's not ideal to store data as comma separated lists though; this really should be split out to an additional table that breaks down the many:many relationship between product and category (multiple products can have multiple categories) into two 1:many relationships (a productcategories table, that has a productid,categoryid pair)
Consider something like this as a one time op:
CREATE TABLE ProductCategories(ProductId INT, CategoryId INT)
INSERT INTO ProductCategories
SELECT
p.productid, c.categoryid
FROM
products p
INNER JOIN categories c on FIND_IN_SET(c.categoryid, p.prodcatids) > 0
Then use it going forwards, and drop the categories column
I have three tables as below, each product may belong to multiple categories.
PRODUCT TABLE AS P
1. ID
2. NAME
CATEGORY TABLE AS C
1. ID
2. NAME
RELATION TABLE AS R
1. ID
2. P_ID
3. C_ID
Now I want to get a list of all products in product table, and with their belonging category name display as well.
How do I write this query?
I can get the category ids pulled from the same query, but don't know how to get all the name pulled as well. Here's what I tried.
select p.*,y.*
from p
left join (select p_id,group_concat(c_id) as category_ids
from relation group by p_id) as y on p.id=y.p_id
Do both JOIN operations (to the relation table, and from there to the table containing the category names) and feed the result to your aggregation function (GROUP_CONCAT)
SELECT P.Name, GROUP_CONCAT(DISTINCT C.Name ORDER BY C.Name SEPARATOR '|') categories
FROM Product P
LEFT JOIN Relation R ON P.ID = R.P_ID
LEFT JOIN Category C ON R.C_ID = C.ID
GROUP BY P.ID, P.Name
This will give you one row per product with the categories separated by |.
This uses LEFT JOIN operations so it won't suppress products that have no categories.
Select P.Name, C.Name
From RELATION R Inner Join PRODUCT P
On R.P_ID=P.Id
Inner Join Category C
On C.Id=R.C_ID
This query will get you all the products, with their corresponding category.
I want to give you a small explanation about the difference between Inner Join and Left Join.
If we take as an example 2 tables :
TA(idA, description) and TB(idB, idA, description).
Select TA.description, TB.description
From TA Inner Join TB On TA.IdA = TB.IdA
will get only the rows in TA, that have a corresponding one in TB.
On the other side,
Select TA.description, TB.description
From TA Left Join TB On TA.IdA = TB.IdA
will get all the rows of TA and if the row in TA doesn't have a corresponding one in TB, TB.description for this row will be NULL.
Hope this helps!
I have these tables:
Customer = {id,firstname,last name,street,city}
Invoice = {id, customerid, total}
Item = {invoiceid, item, productid, quantity, cost}
Product = {id, name, price}
I would like to get the first name of the customer and the list of products what he bought.
I have created an sql code:
select customer.firstname, product.name from product
inner join item on item.productid = product.id
inner join invoice on invoice.id=item.invoiceid
inner join customer on customer.id=invoice.customerid
where customer.id=24
the customer.id is 24, because on this id I should get only 3 items' name.
Unfortunately, I am getting multiplication of these items.
What should I repair in my query?
I am getting multiplication of these items.
That is how relational databases work when you ask for a join. You get a Cartesian Product of the matching records.
However, MySQL has a facility that lets you put multiple values into a single field - it's called group_concat:
SELECT
customer.firstname
, GROUP_CONCAT(product.name SEPARATOR ', ')
FROM product
INNER JOIN item ON item.productid = product.id
INNER JOIN invoice ON invoice.id=item.invoiceid
INNER JOIN customer ON customer.id=invoice.customerid
WHERE customer.id=24
GROUP BY customer.id
Note the use of GROUP BY, which "merges" all rows for the same customer id into a single group, on which GROUP_CONCAT operates.
I have the following query, the job scenario is:
I have three tables. Categories, Roles and Roles_to_categories table.
roles_to_categories table:
--id-- --role_id-- --category_id--
A role in roles table, may be bound to several categories in a pivot table named roles_to_categories. I want a role, for instance admin to fetch all the categories from the table categories which are bound to it in table roles_to_categories.
It works fine, but the problem is when aggregation comes in: GROUP_CONCAT().
I want to just get the list of parent categories, and include their children in a separate column by using GROUP_CONCAT(). My problem is that GROUP_CONCAT() seems to ignore the roles_to_categories pivot table when it retrieves the list of children, which means it includes the children of the a certain category that is NOT ALLOWED (I mean there is no record in roles_to_categories to bind it a role)
The query is:
select categories.name as cat_name, categories.id as cat_id,
roles.name as role_name, roles.id as role_id, roles_to_categories.id as cat_id, roles_to_categories.role_id as role_id,
roles_to_categories.category_id,
group_concat('name: ', categories2.name) as cat_children
FROM roles left join roles_to_categories on roles.id = roles_to_categories.role_id
left join categories on roles_to_categories.category_id = categories.id
left join categories as categories2 on categories2.parent_id = categories.id
WHERE roles.name = "admin";
It selects required columns from all three tables, starting from roles then it left joins to roles_to_categories to get its related records and then re-left-joins on categories table from roles_to_categories to select categories whose ids exists in the fetched records and ....
group_concat is an aggregate - you'll need to group by all non-aggregated columns in your select list.
You've also included multiple aliases of both sides of joined columns in your query - this will be confusing and redundant, and aliased category.id and roles_to_category.id to cat_id.
In this case, since you want to concatenate all children of a parent category, this will be like so:
select
categories.name as cat_name, categories.id as cat_id,
roles.name as role_name, roles.id as role_id,
roles_to_categories.id as roles_to_cat_id,
group_concat('name: ', categories2.name) as cat_children
FROM
roles left join roles_to_categories
on roles.id = roles_to_categories.role_id
left join categories on roles_to_categories.category_id = categories.id
left join categories as categories2 on categories2.parent_id = categories.id
WHERE
roles.name = 'admin'
GROUP BY
categories.name, categories.id, roles.name, roles.id, roles_to_categories.id;