Joining 6 tables into single query? - sql

Hey can anyone help me join the 5 tables below into a single query? I currently have the query below but is doesn't seem to work as if there are two products with the same ID inside the hires table all of the products are returned form the products table which is obviously wrong.
SELECT products.prod_id, products.title, products.price, product_types.name,
listagg(suppliers.name, ',') WITHIN GROUP(ORDER BY suppliers.name) suppliers
FROM products
INNER JOIN product_suppliers ON products.prod_id = product_suppluer.prod_id
INNER JOIN product_types ON product_types.type_id = products.type_id
INNER JOIN suppliers ON product_suppliers.supp_id = suppliers.supp_id
LEFT OUTER JOIN hires ON hires.prod_id = products.prod_id
WHERE (hires.hire_end < to_date('21-JAN-13') OR hires.hire_start > to_date('26-JAN-13'))
OR hires.prod_id IS NULL
GROUP BY products.prod_id, products.title, products.price, product_types.name
Table data:
PRODUCTS
--------------------------------------------
| Prod_ID | Title | Price | Type_ID |
|------------------------------------------|
| 1 | A | 5 | 1 |
| 2 | B | 7 | 1 |
| 3 | C | 3 | 2 |
| 4 | D | 3 | 3 |
|------------------------------------------|
PRODUCT_TYPES
----------------------
| Type_ID | Type |
|--------------------|
| 1 | TYPE_A |
| 2 | TYPE_B |
| 3 | TYPE_C |
| 4 | TYPE_D |
|--------------------|
PRODUCT_SUPPLIERS
-------------------------
| Prod_ID | Supp_ID |
|-----------------------|
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
|-----------------------|
SUPPLIERS
----------------------
| Supp_ID | Name |
|--------------------|
| 1 | SUPP_A |
| 2 | SUPP_B |
| 3 | SUPP_C |
| 4 | SUPP_D |
|--------------------|
HIRES
---------------------------------------------------------------
| Hire_ID | Prod_ID | Cust_ID | Hire_Start | Hire_End |
|-----------------------|------------|------------------------|
| 1 | 1 | 1 | 22-Jan-13 | 23-Jan-13 |
| 2 | 2 | 2 | 27-Jan-13 | 29-Jan-13 |
| 3 | 1 | 3 | 30-Jan-13 | 31-Jan-13 |
|-----------------------|------------|------------|-----------|
PRODUCTS
--------------------------------
| Cust_ID | Name | Phone |
|------------------------------|
| 1 | Cust_A | 555-666 |
| 2 | Cust_B | 444-234 |
| 3 | Cust_C | 319-234 |
| 4 | Cust_D | 398-092 |
|------------------------------|
The output from the query at the moment looks like this:
-------------------------------------------------------------
| Prod_ID | Title | Price | Type_ID | Suppliers |
|------------------------------------------|----------------|
| 1 | A | 5 | Type_A | SUPP_A,SUPP_B |
| 2 | B | 7 | Type_B | SUPP_B |
| 3 | C | 3 | Type_C | SUPP_C |
| 4 | D | 3 | Type_D | SUPP_D |
|------------------------------------------|----------------|
When it should look like this surely? as Prod_ID '1' is hired out between the dates in the query
-------------------------------------------------------------
| Prod_ID | Title | Price | Type_ID | Suppliers |
|------------------------------------------|----------------|
| 2 | B | 7 | Type_B | SUPP_B |
| 3 | C | 3 | Type_C | SUPP_C |
| 4 | D | 3 | Type_D | SUPP_D |
|------------------------------------------|----------------|
If anyone can help modify the query to output as suggested i would be really grateful. Because my understanding is that it should work as written?

Your issue is that Prod_Id 1 is both in and out of those date ranges. So instead, use a subquery to filter out which Prod_Id are in those ranges, and exclude those.
This is a much simplified version of your query:
SELECT P.Prod_ID
FROM Products P
LEFT JOIN (
SELECT Prod_ID
FROM Hires
WHERE hire_end >= To_Date('20130121', 'yyyymmdd') AND hire_start <= To_Date('20130126', 'yyyymmdd')
) H ON P.Prod_ID = H.Prod_ID
WHERE h.prod_id IS NULL
And the SQL Fiddle.
Assuming I copied and pasted correctly, this should be your query:
SELECT products.prod_id, products.title, products.price, product_types.name,
listagg(suppliers.name, ',') WITHIN GROUP(ORDER BY suppliers.name) suppliers
FROM products
INNER JOIN product_suppliers ON products.prod_id = product_suppluer.prod_id
INNER JOIN product_types ON product_types.type_id = products.type_id
INNER JOIN suppliers ON product_suppliers.supp_id = suppliers.supp_id
LEFT JOIN (
SELECT Prod_ID
FROM Hires
WHERE hire_end >= To_Date('20130121', 'yyyymmdd') AND hire_start <= To_Date('20130126', 'yyyymmdd')
) H ON products.Prod_ID = H.Prod_ID
WHERE H.Prod_ID IS NULL
GROUP BY products.prod_id, products.title, products.price, product_types.name
Hope this helps.

