SQL query multi table selection - sql

I have 3 tables,
- Section table that defines some general item sections.
- Category table -> has a "section" column (foreign key).
- Product table -> has a "category" column (foreign key).
I want to get all products that belong to X section.
How can I do it?
select from select?

Select
prod.*
FROM
Product prod
INNER JOIN Category cat ON prod.category = cat.id
INNER JOIN Section sec ON cat.section = sec.id
WHERE
sec.id = X

Lots of same answers here. For some reason, though, all of them are joining the Section table which is (likely) not necessary.
select
p.*
from
Product p,
Category c
where
p.category_id = c.id and
c.section_id = 123
;
Explicit ANSI JOIN syntax per #nemiss's request:
select
p.*
from Product p
join Category c
on c.id = p.category_id
and c.section_id = 123
;
Possible reason to include Section table: Selecting products based on Section name (instead of ID).
select
p.*
from Product p
join Category c
on c.id = p.category_id
join Section s
on s.id = c.section_id
and s.name = 'Books'
;
If doing this, you'll want to make sure Section.name is indexed
alter table Product add index name;

select s.section, p.*
from section s
inner join category c on c.section = s.section
inner join product p on p.category = c.category
where s.section = 'section1'

select p.*
from Product p
join Category c on p.CategoryId = c.Id
join Section s on c.SectionId = s.Id
where s.Id = #val

Related

How to list products that belong to more than 3 private categories

What's the SQL to find the list of products that belong to more than 3 private categories.
I tried this:
SELECT
products.*
FROM
products
INNER JOIN
product_categories
ON
products.product_id = product_categories.product_id
INNER JOIN
categories
ON
product_categories.category_id = categories.category_id
WHERE
categories.is_private = 1
GROUP BY
categories.category_id
HAVING
COUNT(categories.category_id) > 3
Thanks!
Your query would be correct if you aggregated by products.product_id -- well, depending on the database, you might need to include other columns in the SELECT. But it is valid SQL assuming that product_id is unique in that table.
If you only want the product ids you don't need the products table:
select pc.product_id
from product_categories pc join
categories c
on pc.category_id = c.category_id
where is_private = 1
group by pc.product_id
having count(*) > 3;
you need every product witch .... so you should do group by on productID.also you can add other columns of products that you need in both 'select' and 'group by'
SELECT
products.product_id,products.name
FROM
products
INNER JOIN
product_categories
ON
products.product_id = product_categories.product_id
INNER JOIN
categories
ON
product_categories.category_id = categories.category_id
WHERE
categories.is_private = 1
GROUP BY
products.product_id,products.name
HAVING
COUNT (categories.category_id) > 3
To get all columns of products:
SELECT products.*
FROM products p
WHERE product_id in (SELECT pc.product_id
FROM product_categories pc
INNER JOIN categories c ON pc.category_id = c.category_id
WHERE c.is_private = 1
GROUP BY c.category_id
HAVING COUNT(c.category_id) > 3)
Check this out!
select * from products where product_id in
(select pc.product_id from product_categories inner join categories c on
pc.category_id=c.category_id where c.is_private=1
group by c.category_id having count(c.category_id)>3)

How to make this query on PostgreSQL?

I have three tables:
Customer table
Product Table
Customer_Product Table
I need to make query: Search for customers who bought a certain product (for example, name = "toilet paper") at least 2 times
I don't understand how.. I'm noob in databases.. Please help
You need aggregation :
select c.name
from customer c inner join
customer_product cp
on cp.customer_id = c.customer_id inner join
product p
on p.product_id = cp.product_id
where p.lable = 'toilet paper'
group by c.name
having count(p.lable) > 1;

Joining to return all rows even when there are no results

