仅限 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 |
+--------+--------+----------+
条件如下:
- 如果 Person 具有 Role“AAA”或“BBB”而不是“Auth”,则 MYAccess 列应将该人的值显示为“添加”。所有其他值都应为空。
- 如果 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
我正在尝试使用 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 |
+--------+--------+----------+
条件如下:
- 如果 Person 具有 Role“AAA”或“BBB”而不是“Auth”,则 MYAccess 列应将该人的值显示为“添加”。所有其他值都应为空。
- 如果 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