Your left outer join will return null values when there is no match, meaning you still have a row (with no HIRE table data) when the results of this join query are Null:
LEFT OUTER JOIN hires ON hires.prod_id = products.prod_id
WHERE (hires.hire_end < to_date('21-JAN-13')
OR hires.hire_start > to_date('26-JAN-13'))
OR hires.prod_id IS NULL
Try adding a select from the hires table (eg. hire.Hire_Start) to see this happening, then switch it to an inner join as well and I think your problem will be solved.
OR add a WHERE clause on the full query with something like hire.Hire_Start is not null
EDIT
If you change your original query to:
SELECT hires.Hire_Start, products.prod_id, products.title, products.price, product_types.name,
listagg(suppliers.name, ',') WITHIN GROUP(ORDER BY suppliers.name) suppliers
FROM products
INNER JOIN product_suppliers ON products.prod_id = product_suppluer.prod_id
INNER JOIN product_types ON product_types.type_id = products.type_id
INNER JOIN suppliers ON product_suppliers.supp_id = suppliers.supp_id
LEFT OUTER JOIN hires ON hires.prod_id = products.prod_id
WHERE (hires.hire_end < to_date('21-JAN-13') OR hires.hire_start > to_date('26- JAN-13'))
OR hires.prod_id IS NULL
GROUP BY products.prod_id, products.title, products.price, product_types.name
What comes back in the Hire_Start column?
Then if you add it to the where clause do you get the expected result:
SELECT hires.Hire_Start, products.prod_id, products.title, products.price, product_types.name,
listagg(suppliers.name, ',') WITHIN GROUP(ORDER BY suppliers.name) suppliers
FROM products
INNER JOIN product_suppliers ON products.prod_id = product_suppluer.prod_id
INNER JOIN product_types ON product_types.type_id = products.type_id
INNER JOIN suppliers ON product_suppliers.supp_id = suppliers.supp_id
LEFT OUTER JOIN hires ON hires.prod_id = products.prod_id
WHERE (hires.hire_end < to_date('21-JAN-13') OR hires.hire_start > to_date('26- JAN-13'))
OR hires.prod_id IS NULL
WHERE hires.Hire_Start is not null
GROUP BY products.prod_id, products.title, products.price, product_types.name
Finally, dropping the Outer Join altogether, does this work as expected?
SELECT hires.Hire_Start, products.prod_id, products.title, products.price, product_types.name,
listagg(suppliers.name, ',') WITHIN GROUP(ORDER BY suppliers.name) suppliers
FROM products
INNER JOIN product_suppliers ON products.prod_id = product_suppluer.prod_id
INNER JOIN product_types ON product_types.type_id = products.type_id
INNER JOIN suppliers ON product_suppliers.supp_id = suppliers.supp_id
INNER JOIN hires ON hires.prod_id = products.prod_id
WHERE (hires.hire_end < to_date('21-JAN-13') OR hires.hire_start > to_date('26- JAN-13'))
GROUP BY products.prod_id, products.title, products.price, product_types.name
And note: is the OR Hires.prod_ID sopposed to indicate that if the result returns no hire information it is available, in which case you need to write the query more like the other answer provided.

Here is some code that may help you:
SELECT L.V_PRODUCT_ID "PROD_ID" , L.TITLE "TITLE" , L.PRICE "PRICE" , L.TYPE "TYPE" , S.NAME "SUPPLIERS"
FROM
(SELECT V_PRODUCT_ID , TITLE , PRICE , TYPE , SUPPLIER_ID FROM
((select p.prod_id v_product_id , p.title TITLE , p.price PRICE , t.type TYPE
from products p , products_types t
where p.type_id = t_type_id) A
JOIN
(SELECT PROD_ID VV_PRODUCT_ID , SUPP_ID SUPPLIER_ID
FROM PRODUCTS_SUPPLIERS) H
ON (A.V_PRODUCT_ID = H.VV_PRODUCT_ID))) L
JOIN
SUPLLIERS S
ON (L.SUPPLIER_ID = S.SUPP_ID);