I'm trying to get a list how many products we've sold, per company, by all categories.
I'd like the results to look like:
Category A Company 1 0
Category A Company 2 0
Category A Company 3 5
Category B Company 1 1
Category B Company 2 4
Category B Company 3 0
So every category is returned, every company is returned, even if there are no sales.
This is the query I'm trying and it should make the structure of the database clear. I've attacked this from a bunch of direction, but can't seem to wrap my head around how to get at what I'm looking for.
SELECT com.Company_Name, c.Category_Name, sum(p.Quantity)
FROM Category c
LEFT JOIN Item i on c.Category_ID = i.Category_ID
LEFT JOIN Products p on p.Item_ID = i.Item_ID
LEFT JOIN Invoice iv on iv.Invoice_ID = p.Invoice_ID
LEFT JOIN Company com on com.Company_Id = iv.Company_ID
group by c.Category_Name, com.Company_Name
Thanks for any help...
Generate the rows with a cross join, then left join in the rest of the information:
SELECT co.Company_Name, ca.Category_Name,
COALESCE(SUM(p.Quantity), 0) as quantity
FROM Category c CROSS JOIN
Company co LEFT JOIN
(Invoice iv JOIN
Products p
ON iv.Invoice_ID = p.Invoice_ID JOIN
Item i
ON p.Item_ID = i.Item_ID
)
ON co.Company_Id = iv.Company_ID AND
c.Category_ID = i.Category_ID
GROUP BY ca.Category_Name, co.Company_Name

Left outer join with only first row

I have a query something like
SELECT S.product_id, S.link, C.id AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
LEFT OUTER JOIN Categories C ON c.product_id = P.id
WHERE P.active = 1
I works fine for me as long as each product has assigned to only one category. But if a product is assigned to many categories it returns all possible combinations.
Can I only select the first one and if a product don't have any category the link should still be returned with category_id = NULL
An easy way is to use outer apply, so as to have a correlated join, and make that a top 1 query. Thus you are able to access all columns of the category record in question. I'm adding a category name here as an example:
select s.product_id, s.link, c.id as category_id, c.name as category_name
from products p
inner join seo s on s.product_id = p.id
outer apply
(
select top 1 *
from categories cat
where cat.product_id = p.id
order by cat.id
) c
where p.active = 1
and p.product_type = 1;
You can use a GROUP BY to accomplish this along with an Aggregate function, most likely MIN or MAX.
Depending on which Category Id you prefer in your result you could select the minimum.
SELECT S.product_id, S.link, MIN(C.id) AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
LEFT OUTER JOIN Categories C ON c.product_id = P.id
WHERE P.active = 1
GROUP BY S.product_id, S.link
Or the maximum.
SELECT S.product_id, S.link, MAX(C.id) AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
LEFT OUTER JOIN Categories C ON c.product_id = P.id
WHERE P.active = 1
GROUP BY S.product_id, S.link
Alternate solution using subquery:
SELECT S.product_id, S.link,
(
SELECT C.id FROM Categories C WHERE C.product_id = P.id AND
ROW_NUMBER() OVER(ORDER BY /* your sort option goes here*/ ) = 1
) AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
WHERE P.active = 1

Obtain record in right table based on lowest value in middle cross reference table joined to left table

I have a Product table, a Category table, and a cross reference/mapping table in between.
A product can belong to multiple categories.
I want a query to produce the Product Id and the Category Name.
As the product can belong to multiple categories, I want to only include the one that equates to the lowest value in Product_Category_Mapping.DisplayOrder.
Here is a limited sample data set from the three tables
Table: Product PC_Mapping Category
Column:(ID) (DispOrd) (Name)
Records
----------------------------------
1 10 Milk <----- just return this row
1 20 Dairy
1 30 Cheese
#John: I think your query needs little modification. I think Chad wants to pick with lowest value for each product so a group by should be added.
SELECT p.ID as [Product ID], c.Name as Category, m.x
FROM Product p INNER JOIN (
SELECT ProductID, Min(DisplayOrder) as x FROM Product_Category_Mapping GROUP BY ProductId) m ON p.ID = m.ProductID
INNER JOIN Product_Category_Mapping pc ON p.ID = pc.ProductID AND m.x = pc.DisplayOrder
INNER JOIN Category c ON pc.CategoryID = c.ID
I think this should do it, though simpler answers may be possible:
SELECT p.ID as [Product ID], c.Name as Category
FROM Product p INNER JOIN (
SELECT ProductID, Min(DisplayOrder) as x FROM Product_Category_Mapping) m ON p.ID = m.ProductID
INNER JOIN Product_Category_Mapping pc ON p.ID = pc.ProductID AND m.x = pc.DisplayOrder
INNER JOIN Category c ON pc.CategoryID = c.ID