ORACLE - 如何获取所有匹配的&来自多个相同结构化表的不匹配数据

时间:2017-12-01 14:46:35

标签: oracle plsql oracle11g

我有三个表 CIS_GROUP,CUSTOMER,CUSTOMER_TEMP 和数据。
我的查询目标如下:

1) CUSTOMER 表中存在相同客户时,从 CUSTOMER_TEMP 获取数据。
2)当客户仅存在于 CUSTOMER_TEMP 表中时,从 CUSTOMER_TEMP 获取数据。
2)当客户仅存在于 CUSTOMER 表中时,从 CUSTOMER 获取数据。

表格脚本&插入脚本如下

CREATE TABLE ABABILFE.CIS_GROUP 
 (ID         NUMBER
  ,GROUP_NAME VARCHAR2(100)
 )
 /
CREATE TABLE ABABILFE.CUSTOMER 
 (ID         NUMBER
  ,GROUP_ID   NUMBER
  ,CUST_NAME  VARCHAR2(100)
  ,ADDRESS    VARCHAR2(200)
  ,PHONE      VARCHAR2(20)
  ,EMAIL      VARCHAR2(50)
 )
 /
CREATE TABLE ABABILFE.CUSTOMER_TEMP 
 (ID         NUMBER
  ,GROUP_ID   NUMBER
  ,CUST_NAME  VARCHAR2(100)
  ,ADDRESS    VARCHAR2(200)
  ,PHONE      VARCHAR2(20)
  ,EMAIL      VARCHAR2(50)
 )

插入脚本

SET DEFINE OFF;
Insert into CIS_GROUP
 (ID,GROUP_NAME)
Values
 (1,'Albert');
Insert into CIS_GROUP
 (ID,GROUP_NAME)
Values
 (2,'Eric');
COMMIT;  
-------------------------------------------
SET DEFINE OFF;
Insert into CUSTOMER
 (ID,CUST_NAME,ADDRESS,PHONE,EMAIL)
Values
 (1,'Aston','NewYork','0011','aston@gmail.com');
Insert into CUSTOMER
 (ID,GROUP_ID,CUST_NAME,ADDRESS,PHONE,EMAIL)
Values
 (2,1,'Albert','Canada','0022',NULL);
Insert into CUSTOMER
 (ID,GROUP_ID, CUST_NAME,ADDRESS,PHONE,EMAIL)
Values
 (3,1,'Bob','Canada',NULL,'bob123@gmail.com');
Insert into CUSTOMER
 (ID,GROUP_ID,CUST_NAME,ADDRESS,PHONE,EMAIL)
Values
 (4,1,'Charles','Canada',NULL,'charles@gmail.com');
COMMIT;
-------------------------------------------  
SET DEFINE OFF;
Insert into CUSTOMER_TEMP
 (ID,GROUP_ID, CUST_NAME,ADDRESS,PHONE,EMAIL)
Values
 (3, 1,'Bob','Canada','0023','bob@yahoo.com');
Insert into CUSTOMER_TEMP
 (ID,GROUP_ID, CUST_NAME,ADDRESS,PHONE,EMAIL)
Values
 (5,2,'Don','London','123','don@hotmail.com');
Insert into CUSTOMER_TEMP
 (ID,GROUP_ID,CUST_NAME,ADDRESS,PHONE,EMAIL)
Values
 (6,2,'Eric','London',null,'eric@gmail.com');
COMMIT;

表格数据

CIS_GROUP Table Data

| ID |GROUP_NAME |
| -- | --------- |
| 1  | Albert    |
| 2  | Eric      |

                     CUSTOMER Table Data

| ID | GROUP_ID |   NAME   | ADDRESS   | PHONE |       EMAIL      |
| ---| ---------| ---------| --------- | ----- | ---------------- |
|  1 |          | Aston    | New York  | 0011  |aston@gmail.com   |
|  2 |    1     | Albert   | Canada    | 0022  |                  |
|  3 |    1     | Bob      | Canada    |       |bob123@gmail.com  |
|  4 |    1     | Charles  | Canada    |       |charles@gmail.com |


                    CUSTOMER_TEMP Table Data

