将6个表连接成单个查询?

时间:2013-01-25 16:53:27

标签: sql oracle join oracle11g

嘿,任何人都可以帮助我将下面的5个表加入到单个查询中吗?我目前有下面的查询,但似乎没有工作,好像在hires表中有两个具有相同ID的产品,所有产品都从产品表中返回,这显然是错误的。

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

表格数据:

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 |
|------------------------------|

此时查询的输出如下所示:

-------------------------------------------------------------
| 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         |
|------------------------------------------|----------------|

什么时候应该看起来像这样?因为在查询中的日期之间雇佣了Prod_ID'1'

-------------------------------------------------------------
| 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         |
|------------------------------------------|----------------|

如果有人可以帮助修改查询输出,我将非常感激。因为我的理解是它应该按照书面形式工作?

4 个答案:

答案 0 :(得分:4)

您的问题是Prod_Id 1进出这些日期范围。因此,使用子查询来过滤掉那些范围内的Prod_Id,并排除这些。

这是您查询的简化版本:

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

SQL Fiddle

假设我已正确复制并粘贴,这应该是您的查询:

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

希望这有帮助。

答案 1 :(得分:0)

当没有匹配时,左外连接将返回空值,这意味着当此连接查询的结果为空时,您仍然有一行(没有HIRE表数据):

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

尝试从hires表中添加一个select(例如hire.Hire_Start)来查看这种情况,然后将其切换到内部联接,我认为您的问题将得到解决。

或者使用hire.Hire_Start is not null

之类的内容在完整查询中添加WHERE子句

修改

如果您将原始查询更改为:

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

Hire_Start专栏中的内容是什么?

然后,如果将其添加到where子句,您会得到预期的结果:

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

最后,完全放弃外部加入,这是否按预期工作?

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

并注意:OR Hires.prod_ID是否表示如果结果没有返回任何可用的雇用信息,则在这种情况下,您需要更像所提供的其他答案来编写查询。

答案 2 :(得分:0)

以下是一些可以帮助您的代码:

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);

答案 3 :(得分:-3)

SELECT Emp.Empid,Emp.EmpFirstName,Emp.EmpLastName,Dept.DepartmentName  来自员工Emp   内部联合部门      ON Emp.Departmentid = Dept.Departmenttid