SELECT Emp.Empid, Emp.EmpFirstName, Emp.EmpLastName, Dept.DepartmentName
FROM Employee Emp
INNER JOIN Department dept
ON Emp.Departmentid=Dept.Departmenttid

Related

Replace subqueries in where statement

I've built a query that intends to find products (products table) with both a 'used' offer and a 'new' offer, and get the lowest price for each. A product can have multiple offers (link_prices table). The offer's condition is determined by the name of the merchant (merchants table): a name without used and occasion is a 'new' offer, a name with used is a 'used' offer.
Here's a sample of the tables (PostgreSQL):
merchants
+----+---------------+
| id | name |
+----+---------------+
| 1 | amazon_used |
| 2 | ebay_location |
| 3 | amazon |
| 4 | target |
| 5 | target_used |
+----+---------------+
link_prices
+----+-------------+------------+-------+
| id | merchant_id | product_id | price |
+----+-------------+------------+-------+
| 1 | 1 | 1 | |
| 2 | 1 | 2 | 20 |
| 3 | 4 | 2 | 30 |
| 4 | 5 | 2 | 5 |
| 5 | 2 | 3 | 10 |
| 6 | 1 | 4 | 80 |
| 7 | 1 | 3 | 100 |
+----+-------------+------------+-------+
In this case, I'm expecting my query to return
+------------+----------------+---------------+
| product_id | min_used_price | min_new_price |
+------------+----------------+---------------+
| 2 | 5 | 30 |
+------------+----------------+---------------+
I've got the following query to work but I feel like I shouldn't need to use subqueries to achieve this. I just can't work my head around it. Any help would be appreciated to optimize this query.
SELECT products.id,
MIN(CASE WHEN merchants.name ILIKE '%used%' THEN link_prices.price END) as min_used_price,
MIN(CASE WHEN merchants.name NOT ILIKE '%used%' THEN link_prices.price END) as min_new_price
FROM products
INNER JOIN link_prices ON link_prices.product_id = products.id
INNER JOIN merchants ON merchants.id = link_prices.merchant_id
WHERE
products.id IN (
SELECT products.id
FROM products
INNER JOIN link_prices ON link_prices.product_id = products.id
INNER JOIN merchants ON merchants.id = link_prices.merchant_id
AND merchants.name ILIKE '%used%'
AND link_prices.price IS NOT NULL
AND link_prices.price <> 0
)
AND products.id IN (
SELECT products.id
FROM products
INNER JOIN link_prices ON link_prices.product_id = products.id
INNER JOIN merchants ON merchants.id = link_prices.merchant_id
AND merchants.name NOT ILIKE '%used%'
AND merchants.name NOT ILIKE '%location%'
AND link_prices.price IS NOT NULL
AND link_prices.price <> 0
)
GROUP BY products.id
Thanks a ton!
Your description makes this sound like conditional aggregation:
select lp.product_id,
min(lp.price) filter (where m.name like '%used') as min_used_price,
min(lp.price) filter (where m.name not like '%used') as min_new_price
from merchants m join
link_prices lp
on lp.merchant_id = m.id
group by lp.product_id;
You sample query is much more complicated and has conditions that are not mentioned in the text of the question. But I think this structure will work for what you want to do.

Issue with SQL join and group