| ID | GROUP_ID |   NAME   | ADDRESS   | PHONE |       EMAIL      |
| ---| ---------| ---------| --------- | ----- | ---------------- |
|  3 |    1     | Bob      | Canada    | 0023  |  bob@yahoo.com   |
|  5 |    2     | Don      | London    | 123   |  don@hotmail.com |
|  6 |    2     | Eric     | London    |       |  eric@gmail.com  |  

我为我想要的结果写了以下查询

SELECT * FROM

(
 SELECT CUSTOMER_TEMP.id
       ,GROUP_ID
       ,cust_name
       ,address
       ,phone
       ,email
 FROM CIS_GROUP,CUSTOMER_TEMP 
WHERE CIS_GROUP.ID = CUSTOMER_TEMP.GROUP_ID
  AND CIS_GROUP.ID = :PID
)TABLE1
UNION ALL
SELECT * FROM
(
 SELECT CUSTOMER.id
        ,GROUP_ID
        ,cust_name
        ,address
        ,phone
        ,email
   FROM CIS_GROUP,CUSTOMER
  WHERE CIS_GROUP.ID = CUSTOMER.GROUP_ID
    AND CIS_GROUP.ID = :PID
    AND CUSTOMER.ID NOT IN (SELECT CUSTOMER_TEMP.id
                        FROM ABABILFE.CUSTOMER_TEMP)

  )TABLE2 
  ORDER BY 1  

查询结果/所需结果

          My Desire Result (When parameter(:PID) value is 1)

| ID | GROUP_ID |   NAME   | ADDRESS   | PHONE |       EMAIL      |
| ---| ---------| ---------| --------- | ----- | ---------------- |
|  2 |    1     | Albert   | Canada    | 0022  |                  |
|  3 |    1     | Bob      | Canada    | 0023  |  bob@yahoo.com   |
|  4 |    1     | Charles  | Canada    |       | charles@gmail.com|


           My Desire Result (When parameter(:PID) value is 2)

| ID | GROUP_ID |   NAME   | ADDRESS   | PHONE |       EMAIL      |
| ---| ---------| ---------| --------- | ----- | ---------------- |
|  5 |    2     |    Don   | London    |  123  | don@hotmail.com  |
|  6 |    2     |    Eric  | London    |       |  eric@gmail.com  |  

如何更有效地编写此查询/优化方式?

2 个答案:

答案 0 :(得分:0)

您也可以使用CTE

执行此操作
with t as (select id, cust_name, address, phone, email 
             from customer_temp 
             where group_id = 1)
select * from t
union all
select id, cust_name, address, phone, email from customer 
  where group_id = 1 
    and not exists (select 1 from t where id = customer.id)

或对行进行排名,给出第二个表优先级:

select id, cust_name, address, phone, email
  from (
    select rank() over (partition by id order by src) rnk, c.*
      from (
         select 1 src, id, cust_name, address, phone, email 
           from customer_temp where group_id = 1
         union all 
         select 2 src, id, cust_name, address, phone, email 
           from customer where group_id = 1) c )
  where rnk = 1 order by id

两个查询都产生了期望的结果。您提供的insert中存在轻微错误。

答案 1 :(得分:0)

可以删除表CIS_GROUP,因为:

  • 此表未被选中
  • 此表不必按group_id过滤,表custumer和custumer_temp alredy有一个可用于此目的的字段。

而不是"联合所有"用"不在"在第二个查询中,您可以使用完全外部联接,通过客户ID与NVL函数联接以从右表中获取数据。 NVL的第一个参数定义哪个表是主数据源。

最终查询如下所示:

SELECT NVL(CT.id, C.ID) AS ID
      ,NVL(CT.GROUP_ID, C.GROUP_ID) AS GROUP_ID
      ,NVL(CT.cust_name, C.CUST_NAME) AS CUST_NAME
      ,NVL(CT.address, C.ADDRESS) AS ADDRESS
      ,NVL(CT.phone, C.PHONE) AS PHONE
      ,NVL(CT.email, C.EMAIL) AS EMAIL
FROM CUSTOMER C 
FULL OUTER JOIN CUSTOMER_TEMP CT ON C.ID = CT.ID
WHERE (CT.GROUP_ID = :PID OR C.GROUP_ID = :PID)

此版本有更好的执行计划。你可以在这里试试:SQL Fiddle

*编辑:以前的版本不符合问题的要求。