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

时间:2021-05-13 18:14:13

标签: sql oracle case-statement

我正在尝试使用 case 语句根据某些条件创建计算列。我非常接近目标,但无法看到查询出错的地方。希望我能在这里得到一些最好/更简单的方法和一些帮助。

以下是表格:
PERSON 表:

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

角色表:

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

最后一个是明细表
PERSON_ROLE 表:

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

期望/预期输出:

+--------+--------+----------+
| 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. 如果人员具有角色“AAA”或“BBB”而不是“Auth”,则MYAccess列应将值显示为“添加”对于那个人。所有其他值都应为 null。
  2. 如果人员具有角色“身份验证”,则MYAccess列应仅针对该行显示“删除”。即使同一个人有“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      |
+--------+--------+----------+

对于人马丁和斯科特,它应该只显示“删除”,但我也得到了“添加”。

下面是查询:

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

谢谢
理查

1 个答案:

答案 0 :(得分:1)

这就是你要找的吗?
在你的条件下,你说: “如果 Person 具有角色“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 子句),你可以用 1 替换最后 2 条语句:

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
相关问题