I have 4 tables I am trying to join and then group data. The data consists of jobs, invoices and accounts. I want to generate a total of each account in each job.
I have the following tables:
Jobs
| ID | JobNumber |
|----|-----------|
| 1 | J200 |
| 2 | J201 |
Job_Invoices
| ID | InvoiceNumber | JobID |
|----|---------------|-------|
| 10 | I300 | 1 |
| 11 | I301 | 2 |
Invoice_Accounts
| ID | InvoiceId | AccountID | Amount |
|----|-----------|-----------|--------|
| 23 | 10 | 40 | 200 |
| 24 | 10 | 40 | 300 |
| 25 | 10 | 41 | 100 |
| 26 | 11 | 40 | 100 |
Accounts
| ID | Name |
|----|------|
| 40 | Sales|
| 41 | EXP |
I am trying the following:
SELECT
J.JobNumber,
A.Name AS "Account",
SUM(JA.Amount) AS 'Total'
FROM
Job J
LEFT JOIN
Job_Invoices JI ON JI.JobID = J.JobID
INNER JOIN
Invoice_Accounts JA ON JA.InvoiceId = JI.ID
INNER JOIN
Accounts A ON A.ID = JA.AccountID
GROUP BY
J.JobNumber, A.Name, JA.Amount
ORDER BY
J.JobNumber
What I expect:
| JobNumber | Account | Total |
|-----------|-----------|-------|
| J200 | EXP | 100 |
| J200 | Sales | 500 |
| J201 | Sales | 100 |
What I get:
| JobNumber | Account | Total |
|-----------|-----------|-------|
| J200 | EXP | 100 |
| J200 | Sales | 200 |
| J200 | Sales | 300 |
| J201 | Sales | 100 |
You don't need the Job table in the query. The INNER JOINs are to the Job_Invoices table, so the outer join is turned into an inner join anyway.
So, you can simplify this to:
SELECT JI.JobNumber, A.Name AS Account, SUM(JA.Amount) AS Total
FROM Job_Invoices JI JOIN
Invoice_Accounts JA
ON JA.InvoiceId = JI.ID JOIN
Accounts A
ON A.ID = JA.AccountID
GROUP BY JI.JobNumber, A.Name
ORDER BY JI.JobNumber;
Also note that you don't need to escape the column aliases. The just makes the query harder to type.
The problem is you have the JA.Amount in your GROUP BY clause. Try taking it out:
SELECT J.JobNumber, A.Name AS "Account", SUM(JA.Amount) AS 'Total'
FROM Job J
LEFT JOIN Job_Invoices JI ON JI.JobID = J.JobID
INNER JOIN Invoice_Accounts JA ON JA.InvoiceId = JI.ID
INNER JOIN Accounts A ON A.ID = JA.AccountID
GROUP BY J.JobNumber, A.Name
ORDER BY J.JobNumber
You can write a query as:
select sum (IA.Amount) as Amount, J.JobNumber,A.Name
from #Invoice_Accounts IA --as it holds the base data
join #Job_Invoices JI on IA.InvoiceId = JI.ID
join #Jobs J on J.id = JI.JobID
join #Accounts A on A.ID = IA.AccountID
group by J.JobNumber,A.Name
Included the Jobs table as it has the JobNumber column. Sample code here..

SQL duplicate values of records with multiple joins

