簡體   English   中英

Oracle - 查找丟失/未連接的記錄

[英]Oracle - Finding missing /non-joined records

我在 Oracle 12 中有一個問題,用傳統的學生、班級和參加課程的學生的傳統數據庫設計場景(稱為注冊)最容易解釋。 我很了解這個模型。 我有一個場景,我需要獲得一個完整的列表,所有學生針對所有課程,以及他們是否正在上課...

讓我們在這里使用這個桌子設計......

CREATE TABLE CLASSES 
(CLASSID  VARCHAR2(10) PRIMARY KEY,
CLASSNAME  VARCHAR2(25),
INSTRUCTOR VARCHAR2(25) );


CREATE TABLE STUDENTS
(STUDENTID  VARCHAR2(10) PRIMARY KEY,
STUDENTNAMENAME  VARCHAR2(25)
STUDY_MAJOR VARCHAR2(25) );

CREATE TABLE REGISTRATION
(
 CLASSID VARCHAR2(10 BYTE), 
 STUDENTID VARCHAR2(10 BYTE), 
 GRADE NUMBER(4,0), 
 CONSTRAINT "PK1" PRIMARY KEY ("CLASSID", "STUDENTID"),
 CONSTRAINT "FK1" FOREIGN KEY ("CLASSID") REFERENCES "CLASSES" ("CLASSID") ENABLE, 
 CONSTRAINT "FK2" FOREIGN KEY ("STUDENTID") REFERENCES "EGR_MM"."STUDENTS" ("STUDENTID") ENABLE
 ) ;

所以假設以下... 300 名學生和 15 個不同的班級...並且注冊表將顯示有多少學生參加了多少課程...我需要的是該信息加上所有未采取的組合...即我需要一個顯示所有可能組合的報告(SQL 語句)...即 300 x 15,然后該行是否存在於注冊表中...因此,例如,輸出應如下所示...

STUDENTID   Class1_GRADE  Class2_Grade      Class3_Grade`       Class4_Grade
101         A               B                   Not Taking          A
102         C               Not Taking          Not Taking          Not Taking
****** THIS STUDENT NOT TAKING ANY CLASSES So NOT in the Registrations Table
103         Not Taking      Not Taking          Not Taking          Not Taking  

這也可以工作,我可能可以做一個 PIVOT 來獲得上面的列表。

STUDENTID   CLASSID  GRADE
101         Class1    A
101         Class2    B
101         Class3    Not Taking
101         Class4    A
...
102         Class1    C
102         Class2    Not Taking
102         Class3    Not Taking
102         Class4    Not Taking
...
103         Class1    Not Taking  // THIS STUDENT NOT TAKING ANY CLASSES
103         Class2    Not Taking
103         Class3    Not Taking
103         Class4    Not Taking

我如何填寫缺失的數據,即未參加的學生和班級的組合...?

CROSS JOIN學生和班級,然后LEFT OUTER JOIN的注冊,然后使用COALESCE來獲取Not taken值:

SELECT s.studentid,
       c.classid,
       COALESCE( TO_CHAR( r.grade ), 'Not taken' ) AS grade
FROM   students s
       CROSS JOIN classes c
       LEFT OUTER JOIN registration r
       ON ( s.studentid = r.studentid AND c.classid = r.classid )

其中,如果您有數據:

INSERT INTO Classes
SELECT LEVEL,
       'Class' || LEVEL,
       'Instructor' || LEVEL
FROM   DUAL
CONNECT BY LEVEL <= 3;

INSERT INTO Students
SELECT TO_CHAR( LEVEL, 'FM000' ),
       'Student' || LEVEL,
       'Major'
FROM   DUAL
CONNECT BY LEVEL <= 5;

INSERT INTO Registration
SELECT 1, '001', 4 FROM DUAL UNION ALL
SELECT 1, '002', 2 FROM DUAL UNION ALL
SELECT 1, '003', 5 FROM DUAL UNION ALL
SELECT 2, '001', 3 FROM DUAL UNION ALL
SELECT 3, '001', 1 FROM DUAL;

然后輸出:

\n學生證 | 經典 | 年級    \n :-------- |  :------ |  :--------\n 001 |  1 |  4        \n 002 |  1 |  2        \n 003 |  1 |  5        \n 001 |  2 |  3        \n 001 |  3 |  1        \n 005 |  1 | 不采取\n 004 |  2 | 不采取\n 003 |  3 | 不采取\n 005 |  3 | 不采取\n 005 |  2 | 不采取\n 002 |  2 | 不采取\n 003 |  2 | 不采取\n 004 |  1 | 不采取\n 002 |  3 | 不采取\n 004 |  3 | 不采取\n

如果你想旋轉它,那么:

SELECT *
FROM   (
  SELECT s.studentid,
         c.classid,
         COALESCE( TO_CHAR( r.grade ), 'Not taken' ) AS grade
  FROM   students s
         CROSS JOIN classes c
         LEFT OUTER JOIN registration r
         ON ( s.studentid = r.studentid AND c.classid = r.classid )
)
PIVOT ( MAX( grade ) FOR classid IN (
  1 AS Class1,
  2 AS Class2,
  3 AS Class3
) )
ORDER BY StudentID

哪些輸出:

\n學生證 |  1 級 |  2 級 |  3級   \n :-------- |  :-------- |  :-------- |  :--------\n 001 |  4 |  3 |  1        \n 002 |  2 | 未采取| 不采取\n 003 |  5 | 未采取| 不采取\n 004 | 未采取| 未采取| 不采取\n 005 | 未采取| 未采取| 不采取\n

db<> 在這里擺弄

這只是條件聚合:

select s.studentid,
       max(case when r.classid = 1 then r.grade end) as class1_grade,
       max(case when r.classid = 2 then r.grade end) as class2_grade,
       . . .
from students s left join
     registrations r
     on r.studentid = s.studentid;

您必須明確列出列。 為避免這種情況,您需要動態 SQL( execute immediate )。

獲得每行一個等級的結果更簡單。 使用cross join生成行和left join以引入值:

select s.studentid, c.classid, r.grade
from students s cross join
     classes c left join
     registrations r
     on r.studentid = s.studentid and r.classid = c.classid;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM