从一对多查询中排除结果

时间:2016-04-04 20:52:46

标签: sql sql-server inner-join outer-join

我很难从一对多表关系中提取数据。 我需要提取尚未应用“Echo”保修代码的设备合同清单。 在我的场景中,我有一份设备合同表和一份保修表。

设备合同表(以下简称EQC)的设计是:


------------------------------------------------------------------------------------
| EquipmentID  | Contract  | SerialNumber | Make | Model | Date         | Customer |
------------------------------------------------------------------------------------
| 001          | A1        | GDS12        | GRND | GR219 | 2016-03-02   | Acme Corp|
| 002          | B1        | BQWSD        | BQW  | BLU22 | 2016-03-10   | Fast Lawn|
| 003          | C1        | Foo36        | Foo  | Red18 | 2016-03-04   | Perfect T|
| 004          | D1        | Foo37        | Foo  | Red18 | 2016-03-04   | Perfect T|
| 005          | E1        | Foo38        | Foo  | Red18 | 2016-03-01   | Perfect T|
------------------------------------------------------------------------------------

保修表(以下称WAR)的设计是:


---------------------------------------------------
| SerialNum | Make  | WarrantyCode | Warranty Date|
---------------------------------------------------
| GDS12     | GRND  | Alpha        | 2016-04-01   |
| GDS12     | GRND  | Bravo        | 2016-04-01   |
| GDS12     | GRND  | Delta        | 2016-04-01   |
| GDS12     | GRND  | Charlie      | 2016-04-01   |
| GDS12     | GRND  | Echo         | 2016-04-01   |
| BQWSD     | BQW   | Alpha        | 2016-04-01   |
| BQWSD     | BQW   | Bravo        | 2016-04-01   |
| BQWSD     | BQW   | Charlie      | 2016-04-01   |
| BQWSD     | BQW   | Foxtrot      | 2016-04-01   |
| BQWSD     | BQW   | Echo         | 2016-04-01   |
| Foo36     | Foo   | Alpha        | 2016-04-01   |
| Foo36     | Foo   | Bravo        | 2016-04-01   |
| Foo36     | Foo   | Charlie      | 2016-04-01   |
| Foo36     | Foo   | Hotel        | 2016-04-01   |
---------------------------------------------------

我需要做的是提取尚未应用“Echo”保修代码的EQC列表。这意味着它们没有Echo记录,或者它们没有保修记录期。

我的结果集应如下所示:


------------------------------------------------------------------------------------
| EquipmentID  | Contract  | SerialNumber | Make | Model | Date         | Customer |
------------------------------------------------------------------------------------
| 003          | C1        | Foo36        | Foo  | Red18 | 2016-03-04   | Perfect T|
| 004          | D1        | Foo37        | Foo  | Red18 | 2016-03-04   | Perfect T|
| 005          | E1        | Foo38        | Foo  | Red18 | 2016-03-01   | Perfect T|
------------------------------------------------------------------------------------

(GDS12& BQWSD因为已应用Echo WarrantyCode而被删除。)

我的查询是:

SELECT EQC.EquipmentID
  ,EQC.Contract
  ,EQC.SerialNumber
  ,EQC.Make
  ,EQC.Model
  ,EQC.DATE
  ,EQC.Customer
FROM equipment - contracts EQC
LEFT JOIN warranty WAR
  ON WAR.SerialNum = EQC.SerialNumber
    AND WAR.Make = EQC.Make
WHERE WAR.WarrantyCode is null 
  OR WAR.WarrantyCode <> 'Echo'

结果集看起来像这样:


------------------------------------------------------------------------------------
| EquipmentID  | Contract  | SerialNumber | Make | Model | Date         | Customer |
------------------------------------------------------------------------------------
| 001          | A1        | GDS12        | GRND | GR219 | 2016-03-02   | Acme Corp|
| 001          | A1        | GDS12        | GRND | GR219 | 2016-03-02   | Acme Corp|
| 001          | A1        | GDS12        | GRND | GR219 | 2016-03-02   | Acme Corp|
| 001          | A1        | GDS12        | GRND | GR219 | 2016-03-02   | Acme Corp|
| 002          | B1        | BQWSD        | BQW  | BLU22 | 2016-03-10   | Fast Lawn|
| 002          | B1        | BQWSD        | BQW  | BLU22 | 2016-03-10   | Fast Lawn|
| 002          | B1        | BQWSD        | BQW  | BLU22 | 2016-03-10   | Fast Lawn|
| 002          | B1        | BQWSD        | BQW  | BLU22 | 2016-03-10   | Fast Lawn|
| 003          | C1        | Foo36        | Foo  | Red18 | 2016-03-04   | Perfect T|
| 003          | C1        | Foo36        | Foo  | Red18 | 2016-03-04   | Perfect T|
| 003          | C1        | Foo36        | Foo  | Red18 | 2016-03-04   | Perfect T|
| 003          | C1        | Foo36        | Foo  | Red18 | 2016-03-04   | Perfect T|
| 004          | D1        | Foo37        | Foo  | Red18 | 2016-03-04   | Perfect T|
| 005          | E1        | Foo38        | Foo  | Red18 | 2016-03-01   | Perfect T|
------------------------------------------------------------------------------------

1 个答案:

答案 0 :(得分:3)

您希望不存在的EQC 是Echo WAR。或者换言之:您希望EQC 不在 Echo WAR集中。

select *
from equipment eqc
where not exists
(
  select *
  from warranty war
  where war.serialnum = eqc.serialnumber
  and war.make = eqc.make
  and war.warrantycode = 'Echo'
);

或者:

select *
from equipment
where (serialnumber, make) not in
(
  select serialnum, make
  from warranty
  where warrantycode = 'Echo'
);

更新:但是,我不确定SQL Server是否支持IN子句中的元组,如上所示。它是一个很棒的功能,可以让查询真正具有可读性,但不幸的是,有些DBMS不支持这种语法。