My query works fine until I add in the estimate tables, where my data duplicates.
Below is my table structure:
Jobs
| ID | JobNumber |
|----|-----------|
| 1 | J200 |
| 2 | J201 |
Job_Invoices
| ID | InvoiceNumber | JobID |
|----|---------------|-------|
| 10 | I300 | 1 |
| 11 | I301 | 2 |
Invoice_Accounts
| ID | InvoiceId | AccountID | Amount |
|----|-----------|-----------|--------|
| 23 | 10 | 40 | 200 |
| 24 | 10 | 40 | 300 |
| 25 | 10 | 41 | 100 |
| 26 | 11 | 40 | 100 |
Estimates
| ID | JobID |
|----|-------|
| 50 | 1 |
Estimate_Accounts
| ID | EstimateID| AccountID | Amount |
|----|-----------|-----------|--------|
| 23 | 50 | 40 | 100 |
| 24 | 50 | 40 | 100 |
Accounts
| ID | Name |
|----|------|
| 40 | Sales|
| 41 | EXP |
I am trying the below:
SELECT
J.JobNumber,
A.Name AS "Account",
SUM(JA.Amount) AS 'Total Invoiced',
SUM(EA.Amount) AS 'Total Estimated',
FROM
Job J
LEFT JOIN
Job_Invoices JI ON JI.JobID = J.ID
LEFT JOIN
Estimates E ON E.JobID = J.ID
LEFT JOIN
Estimate_Accounts EA ON EA.EstimateID = E.ID
INNER JOIN
Invoice_Accounts JA ON JA.InvoiceId = JI.ID
INNER JOIN
Accounts A ON A.ID = JA.AccountID
GROUP BY
J.JobNumber, A.Name, JA.Amount
ORDER BY
J.JobNumber
This is what I am hoping to achieve:
| JobNumber | Account | Total Invoiced | Total Estimated |
|-----------|-----------|----------------|-----------------|
| J200 | EXP | 100 | 0 |
| J200 | Sales | 500 | 200 |
| J201 | Sales | 100 | 0 |
This works fine if before I add the Estimates and Estimate_Accounts tables, my result looks like the above (without the Total Estimate) column.
However, when I try adding the Total Estimated column by joining the Estimates and Estimate_Accounts tables, Total Invoiced and Total Estimated values double, to something like this:
| JobNumber | Account | Total Invoiced | Total Estimated |
|-----------|-----------|----------------|-----------------|
| J200 | EXP | 200 | 0 |
| J200 | Sales | 1000 | 400 |
| J201 | Sales | 200 | 0 |
You want to join invoice totals with esitimated totals. Both are aggregations. So, make these aggregations, then join. With the jobs and accounts thus found, join the job and account tables.
select
j.jobnumber,
a.name as "Account",
inv.total as "Total Invoiced",
est.total as "Total Estimated",
from
(
select e.jobid, ea.accountid, sum(ea.amount) as total
from estimate_accounts ea
join estimates e on e.id = ea.estimateid
group by e.jobid, ea.accountid
) est
full outer join
(
select ji.jobid, ia.accountid, sum(ia.amount) as total
from invoice_accounts ia
join job_invoices ji on ji.id = ia.invoiceid
group by ji.jobid, ia.accountid
) inv using (jobid, accountid)
join jobs j on j.id = jobid
join accounts a on a.id = accountid
order by j.jobnumber, a.name;
If your DBMS doesn't support the USING clause, you must use ON instead:
select
[...]
) inv on inv.jobid = est.jobid and inv.accountid = est.accountid
join jobs j on j.id in (est.jobid, inv.jobid)
join accounts a on a.id in (est.accountid, inv.accountid)
order by j.jobnumber, a.name;
You need to aggregate before joining, because otherwise the JOIN generates a Cartesian product. However, this is complicated by the account information.
So, this approach aggregates the estimates and invoices separately by account and job. It then combines them using UNION ALL and joins in the rest of the information:
SELECT J.JobNumber, A.Name AS Account,
JE.Total_Invoiced, JE.Total_Estimated
FROM Job J LEFT JOIN
((SELECT JI.JobId, JA.AccountId, SUM(JA.Amount) AS Total_Invoiced, NULL as Total_Estimated
FROM Job_Invoices JI JOIN
Invoice_Accounts JA
ON JA.InvoiceId = JI.ID
GROUP BY JI.JobId, JA.AccountId
) UNION ALL
(SELECT E.JobId, EA.AccountId, NULL, SUM(EA.Amount) as Total_Estimated
FROM Estimates E JOIN
Estimate_Accounts EA
ON EA.EstimateID = E.ID
GROUP BY E.JobId, EA.AccountId
)
) JE
ON JE.JobId = J.ID LEFT JOIN
Accounts A
ON A.ID = JE.AccountID
ORDER BY J.JobNumber;
There are two tables where duplication may happen:
Invoice_Accounts has several records per AccountID/InvoiceId tuple, that you want to SUM()
Estimate_Accounts has several records per EstimateID/AccountID tuple. Also I think that you should use column AccountID when joining this table: this requires changing the order of the JOINs, so Estimate_Accounts is joined after Accounts
I think that it would be simpler to move the aggregation to subqueries, and then join them in the outer query.
Consider:
SELECT
J.JobNumber,
A.Name AS Account,
JA.Amount AS Total_Invoiced,
COALESCE(EA.Amount, 0) AS Total_Estimated
FROM
Job J
LEFT JOIN
Job_Invoices JI ON JI.JobID = J.ID
INNER JOIN
(
SELECT AccountID, InvoiceId, SUM(Amount) Amount
FROM Invoice_Accounts
GROUP BY InvoiceId, AccountID
) JA ON JA.InvoiceId = JI.ID
INNER JOIN
Accounts A ON A.ID = JA.AccountID
LEFT JOIN
Estimates E ON E.JobID = J.ID
LEFT JOIN
(
SELECT EstimateID, AccountID , SUM(Amount) Amount
FROM Estimate_Accounts
GROUP BY EstimateID, AccountID
) EA ON EA.EstimateID = E.ID AND EA.AccountID = JA.AccountID
ORDER BY
J.JobNumber, A.Name;
This demo on DB Fiddle with your sample data returns:
| JobNumber | Account | Total_Invoiced | Total_Estimated |
| --------- | ------- | -------------- | --------------- |
| J200 | EXP | 100 | 0 |
| J200 | Sales | 500 | 200 |
| J201 | Sales | 100 | 0 |

total sales of each product for each salesman who had sales on more than 1 product

I'm trying to write a query for these three tables but I've failed.
I tried to conclude with having and group by statements, but I have errors in join structures
I wrote a query like this.
SELECT a.salesman_name, p.Product_name, Sum(t.quantity) FROM SALES t
inner join SALESMAN a on t.Salesman_id =a.Salesman_id
inner join PRODUCT p on t.Product_id = p.Product_id
GROUP BY a.salesman_name, p.Product_name
HAVING Sum(t.quantity) > 1
but the query result should look like this:
+----------------+--------------+----------+
| SALESMAN_NAME | PRODUCT_NAME | QUANTITY |
+----------------+--------------+----------+
| Ahmet Celik | PRODUCT_A | 25 |
| Ahmet Celik | PRODUCT_D | 5 |
| Ahmet Celik | PRODUCT_E | 10 |
| Coskun Metin | PRODUCT_A | 15 |
| Coskun Metin | PRODUCT_B | 10 |
| Ferhat Kaya | PRODUCT_A | 5 |
| Ferhat Kaya | PRODUCT_C | 12 |
| Ferhat Kaya | PRODUCT_E | 8 |
| Selim Albayrak | PRODUCT_C | 5 |
| Selim Albayrak | PRODUCT_D | 2 |
+----------------+--------------+----------+
I prepared the database in sqlfiddle http://www.sqlfiddle.com/#!18/ba5ee/6
many thanks in advance for your help
There is already a quantity column in your fiddle. Based on that, the solution:
SELECT sm.salesman_name, p.product_name, min(quantity) as quantity
FROM Sales s
left outer JOIN Product p on p.product_id = s.product_id
left outer JOIN Salesman sm on sm.salesman_id = s.salesman_id
where quantity >= 1
Group By salesman_name, product_name
See: http://www.sqlfiddle.com/#!18/ba5ee/20
this code will help you. I tried. It success.
select distinct salesman.salesman_name, product.product_name, quantity
from sales
inner join salesman on salesman.salesman_id = sales.salesman_id
inner join product on product.product_id = sales.product_id
where salesman.salesman_name in (
select salesman.salesman_name
from sales
inner join salesman on salesman.salesman_id = sales.salesman_id
group by salesman.salesman_name
having count(salesman.salesman_name) > 1
)
and salesman.salesman_id not in(
select sales.salesman_id
from sales
group by sales.salesman_id, sales.product_id
having count(*) > 1
)
here the certain answer. no need to use inner join. ask if not understood
SELECT salesman.Salesman_name,
Product.Product_name,
sum(sales.Quantity)
FROM Salesman,Product,Sales where Salesman.Salesmanid=sales.Salesmanid
and Product.Productid=Sales.Productid and 1<(SELECT count(DISTINCT Productid)
from sales
where Salesman.Salesmanid=Sales.Salesmanid)
group by Salesman_name,Product_name

Inner join with multiple tables

