仅限 Oracle SQL:Case 语句或存在查询以根据条件显示结果

Oracle SQL only: Case statement or exists query to show results based on condition

我正在尝试使用 case 语句根据某些条件创建计算列。我离目标很近,但看不到查询哪里出错了。希望我能在这里得到一些 best/easier 方法和一些帮助。

下面是 tables:
人 Table:

+----+--------+
| ID | PERSON |
+----+--------+
|  1 | John   |
|  2 | Scott  |
|  3 | Ruth   |
|  4 | Smith  |
|  5 | Frank  |
|  6 | Martin |
|  7 | Blake  |
+----+--------+

角色 Table:

+----+------+
| ID | ROLE |
+----+------+
|  1 | JJJ  |
|  2 | Auth |
|  3 | AAA  |
|  4 | MMM  |
|  5 | KKK  |
|  6 | BBB  |
+----+------+

最后一个是细节table
PERSON_ROLE Table:

+----+-----------+---------+
| ID | PERSON_ID | ROLE_ID |
+----+-----------+---------+
|  1 |         1 |       1 |
|  2 |         2 |       2 |
|  3 |         2 |       3 |
|  4 |         2 |       4 |
|  5 |         3 |       1 |
|  6 |         3 |       5 |
|  7 |         4 |       3 |
|  8 |         5 |       6 |
|  9 |         6 |       3 |
| 10 |         6 |       6 |
| 11 |         6 |       2 |
| 12 |         7 |       5 |
| 13 |         7 |       6 |
+----+-----------+---------+

Desired/Expected 输出:

+--------+--------+----------+
| PERSON | MYROLE | MYACCESS |
+--------+--------+----------+
| John   | JJJ    |          |
| Scott  | Auth   | Remove   |
| Scott  | AAA    |          |
| Scott  | MMM    |          |
| Ruth   | JJJ    |          |
| Ruth   | KKK    |          |
| Smith  | AAA    | Add      |
| Frank  | BBB    | Add      |
| Martin | AAA    |          |
| Martin | BBB    |          |
| Martin | Auth   | Remove   |
| Blake  | KKK    |          |
| Blake  | BBB    | Add      |
+--------+--------+----------+

条件如下:

  1. 如果 Person 具有 Role“AAA”或“BBB”而不是“Auth”,则 MYAccess 列应将该人的值显示为“添加”。所有其他值都应为空。
  2. 如果 Person 具有 Role“Auth”,则 MYAccess 列应显示“Remove”仅针对该行。即使同一个人有“AAA”或“BBB”或任何其他值,它也应该显示为空。

下面是我得到的实际输出,部分正确:

+--------+--------+----------+
| PERSON | MYROLE | MYACCESS |
+--------+--------+----------+
| Blake  | KKK    |          |
| Blake  | BBB    | Add      |
| Frank  | BBB    | Add      |
| John   | JJJ    |          |
| Martin | AUTH   | Remove   |
| Martin | BBB    | Add      |
| Martin | AAA    | Add      |
| Ruth   | JJJ    |          |
| Ruth   | KKK    |          |
| Scott  | AAA    | Add      |
| Scott  | AUTH   | Remove   |
| Scott  | MMM    |          |
| Smith  | AAA    | Add      |
+--------+--------+----------+

对于 Persons Martin 和 Scott,它应该只显示“删除”,但我也看到“添加”。

下面是查询:

SELECT p.person,upper(r.role) myrole,
case when p.person in (select p.person from  person ut where ut.person = p.person and upper(r.role) = upper('Auth')) then 'Remove' 
     when p.person in (select p.person from  person ut where ut.person = p.person and (upper(r.role) = upper('Auth') or (upper(r.role) = upper('AAA') or upper(r.role) = upper('BBB')))) then 'Add' else null
end as myaccess
FROM person p
       join person_role pr
         ON p.id = pr.person_id
       join myrole r
         ON r.id = pr.role_id
order by p.person

DDL 脚本:

CREATE TABLE person (
    id      INTEGER NOT NULL,
    person  VARCHAR2(50 CHAR)
);

INSERT INTO person (
    id,
    person
) VALUES (
    1,
    'John'
);

INSERT INTO person (
    id,
    person
) VALUES (
    2,
    'Scott'
);

INSERT INTO person (
    id,
    person
) VALUES (
    3,
    'Ruth'
);

INSERT INTO person (
    id,
    person
) VALUES (
    4,
    'Smith'
);

INSERT INTO person (
    id,
    person
) VALUES (
    5,
    'Frank'
);

INSERT INTO person (
    id,
    person
) VALUES (
    6,
    'Martin'
);

INSERT INTO person (
    id,
    person
) VALUES (
    7,
    'Blake'
);

ALTER TABLE person ADD CONSTRAINT person_pk PRIMARY KEY ( id );


CREATE TABLE myrole (
    id    INTEGER NOT NULL,
    role  VARCHAR2(50 CHAR)
);

INSERT INTO myrole (
    id,
    role
) VALUES (
    1,
    'JJJ'
);

INSERT INTO myrole (
    id,
    role
) VALUES (
    2,
    'Auth'
);

INSERT INTO myrole (
    id,
    role
) VALUES (
    3,
    'AAA'
);

INSERT INTO myrole (
    id,
    role
) VALUES (
    4,
    'MMM'
);

INSERT INTO myrole (
    id,
    role
) VALUES (
    5,
    'KKK'
);

INSERT INTO myrole (
    id,
    role
) VALUES (
    6,
    'BBB'
);

ALTER TABLE myrole ADD CONSTRAINT myrole_pk PRIMARY KEY ( id );