I have these four tables:
PRODUCTS
---------
PRODUCT_ID
PRODUCT_TITLE
(other fields)
COLORS
---------
COLOR_ID
COLOR_NAME
MATERIALS
---------
MATERIAL_ID
MATERIAL_NAME
IMAGES
---------
IMAGE_ID
BIG
MED
SMALL
THUMB
SIZE
---------
SIZE_ID
SIZE_NAME
And also:
PRODUCT_COLOR
---------
PRODUCT_ID
COLOR_ID
PRODUCT_MATERIAL
---------
PRODUCT_ID
MATERIAL_ID
PRODUCT_SIZE
---------
PRODUCT_ID
SIZE_ID
PRODUCT_IMAGE
---------
PRODUCT_ID
IMAGE_ID
COLOR_ID (can be null)
MATERIAL_ID (can be null)
All the products can have a different color and/or material. E.g. I can have a product that has one or more material options but no colors associated and vice versa. The output should be something like this:
-----------------------------------------------------------------------------
| PRODUCT_ID | PRODUCT_NAME | COLOR_ID | MATERIAL_ID | IMAGE_ID | SIZE_ID |
-----------------------------------------------------------------------------
| 1 | T-SHIRT | 1 | null | 1 | 1 |
| 1 | T-SHIRT | 1 | null | 1 | 2 |
| 1 | T-SHIRT | 1 | null | 1 | 3 |
| 1 | T-SHIRT | 1 | null | 1 | 4 |
| 2 | JEANS | null | 1 | 2 | 1 |
| 2 | JEANS | null | 1 | 2 | 2 |
| 2 | JEANS | null | 1 | 2 | 3 |
| 2 | JEANS | null | 1 | 2 | 4 |
| 2 | JEANS | null | 1 | 2 | 5 |
| 3 | T-SHIRT VNECK | 2 | 2 | 3 | 1 |
| 3 | T-SHIRT VNECK | 2 | 2 | 3 | 2 |
| 3 | T-SHIRT VNECK | 3 | 2 | 4 | 1 |
| 3 | T-SHIRT VNECK | 3 | 2 | 4 | 2 |
| 3 | T-SHIRT VNECK | 4 | 3 | 5 | 1 |
| 3 | T-SHIRT VNECK | 4 | 3 | 5 | 2 |
-----------------------------------------------------------------------------
I have tried the following statement but it returns 0 rows:
SELECT PRODUCTS.PRODUCT_ID, PRODUCTS.PRODUCT_TITLE, COLORS.COLOR_ID, MATERIALS.MATERIAL_ID, IMAGES.IMAGE_ID, SIZE.SIZE_ID from PRODUCTS
INNER JOIN PRODUCT_COLOR ON (PRODUCTS.PRODUCT_ID = PRODUCT_COLOR.PRODUCT_ID)
INNER JOIN COLORS ON (COLORS.COLOR_ID = PRODUCT_COLOR.COLOR_ID)
INNER JOIN PRODUCT_MATERIAL ON (PRODUCTS.PRODUCT_ID = PRODUCT_MATERIAL.PRODUCT_ID)
INNER JOIN MATERIALS ON (MATERIALS.MATERIAL_ID = PRODUCT_MATERIAL.MATERIAL_ID)
INNER JOIN PRODUCT_IMAGE ON (PRODUCTS.PRODUCT_ID = PRODUCT_IMAGE.PRODUCT_ID)
INNER JOIN IMAGES ON (IMAGES.IMAGE_ID = PRODUCT_IMAGE.IMAGE_ID)
INNER JOIN PRODUCT_SIZE ON (PRODUCTS.PRODUCT_ID = PRODUCT_SIZE.PRODUCT_ID)
INNER JOIN SIZE ON (SIZE.SIZE_ID = PRODUCT_SIZE.SIZE_ID)
ORDER BY PRODUCTS.id_PRODUCT;
Any ideas?
You could do something like this:
select p.product_id,
p.product_name,
c.color_id,
m.material_id,
i.image_id,
s.size_id
from products p
left join product_color pc
on p.product_id = pc.product_id
left join colors c
on pc.color_id = c.colorid
left join product_material pm
on p.product_id = pm.product_id
left join materials m
on pm.material_id = m.material_id
left join product_image pi
on p.product_id = pi.product_id
left join images i
on pi.image_id = i.image_id
or c.color_id = i.color_id
or m.material_id = i.material_id
left join product_size ps
on p.product_id = ps.product_id
left join size s
on ps.size_id = s.size_id
I would advise you reviewing JOINs. There is a great visual explanation of joins online that will help you write these queries.
Well, you need to learn how to build joins, and the way I normally do it is by selecting one table and join the next one and the next one and the next one until I have the result I want.
select product_id, product_name
from products
next I join the first one I need so I go ahead and say
select p.product_id, p.product_name, pc.color_id
from products p
join product_color pc on (pc.product_id = p.product_id)
On the join it is important to figure out if I maybe have nothing to join with and I still want to see the line. So I rather use a left join
select p.product_id, p.product_name, pc.color_id
from products p
left join product_color pc on (pc.product_id = p.product_id)
That way you add each table to join. By the way. Is this homework?
If you just need IDs, keep it simple
select p.product_id,
p.product_name,
pc.color_id,
pm.material_id,
pi.image_id,
ps.size_id
from products p,
PRODUCT_COLOR pc,
product_material pm,
PRODUCT_SIZE ps,
PRODUCT_IMAGE pi
where
p.product_id = pc.product_id(+)
and p.product_id = pm.product_id(+)
and p.product_id = ps.product_id(+)
and p.product_id = pi.product_id(+);