CREATE TABLE person_role (
    id         INTEGER NOT NULL,
    person_id  INTEGER,
    myrole_id  INTEGER
);

ALTER TABLE person_role ADD CONSTRAINT person_role_pk PRIMARY KEY ( id );

CREATE SEQUENCE myrole_seq START WITH 1 NOCACHE;

CREATE OR REPLACE TRIGGER myrole_tr BEFORE
    INSERT ON myrole
    FOR EACH ROW
    WHEN ( new.id IS NULL )
BEGIN
    :new.id := myrole_seq.nextval;
END;
/

CREATE SEQUENCE person_seq START WITH 1 NOCACHE;

CREATE OR REPLACE TRIGGER person_tr BEFORE
    INSERT ON person
    FOR EACH ROW
    WHEN ( new.id IS NULL )
BEGIN
    :new.id := person_seq.nextval;
END;
/

CREATE SEQUENCE person_role_seq START WITH 1 NOCACHE;

CREATE OR REPLACE TRIGGER person_role_tr BEFORE
    INSERT ON person_role
    FOR EACH ROW
    WHEN ( new.id IS NULL )
BEGIN
    :new.id := person_role_seq.nextval;
END;
/

谢谢
里查

这是您要找的吗?
在你的条件下你说: “如果人员具有角色“AAA”或“BBB”而不是“Auth”,则 MYAccess 列应将该人员的值显示为“添加”。所有其他值应为空。 “ Scott 拥有 Auth,因此此条件会产生错误。根据这条规则,斯科特不应该有“添加”。在您的预期输出中,它具有“添加”。我错过了什么吗?

WITH person_roles (id, person_id, role_id) AS
(
SELECT  1, 1,1 FROM DUAL UNION ALL
SELECT  2, 2,2 FROM DUAL UNION ALL
SELECT  3, 2,3 FROM DUAL UNION ALL
SELECT  4, 2,4 FROM DUAL UNION ALL
SELECT  5, 3,1 FROM DUAL UNION ALL
SELECT  6, 3,5 FROM DUAL UNION ALL
SELECT  7, 4,3 FROM DUAL UNION ALL
SELECT  8, 5,6 FROM DUAL UNION ALL
SELECT  9, 6,3 FROM DUAL UNION ALL
SELECT 10, 6,6 FROM DUAL UNION ALL
SELECT 11, 6,2 FROM DUAL UNION ALL
SELECT 12, 7,5 FROM DUAL UNION ALL
SELECT 13, 7,6 FROM DUAL
),persons (id, person) AS
(
SELECT   1,'John' FROM DUAL UNION ALL   
SELECT   2,'Scott' FROM DUAL UNION ALL  
SELECT   3,'Ruth' FROM DUAL UNION ALL   
SELECT   4,'Smith' FROM DUAL UNION ALL  
SELECT   5,'Frank' FROM DUAL UNION ALL  
SELECT   6,'Martin' FROM DUAL UNION ALL 
SELECT   7,'Blake' FROM DUAL
),roles (id, role) AS
(
SELECT 1,'JJJ' FROM DUAL UNION ALL   
SELECT 2,'Auth' FROM DUAL UNION ALL  
SELECT 3,'AAA' FROM DUAL UNION ALL   
SELECT 4,'MMM' FROM DUAL UNION ALL   
SELECT 5,'KKK' FROM DUAL UNION ALL   
SELECT 6,'BBB' FROM DUAL 
), rule_1(person_id, role_type)  AS
(
SELECT p.id, MIN(CASE WHEN r.ROLE = 'Auth' THEN 0 WHEN r.ROLE in ('AAA','BBB') THEN 1 ELSE 2 END) 
  FROM person_roles pr 
  JOIN persons p ON p.id = pr.person_id 
  JOIN roles r ON r.id = pr.role_id
  GROUP BY p.id
)
SELECT p.person, r.role, 
  CASE 
    WHEN rl.role_type = 1 AND r.role IN ('AAA','BBB') THEN 'Add'  
    WHEN rl.role_type = 0 AND r.role = 'Auth' THEN 'Remove' 
  END as action
  FROM person_roles pr 
  JOIN persons p ON p.id = pr.person_id 
  JOIN roles r ON r.id = pr.role_id
  JOIN rule_1 rl ON rl.person_id = pr.person_id
ORDER BY p.person

PERSON ROLE ACTION
------ ---- ------
Blake  BBB  Add   
Blake  KKK        
Frank  BBB  Add   
John   JJJ        
Martin AAA        
Martin Auth Remove
Martin BBB        
Ruth   KKK        
Ruth   JJJ        
Scott  MMM        
Scott  AAA        
Scott  Auth Remove
Smith  AAA  Add   

如果您想避免 CTE(with 子句),您可以将最后 2 个语句替换为 1:

SELECT p.person, r.role, 
  CASE 
    WHEN rl.role_type = 1 AND r.role IN ('AAA','BBB') THEN 'Add'  
    WHEN rl.role_type = 0 AND r.role = 'Auth' THEN 'Remove' 
  END as action
  FROM person_roles pr 
  JOIN persons p ON p.id = pr.person_id 
  JOIN roles r ON r.id = pr.role_id
  JOIN (
    SELECT p.id, MIN(CASE WHEN r.ROLE = 'Auth' THEN 0 WHEN r.ROLE in ('AAA','BBB') THEN 1 ELSE 2 END) as role_type
    FROM person_roles pr 
    JOIN persons p ON p.id = pr.person_id 
    JOIN roles r ON r.id = pr.role_id
    GROUP BY p.id
    ) rl ON rl.id = pr.person_id
ORDER BY p.person