Oracle 查询将多级多对多关系分组为独立的组
Oracle query to group multi level many to many relationships into independent groups
基于对学生和学科交叉引用的多级多对多依赖,如何形成一个 ORACLE sql/plsql 查询来 GROUP Student_Subject table 以便组是独立的& 独家如下?我实际有 519 行 table。我正在寻找一个高效的解决方案
示例来源 table :
预期目标输出:
实际来源Table数据创建查询
CREATE TABLE student_subject ( student_name, subject_name ) AS
SELECT 'SMITH', 'CHEMISTRY' FROM DUAL UNION ALL
SELECT 'ROBIN', 'PHYSICS' FROM DUAL UNION ALL
SELECT 'SAM', 'PHYSICS' FROM DUAL UNION ALL
SELECT 'SAM', 'MATH' FROM DUAL UNION ALL
SELECT 'JENNY', 'MATH' FROM DUAL UNION ALL
SELECT 'JENNY', 'ACCOUNTS' FROM DUAL UNION ALL
SELECT 'DON', 'ENGLISH' FROM DUAL UNION ALL
SELECT 'DON', 'SPANISH' FROM DUAL UNION ALL
SELECT 'RON', 'HISTORY' FROM DUAL UNION ALL
SELECT 'JOVAN', 'HISTORY' FROM DUAL UNION ALL
-- etc. for an additional 509 more rows
虽然您没有指定分类标准,但在分析您的输出后 table,我们可以假设:
- 第 1 组:一对一(学生-主题对);
- Group2:多对多;
- Group3:一对多;
- Group4:多对一;
实施此分类的一种方法是按组创建某种汇总统计信息,例如计数最大值。所以:
- 首先,您可以按学科统计学生人数(创建
student_by_subject
变量)。
- 其次,您按学生 (
subject_by_student
) 计算科目,并按学生 (max_student
) 计算 student_by_subject
的最大值。
- 第三,计算
subject_by_student
的最大值(max_subject
);
- 第四,根据最大计数变量对组进行分类;
这可以在单个查询中完成:
create table want as
select
student_name, subject_name,
case when max_student=1 and max_subject=1 then 1
when max_student>1 and max_subject>1 then 2
when max_student=1 and max_subject>1 then 3
when max_student>1 and max_subject=1 then 4 end as NEW_GROUP
from (select subject_name, student_name, max_student,
max(subject_by_student) as max_subject
from (select student_name, subject_name, student_by_subject,
count(subject_name) as subject_by_student,
max(student_by_subject) as max_student
from (select student_name, subject_name,
count(student_name) as student_by_subject
from student_subject group by subject_name)
group by student_name)
group by subject_name)
ORDER by NEW_GROUP;
您可以使用分层查询来查找群组:
SELECT MIN( id ) AS id,
student_name,
subject_name
FROM (
SELECT CONNECT_BY_ROOT( id ) AS id,
student_name,
subject_name
FROM (
SELECT student_name,
subject_name,
ROW_NUMBER() OVER ( ORDER BY subject_name, student_name ) AS id,
ROW_NUMBER() OVER ( PARTITION BY subject_name ORDER BY student_name ) AS rn
FROM student_subject s
)
START WITH rn = 1
CONNECT BY NOCYCLE
PRIOR student_name = student_name
OR PRIOR subject_name = subject_name
)
GROUP BY
student_name,
subject_name
ORDER BY
id,
subject_name,
student_name
其中,对于示例数据:
CREATE TABLE student_subject ( student_name, subject_name ) AS
SELECT 'SMITH', 'CHEMISTRY' FROM DUAL UNION ALL
SELECT 'ROBIN', 'PHYSICS' FROM DUAL UNION ALL
SELECT 'SAM', 'PHYSICS' FROM DUAL UNION ALL
SELECT 'SAM', 'MATH' FROM DUAL UNION ALL
SELECT 'JENNY', 'MATH' FROM DUAL UNION ALL
SELECT 'JENNY', 'ACCOUNTS' FROM DUAL UNION ALL
SELECT 'DON', 'ENGLISH' FROM DUAL UNION ALL
SELECT 'DON', 'SPANISH' FROM DUAL UNION ALL
SELECT 'RON', 'HISTORY' FROM DUAL UNION ALL
SELECT 'JOVAN', 'HISTORY' FROM DUAL;
输出:
ID | STUDENT_NAME | SUBJECT_NAME
-: | :----------- | :-----------
1 | JENNY | ACCOUNTS
1 | JENNY | MATH
1 | SAM | MATH
1 | ROBIN | PHYSICS
1 | SAM | PHYSICS
2 | SMITH | CHEMISTRY
3 | DON | ENGLISH
3 | DON | SPANISH
4 | JOVAN | HISTORY
4 | RON | HISTORY
db<>fiddle here
I am looking for a performant solution
如果你想要性能,那就忘记SQL。对于您的(高度连接的)数据,没有办法使用不会查看大量额外、不必要数据的 CONNECT BY
技巧。
这是一个简单的 PL/SQL 块,可以非常快速地完成。到目前为止,我相信比纯 SQL 更快。 (和往常一样,如果这意味着学习新东西,我会很高兴地吃乌鸦...)
这是通过从尚未分配给组的行中找到具有最低 subject_name
的记录来实现的。这些获得分配的下一个组号。然后,我们无限期地循环查找与新组中的行直接相关的行,并将这些行分配给新组。当我们找不到更多直接相关的行时,该组结束,我们开始下一组。当我们无法创建任何新组时,我们就完成了。
-- Add a column to student_subject to hold the group number results
ALTER TABLE student_subject ADD ( group_number NUMBER );
-- Let's time it...
SET TIMING ON
-- Go through and assign group numbers to each record.
-- Doing it iteratively in PL/SQL means we can easily look at each row only once.
BEGIN
UPDATE student_subject SET group_number = null;
LOOP
UPDATE student_subject ss
SET group_number = ( SELECT nvl(max(group_number),0)+1 FROM student_subject ss2 ) -- Assign next group number
WHERE subject_name = ( SELECT min(subject_name) FROM student_subject ss2 WHERE group_number IS NULL );
EXIT WHEN SQL%ROWCOUNT = 0; -- done.. all rows have groups now.
LOOP
UPDATE student_subject ss
SET group_number = ( SELECT max(group_number) FROM student_subject ss2 )
WHERE group_number is null
AND EXISTS ( SELECT 'direct relation' FROM student_subject ss2 WHERE (ss2.subject_name = ss.subject_name OR ss2.student_name = ss.student_name ) AND ss2.group_number = ( SELECT max(group_number) FROM student_subject ss3 ) );
EXIT WHEN SQL%ROWCOUNT = 0; -- finished group. move to next group
END LOOP;
END LOOP;
END;
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.128
您可以通过将更新中的 (SELECT...
表达式替换为 PL/SQL 变量来进一步优化它。例如,跟踪当前组号而不是每次都选择 MAX()
。我只是懒惰。
您可以使用 PL/SQL 流水线函数:
如果创建类型:
CREATE TYPE ssg_obj AS OBJECT (
student_name VARCHAR2(100),
subject_name VARCHAR2(100),
grp NUMBER(8,0)
);
CREATE TYPE ssg_tbl AS TABLE OF ssg_obj;
那么你可以使用:
CREATE FUNCTION get_student_subject_groups RETURN ssg_tbl PIPELINED
IS
TYPE stud_tbl IS TABLE OF STUDENT_SUBJECT.STUDENT_NAME%TYPE;
TYPE subj_tbl IS TABLE OF STUDENT_SUBJECT.SUBJECT_NAME%TYPE;
ssgs ssg_tbl;
t_found_students stud_tbl;
t_found_subjects subj_tbl;
v_grp PLS_INTEGER := 0;
v_min_idx PLS_INTEGER := 0;
v_found BOOLEAN;
v_match_subj BOOLEAN;
v_match_stud BOOLEAN;
BEGIN
SELECT ssg_obj( student_name, subject_name, 0 )
BULK COLLECT INTO ssgs
FROM student_subject;
LOOP
v_grp := v_grp + 1;
v_found := FALSE;
FOR i IN v_min_idx + 1 .. ssgs.COUNT LOOP
IF ssgs(i).grp = 0 THEN
v_min_idx := i;
ssgs(i).grp := v_grp;
PIPE ROW( ssgs(i) );
t_found_students := stud_tbl( ssgs(i).student_name );
t_found_subjects := subj_tbl( ssgs(i).subject_name );
v_found := TRUE;
EXIT;
END IF;
END LOOP;
EXIT WHEN NOT v_found;
LOOP
v_found := FALSE;
FOR i IN v_min_idx + 1 .. ssgs.COUNT LOOP
IF ssgs(i).grp > 0 THEN
CONTINUE;
END IF;
v_match_subj := ssgs(i).subject_name MEMBER OF t_found_subjects;
v_match_stud := ssgs(i).student_name MEMBER OF t_found_students;
IF v_match_subj OR v_match_stud THEN
ssgs(i).grp := v_grp;
PIPE ROW( ssgs(i) );
IF NOT v_match_subj THEN
t_found_subjects.EXTEND;
t_found_subjects(t_found_subjects.COUNT) := ssgs(i).subject_name;
v_found := TRUE;
END IF;
IF NOT v_match_stud THEN
t_found_students.EXTEND;
t_found_students(t_found_students.COUNT) := ssgs(i).student_name;
v_found := TRUE;
END IF;
END IF;
END LOOP;
EXIT WHEN NOT v_found;
END LOOP;
END LOOP;
END;
/
然后:
SELECT *
FROM TABLE( get_student_subject_groups() )
输出(对于您的大样本数据):
STUDENT_NAME | SUBJECT_NAME | GRP
:----------- | :--------------------------------- | --:
LIAM | ACCOUNTING | 1
NOAH | ACCOUNTING | 1
OLIVER | ACCOUNTING | 1
WILLIAM | ACCOUNTING | 1
ELIJAH | ACCOUNTING | 1
JAMES | ACCOUNTING | 1
BENJAMIN | ACCOUNTING | 1
LUCAS | ACCOUNTING | 1
MASON | ACCOUNTING | 1
LIAM | BUSINESS_LAW | 1
NOAH | BUSINESS_LAW | 1
WILLIAM | BUSINESS_LAW | 1
ELIJAH | BUSINESS_LAW | 1
ETHAN | BUSINESS_LAW | 1
ALEXANDER | BUSINESS_LAW | 1
HENRY | BUSINESS_LAW | 1
JACOB | BUSINESS_LAW | 1
MICHAEL | BUSINESS_LAW | 1
DANIEL | BUSINESS_LAW | 1
LOGAN | BUSINESS_LAW | 1
JACKSON | BUSINESS_LAW | 1
SEBASTIAN | BUSINESS_LAW | 1
JACK | BUSINESS_LAW | 1
AIDEN | BUSINESS_LAW | 1
OWEN | BUSINESS_LAW | 1
SAMUEL | BUSINESS_LAW | 1
MATTHEW | BUSINESS_LAW | 1
JOSEPH | BUSINESS_LAW | 1
NOAH | BUSINESS_MANAGEMENT | 1
OLIVER | BUSINESS_MANAGEMENT | 1
WILLIAM | BUSINESS_MANAGEMENT | 1
ELIJAH | BUSINESS_MANAGEMENT | 1
LEVI | BUSINESS_MANAGEMENT | 1
BENJAMIN | BUSINESS_MANAGEMENT | 1
LUCAS | BUSINESS_MANAGEMENT | 1
MATEO | BUSINESS_MANAGEMENT | 1
DAVID | BUSINESS_MANAGEMENT | 1
ETHAN | BUSINESS_MANAGEMENT | 1
ALEXANDER | BUSINESS_MANAGEMENT | 1
HENRY | BUSINESS_MANAGEMENT | 1
JACOB | BUSINESS_MANAGEMENT | 1
MICHAEL | BUSINESS_MANAGEMENT | 1
JOHN | BUSINESS_MANAGEMENT | 1
WYATT | BUSINESS_MANAGEMENT | 1
CARTER | BUSINESS_MANAGEMENT | 1
JULIAN | BUSINESS_MANAGEMENT | 1
LUKE | BUSINESS_MANAGEMENT | 1
GRAYSON | BUSINESS_MANAGEMENT | 1
LIAM | INTRODUCTION_TO_BUSINESS | 1
LUKE | INTRODUCTION_TO_BUSINESS | 1
LIAM | PERSONAL_FINANCE | 1
NOAH | PERSONAL_FINANCE | 1
ELIJAH | PERSONAL_FINANCE | 1
LOGAN | PERSONAL_FINANCE | 1
LIAM | APP_DEVELOPMENT | 1
ANTHONY | APP_DEVELOPMENT | 1
NOAH | APP_DEVELOPMENT | 1
WILLIAM | APP_DEVELOPMENT | 1
ELIJAH | APP_DEVELOPMENT | 1
ETHAN | APP_DEVELOPMENT | 1
LOGAN | APP_DEVELOPMENT | 1
DYLAN | APP_DEVELOPMENT | 1
LIAM | AUDIO_PRODUCTION | 1
ANTHONY | AUDIO_PRODUCTION | 1
NOAH | AUDIO_PRODUCTION | 1
OLIVER | AUDIO_PRODUCTION | 1
WILLIAM | AUDIO_PRODUCTION | 1
ELIJAH | AUDIO_PRODUCTION | 1
JAMES | AUDIO_PRODUCTION | 1
LEVI | AUDIO_PRODUCTION | 1
BENJAMIN | AUDIO_PRODUCTION | 1
LUCAS | AUDIO_PRODUCTION | 1
MATEO | AUDIO_PRODUCTION | 1
DAVID | AUDIO_PRODUCTION | 1
LOGAN | AUDIO_PRODUCTION | 1
ISAAC | AUDIO_PRODUCTION | 1
LEO | AUDIO_PRODUCTION | 1
MASON | AUDIO_PRODUCTION | 1
LINCOLN | AUDIO_PRODUCTION | 1
JAYDEN | AUDIO_PRODUCTION | 1
JAXON | AUDIO_PRODUCTION | 1
LIAM | COMPUTER_PROGRAMMING | 1
OLIVER | COMPUTER_PROGRAMMING | 1
ASHER | COMPUTER_PROGRAMMING | 1
ELIJAH | COMPUTER_PROGRAMMING | 1
CHRISTOPHER | COMPUTER_PROGRAMMING | 1
LUCAS | COMPUTER_PROGRAMMING | 1
DAVID | COMPUTER_PROGRAMMING | 1
JOSIAH | COMPUTER_PROGRAMMING | 1
DYLAN | COMPUTER_PROGRAMMING | 1
ANDREW | COMPUTER_PROGRAMMING | 1
THOMAS | COMPUTER_PROGRAMMING | 1
WILLIAM | COMPUTER_REPAIR | 1
LIAM | FILM_PRODUCTION | 1
JOSHUA | FILM_PRODUCTION | 1
NOAH | FILM_PRODUCTION | 1
OLIVER | FILM_PRODUCTION | 1
ASHER | FILM_PRODUCTION | 1
ELIJAH | FILM_PRODUCTION | 1
EZRA | FILM_PRODUCTION | 1
BENJAMIN | FILM_PRODUCTION | 1
LUCAS | FILM_PRODUCTION | 1
MATEO | FILM_PRODUCTION | 1
DAVID | FILM_PRODUCTION | 1
HUDSON | FILM_PRODUCTION | 1
JOSIAH | FILM_PRODUCTION | 1
DYLAN | FILM_PRODUCTION | 1
THOMAS | FILM_PRODUCTION | 1
LIAM | GRAPHIC_DESIGN | 1
LIAM | MEDIA_TECHNOLOGY | 1
NOAH | MEDIA_TECHNOLOGY | 1
DYLAN | MEDIA_TECHNOLOGY | 1
SEBASTIAN | MUSIC_PRODUCTION | 1
CHARLES | MUSIC_PRODUCTION | 1
JOSEPH | MUSIC_PRODUCTION | 1
LIAM | TYPING | 1
NOAH | TYPING | 1
ELIJAH | TYPING | 1
DYLAN | TYPING | 1
LIAM | VIDEO_GAME_DEVELOPMENT | 1
NOAH | VIDEO_GAME_DEVELOPMENT | 1
LIAM | WEB_DESIGN | 1
CALEB | WEB_DESIGN | 1
ISAIAH | WEB_DESIGN | 1
WILLIAM | WEB_DESIGN | 1
ELIJAH | WEB_DESIGN | 1
ETHAN | WEB_DESIGN | 1
JACOB | WEB_DESIGN | 1
LOGAN | WEB_DESIGN | 1
LIAM | WORD_PROCESSING | 1
ELIJAH | AMERICAN_LITERATURE | 1
LIAM | BRITISH_LITERATURE | 1
WILLIAM | BRITISH_LITERATURE | 1
ELIJAH | BRITISH_LITERATURE | 1
ETHAN | BRITISH_LITERATURE | 1
JACOB | BRITISH_LITERATURE | 1
JACK | BRITISH_LITERATURE | 1
SAMUEL | BRITISH_LITERATURE | 1
LIAM | CONTEMPORARY_LITERATURE | 1
ELIJAH | CONTEMPORARY_LITERATURE | 1
LEVI | CONTEMPORARY_LITERATURE | 1
ISAAC | CONTEMPORARY_LITERATURE | 1
LINCOLN | CONTEMPORARY_LITERATURE | 1
JAXON | CONTEMPORARY_LITERATURE | 1
LIAM | COMMUNICATION_SKILLS | 1
NOAH | COMMUNICATION_SKILLS | 1
OLIVER | COMMUNICATION_SKILLS | 1
ELIJAH | COMMUNICATION_SKILLS | 1
BENJAMIN | COMMUNICATION_SKILLS | 1
LUCAS | COMMUNICATION_SKILLS | 1
DAVID | COMMUNICATION_SKILLS | 1
JOHN | COMMUNICATION_SKILLS | 1
LUKE | COMMUNICATION_SKILLS | 1
ANDREW | COMMUNICATION_SKILLS | 1
MAVERICK | COMMUNICATION_SKILLS | 1
LIAM | DEBATE | 1
NOAH | DEBATE | 1
LIAM | ENGLISH_LANGUAGE_AND_COMPOSITION | 1
ELIJAH | ENGLISH_LANGUAGE_AND_COMPOSITION | 1
BENJAMIN | ENGLISH_LANGUAGE_AND_COMPOSITION | 1
MASON | ENGLISH_LANGUAGE_AND_COMPOSITION | 1
MATEO | HUMANITIES | 1
DAVID | HUMANITIES | 1
ISAAC | HUMANITIES | 1
LINCOLN | HUMANITIES | 1
LIAM | JOURNALISM | 1
COLTON | JOURNALISM | 1
ELIAS | JOURNALISM | 1
ELIJAH | JOURNALISM | 1
LEVI | JOURNALISM | 1
LIAM | LITERARY_ANALYSIS | 1
AARON | LITERARY_ANALYSIS | 1
ELIAS | LITERARY_ANALYSIS | 1
ELIJAH | LITERARY_ANALYSIS | 1
LEVI | LITERARY_ANALYSIS | 1
AARON | MODERN_LITERATURE | 1
ELIAS | MODERN_LITERATURE | 1
LEVI | MODERN_LITERATURE | 1
AARON | POETRY | 1
ELIAS | POETRY | 1
LEVI | POETRY | 1
ELIAS | POPULAR_LITERATURE | 1
LEVI | POPULAR_LITERATURE | 1
BENJAMIN | RHETORIC | 1
ISAAC | RHETORIC | 1
MASON | RHETORIC | 1
ELIJAH | TECHNICAL_WRITING | 1
ANTHONY | WORKS_OF_SHAKESPEARE | 1
ELIJAH | WORKS_OF_SHAKESPEARE | 1
LEVI | WORKS_OF_SHAKESPEARE | 1
LIAM | WORLD_LITERATURE | 1
ETHAN | WORLD_LITERATURE | 1
ALEXANDER | WORLD_LITERATURE | 1
HENRY | WORLD_LITERATURE | 1
JACOB | WORLD_LITERATURE | 1
LOGAN | WRITTEN_AND_ORAL_COMMUNICATION | 1
MASON | WRITTEN_AND_ORAL_COMMUNICATION | 1
ELI | WRITTEN_AND_ORAL_COMMUNICATION | 1
LIAM | CHEMISTRY_OF_FOODS | 1
ANTHONY | CHEMISTRY_OF_FOODS | 1
LANDON | CHEMISTRY_OF_FOODS | 1
JONATHAN | CHEMISTRY_OF_FOODS | 1
NOLAN | CHEMISTRY_OF_FOODS | 1
NOAH | CHEMISTRY_OF_FOODS | 1
HUNTER | CHEMISTRY_OF_FOODS | 1
OLIVER | CHEMISTRY_OF_FOODS | 1
WILLIAM | CHEMISTRY_OF_FOODS | 1
ELIJAH | CHEMISTRY_OF_FOODS | 1
CAMERON | CHEMISTRY_OF_FOODS | 1
BENJAMIN | CHEMISTRY_OF_FOODS | 1
LUCAS | CHEMISTRY_OF_FOODS | 1
LOGAN | CHEMISTRY_OF_FOODS | 1
MASON | CHEMISTRY_OF_FOODS | 1
DYLAN | CHEMISTRY_OF_FOODS | 1
DYLAN | CPR_TRAINING | 1
LIAM | CULINARY_ARTS | 1
ELIJAH | CULINARY_ARTS | 1
GABRIEL | CULINARY_ARTS | 1
LIAM | EARLY_CHILDHOOD_DEVELOPMENT | 1
SANTIAGO | EARLY_CHILDHOOD_DEVELOPMENT | 1
JEREMIAH | EARLY_CHILDHOOD_DEVELOPMENT | 1
JOSHUA | EARLY_CHILDHOOD_DEVELOPMENT | 1
NOAH | EARLY_CHILDHOOD_DEVELOPMENT | 1
ASHER | EARLY_CHILDHOOD_DEVELOPMENT | 1
ELIJAH | EARLY_CHILDHOOD_DEVELOPMENT | 1
THEODORE | EARLY_CHILDHOOD_DEVELOPMENT | 1
EZRA | EARLY_CHILDHOOD_DEVELOPMENT | 1
LEVI | EARLY_CHILDHOOD_DEVELOPMENT | 1
RYAN | EARLY_CHILDHOOD_DEVELOPMENT | 1
EZEKIEL | EARLY_CHILDHOOD_DEVELOPMENT | 1
ANGEL | EARLY_CHILDHOOD_DEVELOPMENT | 1
JOSIAH | EARLY_CHILDHOOD_DEVELOPMENT | 1
ROMAN | EARLY_CHILDHOOD_DEVELOPMENT | 1
EASTON | EARLY_CHILDHOOD_DEVELOPMENT | 1
LOGAN | EARLY_CHILDHOOD_DEVELOPMENT | 1
MILES | EARLY_CHILDHOOD_DEVELOPMENT | 1
ROBERT | EARLY_CHILDHOOD_DEVELOPMENT | 1
JAMESON | EARLY_CHILDHOOD_DEVELOPMENT | 1
NICHOLAS | EARLY_CHILDHOOD_DEVELOPMENT | 1
GREYSON | EARLY_CHILDHOOD_DEVELOPMENT | 1
COOPER | EARLY_CHILDHOOD_DEVELOPMENT | 1
IAN | EARLY_CHILDHOOD_DEVELOPMENT | 1
MASON | EARLY_CHILDHOOD_DEVELOPMENT | 1
CARSON | EARLY_CHILDHOOD_DEVELOPMENT | 1
AXEL | EARLY_CHILDHOOD_DEVELOPMENT | 1
JAXSON | EARLY_CHILDHOOD_DEVELOPMENT | 1
DOMINIC | EARLY_CHILDHOOD_DEVELOPMENT | 1
LEONARDO | EARLY_CHILDHOOD_DEVELOPMENT | 1
LUCA | EARLY_CHILDHOOD_DEVELOPMENT | 1
AUSTIN | EARLY_CHILDHOOD_DEVELOPMENT | 1
JORDAN | EARLY_CHILDHOOD_DEVELOPMENT | 1
ADAM | EARLY_CHILDHOOD_DEVELOPMENT | 1
XAVIER | EARLY_CHILDHOOD_DEVELOPMENT | 1
JOSE | EARLY_CHILDHOOD_DEVELOPMENT | 1
LIAM | EARLY_CHILDHOOD_EDUCATION | 1
ANTHONY | EARLY_CHILDHOOD_EDUCATION | 1
NOAH | EARLY_CHILDHOOD_EDUCATION | 1
BENJAMIN | EARLY_CHILDHOOD_EDUCATION | 1
MATEO | EARLY_CHILDHOOD_EDUCATION | 1
LOGAN | EARLY_CHILDHOOD_EDUCATION | 1
ISAAC | EARLY_CHILDHOOD_EDUCATION | 1
MASON | EARLY_CHILDHOOD_EDUCATION | 1
JAXON | EARLY_CHILDHOOD_EDUCATION | 1
LIAM | FAMILY_STUDIES | 1
ELIJAH | FAMILY_STUDIES | 1
RYAN | FAMILY_STUDIES | 1
DYLAN | FAMILY_STUDIES | 1
DYLAN | FASHION_AND_RETAIL_MERCHANDISING | 1
LIAM | FASHION_CONSTRUCTION | 1
SANTIAGO | FASHION_CONSTRUCTION | 1
JEREMIAH | FASHION_CONSTRUCTION | 1
ASHER | FASHION_CONSTRUCTION | 1
ELIJAH | FASHION_CONSTRUCTION | 1
JOSIAH | FASHION_CONSTRUCTION | 1
ROBERT | FASHION_CONSTRUCTION | 1
JAMESON | FASHION_CONSTRUCTION | 1
GREYSON | FASHION_CONSTRUCTION | 1
DYLAN | FASHION_CONSTRUCTION | 1
LIAM | HOME_ECONOMICS | 1
NOAH | HOME_ECONOMICS | 1
JACE | HOME_ECONOMICS | 1
WILLIAM | HOME_ECONOMICS | 1
ELIJAH | HOME_ECONOMICS | 1
CONNOR | HOME_ECONOMICS | 1
LEVI | HOME_ECONOMICS | 1
BENJAMIN | HOME_ECONOMICS | 1
EVERETT | HOME_ECONOMICS | 1
MATEO | HOME_ECONOMICS | 1
DECLAN | HOME_ECONOMICS | 1
LOGAN | HOME_ECONOMICS | 1
ISAAC | HOME_ECONOMICS | 1
GRAYSON | HOME_ECONOMICS | 1
EVAN | HOME_ECONOMICS | 1
MASON | HOME_ECONOMICS | 1
JAXON | HOME_ECONOMICS | 1
LIAM | INTERIOR_DESIGN | 1
KAYDEN | INTERIOR_DESIGN | 1
PARKER | INTERIOR_DESIGN | 1
WESLEY | INTERIOR_DESIGN | 1
KAI | INTERIOR_DESIGN | 1
BRAYDEN | INTERIOR_DESIGN | 1
BRYSON | INTERIOR_DESIGN | 1
WESTON | INTERIOR_DESIGN | 1
NOAH | INTERIOR_DESIGN | 1
ELIJAH | INTERIOR_DESIGN | 1
BENJAMIN | INTERIOR_DESIGN | 1
JOHN | INTERIOR_DESIGN | 1
CARTER | INTERIOR_DESIGN | 1
LOGAN | INTERIOR_DESIGN | 1
JULIAN | INTERIOR_DESIGN | 1
ISAAC | INTERIOR_DESIGN | 1
MASON | INTERIOR_DESIGN | 1
JASON | INTERIOR_DESIGN | 1
ELI | INTERIOR_DESIGN | 1
EMMETT | INTERIOR_DESIGN | 1
SAWYER | INTERIOR_DESIGN | 1
SILAS | INTERIOR_DESIGN | 1
LOGAN | NUTRITION | 1
BROOKS | NUTRITION | 1
MICAH | NUTRITION | 1
DAMIAN | NUTRITION | 1
MASON | NUTRITION | 1
HARRISON | NUTRITION | 1
ELI | NUTRITION | 1
WAYLON | NUTRITION | 1
AIDEN | NUTRITION | 1
AYDEN | NUTRITION | 1
VINCENT | NUTRITION | 1
LIAM | AMERICAN_SIGN_LANGUAGE | 1
NOAH | AMERICAN_SIGN_LANGUAGE | 1
ELIJAH | AMERICAN_SIGN_LANGUAGE | 1
BENJAMIN | AMERICAN_SIGN_LANGUAGE | 1
RYDER | AMERICAN_SIGN_LANGUAGE | 1
WYATT | AMERICAN_SIGN_LANGUAGE | 1
MASON | AMERICAN_SIGN_LANGUAGE | 1
LIAM | ANCIENT_GREEK | 1
NOAH | ANCIENT_GREEK | 1
ELIJAH | ANCIENT_GREEK | 1
ETHAN | ANCIENT_GREEK | 1
LIAM | ARABIC | 1
NOAH | ARABIC | 1
LOGAN | ARABIC | 1
JACKSON | ARABIC | 1
OWEN | ARABIC | 1
KINGSTON | ARABIC | 1
CHARLES | ARABIC | 1
JOSEPH | ARABIC | 1
LIAM | FRENCH | 1
AIDEN | FRENCH | 1
MATTHEW | FRENCH | 1
LIAM | GERMAN | 1
ELIJAH | GERMAN | 1
MATEO | GERMAN | 1
GRAYSON | GERMAN | 1
JAXON | GERMAN | 1
ELIJAH | HEBREW | 1
DYLAN | HEBREW | 1
JAXON | HEBREW | 1
LIAM | JAPANESE | 1
LIAM | KOREAN | 1
ANTHONY | KOREAN | 1
NOAH | KOREAN | 1
OLIVER | KOREAN | 1
ELIJAH | KOREAN | 1
THEODORE | KOREAN | 1
EZRA | KOREAN | 1
LEVI | KOREAN | 1
RYAN | KOREAN | 1
BENJAMIN | KOREAN | 1
LUCAS | KOREAN | 1
DAVID | KOREAN | 1
JOHN | KOREAN | 1
CARTER | KOREAN | 1
LOGAN | KOREAN | 1
JULIAN | KOREAN | 1
JACKSON | KOREAN | 1
LUKE | KOREAN | 1
DAMIAN | KOREAN | 1
ISAAC | KOREAN | 1
GRAYSON | KOREAN | 1
GAVIN | KOREAN | 1
MASON | KOREAN | 1
JASON | KOREAN | 1
HARRISON | KOREAN | 1
EMMETT | KOREAN | 1
JORDAN | KOREAN | 1
JAXON | KOREAN | 1
JOSEPH | KOREAN | 1
ADAM | KOREAN | 1
XAVIER | KOREAN | 1
ELIJAH | LATIN | 1
MATEO | LATIN | 1
JAXON | LATIN | 1
LIAM | PORTUGUESE | 1
LANDON | PORTUGUESE | 1
JONATHAN | PORTUGUESE | 1
NOAH | PORTUGUESE | 1
HUNTER | PORTUGUESE | 1
OLIVER | PORTUGUESE | 1
JACE | PORTUGUESE | 1
WILLIAM | PORTUGUESE | 1
ELIJAH | PORTUGUESE | 1
CAMERON | PORTUGUESE | 1
JAMES | PORTUGUESE | 1
CONNOR | PORTUGUESE | 1
BENJAMIN | PORTUGUESE | 1
LUCAS | PORTUGUESE | 1
EVERETT | PORTUGUESE | 1
MATEO | PORTUGUESE | 1
DAVID | PORTUGUESE | 1
WYATT | PORTUGUESE | 1
LOGAN | PORTUGUESE | 1
ISAAC | PORTUGUESE | 1
GRAYSON | PORTUGUESE | 1
MASON | PORTUGUESE | 1
DYLAN | PORTUGUESE | 1
LINCOLN | PORTUGUESE | 1
JAXON | PORTUGUESE | 1
RYAN | RUSSIAN | 1
RYDER | RUSSIAN | 1
DYLAN | RUSSIAN | 1
EMMETT | SPANISH | 1
NICHOLAS | ALGEBRA_1 | 1
LEONARDO | ALGEBRA_1 | 1
SANTIAGO | ALGEBRA_2 | 1
JEREMIAH | ALGEBRA_2 | 1
TYLER | ALGEBRA_2 | 1
NOAH | ALGEBRA_2 | 1
ASHER | ALGEBRA_2 | 1
THEODORE | ALGEBRA_2 | 1
EZRA | ALGEBRA_2 | 1
LEVI | ALGEBRA_2 | 1
RYAN | ALGEBRA_2 | 1
BENJAMIN | ALGEBRA_2 | 1
EZEKIEL | ALGEBRA_2 | 1
ANGEL | ALGEBRA_2 | 1
JOSIAH | ALGEBRA_2 | 1
ROMAN | ALGEBRA_2 | 1
EASTON | ALGEBRA_2 | 1
LOGAN | ALGEBRA_2 | 1
MILES | ALGEBRA_2 | 1
ROBERT | ALGEBRA_2 | 1
JAMESON | ALGEBRA_2 | 1
NICHOLAS | ALGEBRA_2 | 1
GREYSON | ALGEBRA_2 | 1
ISAAC | ALGEBRA_2 | 1
COOPER | ALGEBRA_2 | 1
GRAYSON | ALGEBRA_2 | 1
IAN | ALGEBRA_2 | 1
MASON | ALGEBRA_2 | 1
CARSON | ALGEBRA_2 | 1
AXEL | ALGEBRA_2 | 1
JAXSON | ALGEBRA_2 | 1
DOMINIC | ALGEBRA_2 | 1
ISAAC | CONSUMER_EDUCATION | 1
JAYDEN | ENTREPRENEURIAL_SKILLS | 1
THEODORE | MARKETING | 1
GABRIEL | ANIMATION | 1
RYAN | WEB_PROGRAMMING | 1
GABRIEL | ENGLISH_LITERATURE_AND_COMPOSITION | 1
CONNOR | CPR_TRAINING | 1
BENNETT | NUTRITION | 1
TYLER | ALGEBRA_1 | 1
NATHAN | CREATIVE_WRITING | 2
ADRIAN | CREATIVE_WRITING | 2
CHRISTIAN | CREATIVE_WRITING | 2
ROWAN | CHINESE | 3
GEORGE | CHINESE | 3
LUIS | CHINESE | 3
CHASE | CHINESE | 3
COLE | CHINESE | 3
NATHANIEL | CHINESE | 3
ZACHARY | CHINESE | 3
ASHTON | CHINESE | 3
BRAXTON | ITALIAN | 4
db<>fiddle here
基于对学生和学科交叉引用的多级多对多依赖,如何形成一个 ORACLE sql/plsql 查询来 GROUP Student_Subject table 以便组是独立的& 独家如下?我实际有 519 行 table。我正在寻找一个高效的解决方案
示例来源 table :
预期目标输出:
实际来源Table数据创建查询
CREATE TABLE student_subject ( student_name, subject_name ) AS
SELECT 'SMITH', 'CHEMISTRY' FROM DUAL UNION ALL
SELECT 'ROBIN', 'PHYSICS' FROM DUAL UNION ALL
SELECT 'SAM', 'PHYSICS' FROM DUAL UNION ALL
SELECT 'SAM', 'MATH' FROM DUAL UNION ALL
SELECT 'JENNY', 'MATH' FROM DUAL UNION ALL
SELECT 'JENNY', 'ACCOUNTS' FROM DUAL UNION ALL
SELECT 'DON', 'ENGLISH' FROM DUAL UNION ALL
SELECT 'DON', 'SPANISH' FROM DUAL UNION ALL
SELECT 'RON', 'HISTORY' FROM DUAL UNION ALL
SELECT 'JOVAN', 'HISTORY' FROM DUAL UNION ALL
-- etc. for an additional 509 more rows
虽然您没有指定分类标准,但在分析您的输出后 table,我们可以假设:
- 第 1 组:一对一(学生-主题对);
- Group2:多对多;
- Group3:一对多;
- Group4:多对一;
实施此分类的一种方法是按组创建某种汇总统计信息,例如计数最大值。所以:
- 首先,您可以按学科统计学生人数(创建
student_by_subject
变量)。 - 其次,您按学生 (
subject_by_student
) 计算科目,并按学生 (max_student
) 计算student_by_subject
的最大值。 - 第三,计算
subject_by_student
的最大值(max_subject
); - 第四,根据最大计数变量对组进行分类;
这可以在单个查询中完成:
create table want as
select
student_name, subject_name,
case when max_student=1 and max_subject=1 then 1
when max_student>1 and max_subject>1 then 2
when max_student=1 and max_subject>1 then 3
when max_student>1 and max_subject=1 then 4 end as NEW_GROUP
from (select subject_name, student_name, max_student,
max(subject_by_student) as max_subject
from (select student_name, subject_name, student_by_subject,
count(subject_name) as subject_by_student,
max(student_by_subject) as max_student
from (select student_name, subject_name,
count(student_name) as student_by_subject
from student_subject group by subject_name)
group by student_name)
group by subject_name)
ORDER by NEW_GROUP;
您可以使用分层查询来查找群组:
SELECT MIN( id ) AS id,
student_name,
subject_name
FROM (
SELECT CONNECT_BY_ROOT( id ) AS id,
student_name,
subject_name
FROM (
SELECT student_name,
subject_name,
ROW_NUMBER() OVER ( ORDER BY subject_name, student_name ) AS id,
ROW_NUMBER() OVER ( PARTITION BY subject_name ORDER BY student_name ) AS rn
FROM student_subject s
)
START WITH rn = 1
CONNECT BY NOCYCLE
PRIOR student_name = student_name
OR PRIOR subject_name = subject_name
)
GROUP BY
student_name,
subject_name
ORDER BY
id,
subject_name,
student_name
其中,对于示例数据:
CREATE TABLE student_subject ( student_name, subject_name ) AS
SELECT 'SMITH', 'CHEMISTRY' FROM DUAL UNION ALL
SELECT 'ROBIN', 'PHYSICS' FROM DUAL UNION ALL
SELECT 'SAM', 'PHYSICS' FROM DUAL UNION ALL
SELECT 'SAM', 'MATH' FROM DUAL UNION ALL
SELECT 'JENNY', 'MATH' FROM DUAL UNION ALL
SELECT 'JENNY', 'ACCOUNTS' FROM DUAL UNION ALL
SELECT 'DON', 'ENGLISH' FROM DUAL UNION ALL
SELECT 'DON', 'SPANISH' FROM DUAL UNION ALL
SELECT 'RON', 'HISTORY' FROM DUAL UNION ALL
SELECT 'JOVAN', 'HISTORY' FROM DUAL;
输出:
ID | STUDENT_NAME | SUBJECT_NAME -: | :----------- | :----------- 1 | JENNY | ACCOUNTS 1 | JENNY | MATH 1 | SAM | MATH 1 | ROBIN | PHYSICS 1 | SAM | PHYSICS 2 | SMITH | CHEMISTRY 3 | DON | ENGLISH 3 | DON | SPANISH 4 | JOVAN | HISTORY 4 | RON | HISTORY
db<>fiddle here
I am looking for a performant solution
如果你想要性能,那就忘记SQL。对于您的(高度连接的)数据,没有办法使用不会查看大量额外、不必要数据的 CONNECT BY
技巧。
这是一个简单的 PL/SQL 块,可以非常快速地完成。到目前为止,我相信比纯 SQL 更快。 (和往常一样,如果这意味着学习新东西,我会很高兴地吃乌鸦...)
这是通过从尚未分配给组的行中找到具有最低 subject_name
的记录来实现的。这些获得分配的下一个组号。然后,我们无限期地循环查找与新组中的行直接相关的行,并将这些行分配给新组。当我们找不到更多直接相关的行时,该组结束,我们开始下一组。当我们无法创建任何新组时,我们就完成了。
-- Add a column to student_subject to hold the group number results
ALTER TABLE student_subject ADD ( group_number NUMBER );
-- Let's time it...
SET TIMING ON
-- Go through and assign group numbers to each record.
-- Doing it iteratively in PL/SQL means we can easily look at each row only once.
BEGIN
UPDATE student_subject SET group_number = null;
LOOP
UPDATE student_subject ss
SET group_number = ( SELECT nvl(max(group_number),0)+1 FROM student_subject ss2 ) -- Assign next group number
WHERE subject_name = ( SELECT min(subject_name) FROM student_subject ss2 WHERE group_number IS NULL );
EXIT WHEN SQL%ROWCOUNT = 0; -- done.. all rows have groups now.
LOOP
UPDATE student_subject ss
SET group_number = ( SELECT max(group_number) FROM student_subject ss2 )
WHERE group_number is null
AND EXISTS ( SELECT 'direct relation' FROM student_subject ss2 WHERE (ss2.subject_name = ss.subject_name OR ss2.student_name = ss.student_name ) AND ss2.group_number = ( SELECT max(group_number) FROM student_subject ss3 ) );
EXIT WHEN SQL%ROWCOUNT = 0; -- finished group. move to next group
END LOOP;
END LOOP;
END;
PL/SQL procedure successfully completed. Elapsed: 00:00:00.128
您可以通过将更新中的 (SELECT...
表达式替换为 PL/SQL 变量来进一步优化它。例如,跟踪当前组号而不是每次都选择 MAX()
。我只是懒惰。
您可以使用 PL/SQL 流水线函数:
如果创建类型:
CREATE TYPE ssg_obj AS OBJECT (
student_name VARCHAR2(100),
subject_name VARCHAR2(100),
grp NUMBER(8,0)
);
CREATE TYPE ssg_tbl AS TABLE OF ssg_obj;
那么你可以使用:
CREATE FUNCTION get_student_subject_groups RETURN ssg_tbl PIPELINED
IS
TYPE stud_tbl IS TABLE OF STUDENT_SUBJECT.STUDENT_NAME%TYPE;
TYPE subj_tbl IS TABLE OF STUDENT_SUBJECT.SUBJECT_NAME%TYPE;
ssgs ssg_tbl;
t_found_students stud_tbl;
t_found_subjects subj_tbl;
v_grp PLS_INTEGER := 0;
v_min_idx PLS_INTEGER := 0;
v_found BOOLEAN;
v_match_subj BOOLEAN;
v_match_stud BOOLEAN;
BEGIN
SELECT ssg_obj( student_name, subject_name, 0 )
BULK COLLECT INTO ssgs
FROM student_subject;
LOOP
v_grp := v_grp + 1;
v_found := FALSE;
FOR i IN v_min_idx + 1 .. ssgs.COUNT LOOP
IF ssgs(i).grp = 0 THEN
v_min_idx := i;
ssgs(i).grp := v_grp;
PIPE ROW( ssgs(i) );
t_found_students := stud_tbl( ssgs(i).student_name );
t_found_subjects := subj_tbl( ssgs(i).subject_name );
v_found := TRUE;
EXIT;
END IF;
END LOOP;
EXIT WHEN NOT v_found;
LOOP
v_found := FALSE;
FOR i IN v_min_idx + 1 .. ssgs.COUNT LOOP
IF ssgs(i).grp > 0 THEN
CONTINUE;
END IF;
v_match_subj := ssgs(i).subject_name MEMBER OF t_found_subjects;
v_match_stud := ssgs(i).student_name MEMBER OF t_found_students;
IF v_match_subj OR v_match_stud THEN
ssgs(i).grp := v_grp;
PIPE ROW( ssgs(i) );
IF NOT v_match_subj THEN
t_found_subjects.EXTEND;
t_found_subjects(t_found_subjects.COUNT) := ssgs(i).subject_name;
v_found := TRUE;
END IF;
IF NOT v_match_stud THEN
t_found_students.EXTEND;
t_found_students(t_found_students.COUNT) := ssgs(i).student_name;
v_found := TRUE;
END IF;
END IF;
END LOOP;
EXIT WHEN NOT v_found;
END LOOP;
END LOOP;
END;
/
然后:
SELECT *
FROM TABLE( get_student_subject_groups() )
输出(对于您的大样本数据):
STUDENT_NAME | SUBJECT_NAME | GRP :----------- | :--------------------------------- | --: LIAM | ACCOUNTING | 1 NOAH | ACCOUNTING | 1 OLIVER | ACCOUNTING | 1 WILLIAM | ACCOUNTING | 1 ELIJAH | ACCOUNTING | 1 JAMES | ACCOUNTING | 1 BENJAMIN | ACCOUNTING | 1 LUCAS | ACCOUNTING | 1 MASON | ACCOUNTING | 1 LIAM | BUSINESS_LAW | 1 NOAH | BUSINESS_LAW | 1 WILLIAM | BUSINESS_LAW | 1 ELIJAH | BUSINESS_LAW | 1 ETHAN | BUSINESS_LAW | 1 ALEXANDER | BUSINESS_LAW | 1 HENRY | BUSINESS_LAW | 1 JACOB | BUSINESS_LAW | 1 MICHAEL | BUSINESS_LAW | 1 DANIEL | BUSINESS_LAW | 1 LOGAN | BUSINESS_LAW | 1 JACKSON | BUSINESS_LAW | 1 SEBASTIAN | BUSINESS_LAW | 1 JACK | BUSINESS_LAW | 1 AIDEN | BUSINESS_LAW | 1 OWEN | BUSINESS_LAW | 1 SAMUEL | BUSINESS_LAW | 1 MATTHEW | BUSINESS_LAW | 1 JOSEPH | BUSINESS_LAW | 1 NOAH | BUSINESS_MANAGEMENT | 1 OLIVER | BUSINESS_MANAGEMENT | 1 WILLIAM | BUSINESS_MANAGEMENT | 1 ELIJAH | BUSINESS_MANAGEMENT | 1 LEVI | BUSINESS_MANAGEMENT | 1 BENJAMIN | BUSINESS_MANAGEMENT | 1 LUCAS | BUSINESS_MANAGEMENT | 1 MATEO | BUSINESS_MANAGEMENT | 1 DAVID | BUSINESS_MANAGEMENT | 1 ETHAN | BUSINESS_MANAGEMENT | 1 ALEXANDER | BUSINESS_MANAGEMENT | 1 HENRY | BUSINESS_MANAGEMENT | 1 JACOB | BUSINESS_MANAGEMENT | 1 MICHAEL | BUSINESS_MANAGEMENT | 1 JOHN | BUSINESS_MANAGEMENT | 1 WYATT | BUSINESS_MANAGEMENT | 1 CARTER | BUSINESS_MANAGEMENT | 1 JULIAN | BUSINESS_MANAGEMENT | 1 LUKE | BUSINESS_MANAGEMENT | 1 GRAYSON | BUSINESS_MANAGEMENT | 1 LIAM | INTRODUCTION_TO_BUSINESS | 1 LUKE | INTRODUCTION_TO_BUSINESS | 1 LIAM | PERSONAL_FINANCE | 1 NOAH | PERSONAL_FINANCE | 1 ELIJAH | PERSONAL_FINANCE | 1 LOGAN | PERSONAL_FINANCE | 1 LIAM | APP_DEVELOPMENT | 1 ANTHONY | APP_DEVELOPMENT | 1 NOAH | APP_DEVELOPMENT | 1 WILLIAM | APP_DEVELOPMENT | 1 ELIJAH | APP_DEVELOPMENT | 1 ETHAN | APP_DEVELOPMENT | 1 LOGAN | APP_DEVELOPMENT | 1 DYLAN | APP_DEVELOPMENT | 1 LIAM | AUDIO_PRODUCTION | 1 ANTHONY | AUDIO_PRODUCTION | 1 NOAH | AUDIO_PRODUCTION | 1 OLIVER | AUDIO_PRODUCTION | 1 WILLIAM | AUDIO_PRODUCTION | 1 ELIJAH | AUDIO_PRODUCTION | 1 JAMES | AUDIO_PRODUCTION | 1 LEVI | AUDIO_PRODUCTION | 1 BENJAMIN | AUDIO_PRODUCTION | 1 LUCAS | AUDIO_PRODUCTION | 1 MATEO | AUDIO_PRODUCTION | 1 DAVID | AUDIO_PRODUCTION | 1 LOGAN | AUDIO_PRODUCTION | 1 ISAAC | AUDIO_PRODUCTION | 1 LEO | AUDIO_PRODUCTION | 1 MASON | AUDIO_PRODUCTION | 1 LINCOLN | AUDIO_PRODUCTION | 1 JAYDEN | AUDIO_PRODUCTION | 1 JAXON | AUDIO_PRODUCTION | 1 LIAM | COMPUTER_PROGRAMMING | 1 OLIVER | COMPUTER_PROGRAMMING | 1 ASHER | COMPUTER_PROGRAMMING | 1 ELIJAH | COMPUTER_PROGRAMMING | 1 CHRISTOPHER | COMPUTER_PROGRAMMING | 1 LUCAS | COMPUTER_PROGRAMMING | 1 DAVID | COMPUTER_PROGRAMMING | 1 JOSIAH | COMPUTER_PROGRAMMING | 1 DYLAN | COMPUTER_PROGRAMMING | 1 ANDREW | COMPUTER_PROGRAMMING | 1 THOMAS | COMPUTER_PROGRAMMING | 1 WILLIAM | COMPUTER_REPAIR | 1 LIAM | FILM_PRODUCTION | 1 JOSHUA | FILM_PRODUCTION | 1 NOAH | FILM_PRODUCTION | 1 OLIVER | FILM_PRODUCTION | 1 ASHER | FILM_PRODUCTION | 1 ELIJAH | FILM_PRODUCTION | 1 EZRA | FILM_PRODUCTION | 1 BENJAMIN | FILM_PRODUCTION | 1 LUCAS | FILM_PRODUCTION | 1 MATEO | FILM_PRODUCTION | 1 DAVID | FILM_PRODUCTION | 1 HUDSON | FILM_PRODUCTION | 1 JOSIAH | FILM_PRODUCTION | 1 DYLAN | FILM_PRODUCTION | 1 THOMAS | FILM_PRODUCTION | 1 LIAM | GRAPHIC_DESIGN | 1 LIAM | MEDIA_TECHNOLOGY | 1 NOAH | MEDIA_TECHNOLOGY | 1 DYLAN | MEDIA_TECHNOLOGY | 1 SEBASTIAN | MUSIC_PRODUCTION | 1 CHARLES | MUSIC_PRODUCTION | 1 JOSEPH | MUSIC_PRODUCTION | 1 LIAM | TYPING | 1 NOAH | TYPING | 1 ELIJAH | TYPING | 1 DYLAN | TYPING | 1 LIAM | VIDEO_GAME_DEVELOPMENT | 1 NOAH | VIDEO_GAME_DEVELOPMENT | 1 LIAM | WEB_DESIGN | 1 CALEB | WEB_DESIGN | 1 ISAIAH | WEB_DESIGN | 1 WILLIAM | WEB_DESIGN | 1 ELIJAH | WEB_DESIGN | 1 ETHAN | WEB_DESIGN | 1 JACOB | WEB_DESIGN | 1 LOGAN | WEB_DESIGN | 1 LIAM | WORD_PROCESSING | 1 ELIJAH | AMERICAN_LITERATURE | 1 LIAM | BRITISH_LITERATURE | 1 WILLIAM | BRITISH_LITERATURE | 1 ELIJAH | BRITISH_LITERATURE | 1 ETHAN | BRITISH_LITERATURE | 1 JACOB | BRITISH_LITERATURE | 1 JACK | BRITISH_LITERATURE | 1 SAMUEL | BRITISH_LITERATURE | 1 LIAM | CONTEMPORARY_LITERATURE | 1 ELIJAH | CONTEMPORARY_LITERATURE | 1 LEVI | CONTEMPORARY_LITERATURE | 1 ISAAC | CONTEMPORARY_LITERATURE | 1 LINCOLN | CONTEMPORARY_LITERATURE | 1 JAXON | CONTEMPORARY_LITERATURE | 1 LIAM | COMMUNICATION_SKILLS | 1 NOAH | COMMUNICATION_SKILLS | 1 OLIVER | COMMUNICATION_SKILLS | 1 ELIJAH | COMMUNICATION_SKILLS | 1 BENJAMIN | COMMUNICATION_SKILLS | 1 LUCAS | COMMUNICATION_SKILLS | 1 DAVID | COMMUNICATION_SKILLS | 1 JOHN | COMMUNICATION_SKILLS | 1 LUKE | COMMUNICATION_SKILLS | 1 ANDREW | COMMUNICATION_SKILLS | 1 MAVERICK | COMMUNICATION_SKILLS | 1 LIAM | DEBATE | 1 NOAH | DEBATE | 1 LIAM | ENGLISH_LANGUAGE_AND_COMPOSITION | 1 ELIJAH | ENGLISH_LANGUAGE_AND_COMPOSITION | 1 BENJAMIN | ENGLISH_LANGUAGE_AND_COMPOSITION | 1 MASON | ENGLISH_LANGUAGE_AND_COMPOSITION | 1 MATEO | HUMANITIES | 1 DAVID | HUMANITIES | 1 ISAAC | HUMANITIES | 1 LINCOLN | HUMANITIES | 1 LIAM | JOURNALISM | 1 COLTON | JOURNALISM | 1 ELIAS | JOURNALISM | 1 ELIJAH | JOURNALISM | 1 LEVI | JOURNALISM | 1 LIAM | LITERARY_ANALYSIS | 1 AARON | LITERARY_ANALYSIS | 1 ELIAS | LITERARY_ANALYSIS | 1 ELIJAH | LITERARY_ANALYSIS | 1 LEVI | LITERARY_ANALYSIS | 1 AARON | MODERN_LITERATURE | 1 ELIAS | MODERN_LITERATURE | 1 LEVI | MODERN_LITERATURE | 1 AARON | POETRY | 1 ELIAS | POETRY | 1 LEVI | POETRY | 1 ELIAS | POPULAR_LITERATURE | 1 LEVI | POPULAR_LITERATURE | 1 BENJAMIN | RHETORIC | 1 ISAAC | RHETORIC | 1 MASON | RHETORIC | 1 ELIJAH | TECHNICAL_WRITING | 1 ANTHONY | WORKS_OF_SHAKESPEARE | 1 ELIJAH | WORKS_OF_SHAKESPEARE | 1 LEVI | WORKS_OF_SHAKESPEARE | 1 LIAM | WORLD_LITERATURE | 1 ETHAN | WORLD_LITERATURE | 1 ALEXANDER | WORLD_LITERATURE | 1 HENRY | WORLD_LITERATURE | 1 JACOB | WORLD_LITERATURE | 1 LOGAN | WRITTEN_AND_ORAL_COMMUNICATION | 1 MASON | WRITTEN_AND_ORAL_COMMUNICATION | 1 ELI | WRITTEN_AND_ORAL_COMMUNICATION | 1 LIAM | CHEMISTRY_OF_FOODS | 1 ANTHONY | CHEMISTRY_OF_FOODS | 1 LANDON | CHEMISTRY_OF_FOODS | 1 JONATHAN | CHEMISTRY_OF_FOODS | 1 NOLAN | CHEMISTRY_OF_FOODS | 1 NOAH | CHEMISTRY_OF_FOODS | 1 HUNTER | CHEMISTRY_OF_FOODS | 1 OLIVER | CHEMISTRY_OF_FOODS | 1 WILLIAM | CHEMISTRY_OF_FOODS | 1 ELIJAH | CHEMISTRY_OF_FOODS | 1 CAMERON | CHEMISTRY_OF_FOODS | 1 BENJAMIN | CHEMISTRY_OF_FOODS | 1 LUCAS | CHEMISTRY_OF_FOODS | 1 LOGAN | CHEMISTRY_OF_FOODS | 1 MASON | CHEMISTRY_OF_FOODS | 1 DYLAN | CHEMISTRY_OF_FOODS | 1 DYLAN | CPR_TRAINING | 1 LIAM | CULINARY_ARTS | 1 ELIJAH | CULINARY_ARTS | 1 GABRIEL | CULINARY_ARTS | 1 LIAM | EARLY_CHILDHOOD_DEVELOPMENT | 1 SANTIAGO | EARLY_CHILDHOOD_DEVELOPMENT | 1 JEREMIAH | EARLY_CHILDHOOD_DEVELOPMENT | 1 JOSHUA | EARLY_CHILDHOOD_DEVELOPMENT | 1 NOAH | EARLY_CHILDHOOD_DEVELOPMENT | 1 ASHER | EARLY_CHILDHOOD_DEVELOPMENT | 1 ELIJAH | EARLY_CHILDHOOD_DEVELOPMENT | 1 THEODORE | EARLY_CHILDHOOD_DEVELOPMENT | 1 EZRA | EARLY_CHILDHOOD_DEVELOPMENT | 1 LEVI | EARLY_CHILDHOOD_DEVELOPMENT | 1 RYAN | EARLY_CHILDHOOD_DEVELOPMENT | 1 EZEKIEL | EARLY_CHILDHOOD_DEVELOPMENT | 1 ANGEL | EARLY_CHILDHOOD_DEVELOPMENT | 1 JOSIAH | EARLY_CHILDHOOD_DEVELOPMENT | 1 ROMAN | EARLY_CHILDHOOD_DEVELOPMENT | 1 EASTON | EARLY_CHILDHOOD_DEVELOPMENT | 1 LOGAN | EARLY_CHILDHOOD_DEVELOPMENT | 1 MILES | EARLY_CHILDHOOD_DEVELOPMENT | 1 ROBERT | EARLY_CHILDHOOD_DEVELOPMENT | 1 JAMESON | EARLY_CHILDHOOD_DEVELOPMENT | 1 NICHOLAS | EARLY_CHILDHOOD_DEVELOPMENT | 1 GREYSON | EARLY_CHILDHOOD_DEVELOPMENT | 1 COOPER | EARLY_CHILDHOOD_DEVELOPMENT | 1 IAN | EARLY_CHILDHOOD_DEVELOPMENT | 1 MASON | EARLY_CHILDHOOD_DEVELOPMENT | 1 CARSON | EARLY_CHILDHOOD_DEVELOPMENT | 1 AXEL | EARLY_CHILDHOOD_DEVELOPMENT | 1 JAXSON | EARLY_CHILDHOOD_DEVELOPMENT | 1 DOMINIC | EARLY_CHILDHOOD_DEVELOPMENT | 1 LEONARDO | EARLY_CHILDHOOD_DEVELOPMENT | 1 LUCA | EARLY_CHILDHOOD_DEVELOPMENT | 1 AUSTIN | EARLY_CHILDHOOD_DEVELOPMENT | 1 JORDAN | EARLY_CHILDHOOD_DEVELOPMENT | 1 ADAM | EARLY_CHILDHOOD_DEVELOPMENT | 1 XAVIER | EARLY_CHILDHOOD_DEVELOPMENT | 1 JOSE | EARLY_CHILDHOOD_DEVELOPMENT | 1 LIAM | EARLY_CHILDHOOD_EDUCATION | 1 ANTHONY | EARLY_CHILDHOOD_EDUCATION | 1 NOAH | EARLY_CHILDHOOD_EDUCATION | 1 BENJAMIN | EARLY_CHILDHOOD_EDUCATION | 1 MATEO | EARLY_CHILDHOOD_EDUCATION | 1 LOGAN | EARLY_CHILDHOOD_EDUCATION | 1 ISAAC | EARLY_CHILDHOOD_EDUCATION | 1 MASON | EARLY_CHILDHOOD_EDUCATION | 1 JAXON | EARLY_CHILDHOOD_EDUCATION | 1 LIAM | FAMILY_STUDIES | 1 ELIJAH | FAMILY_STUDIES | 1 RYAN | FAMILY_STUDIES | 1 DYLAN | FAMILY_STUDIES | 1 DYLAN | FASHION_AND_RETAIL_MERCHANDISING | 1 LIAM | FASHION_CONSTRUCTION | 1 SANTIAGO | FASHION_CONSTRUCTION | 1 JEREMIAH | FASHION_CONSTRUCTION | 1 ASHER | FASHION_CONSTRUCTION | 1 ELIJAH | FASHION_CONSTRUCTION | 1 JOSIAH | FASHION_CONSTRUCTION | 1 ROBERT | FASHION_CONSTRUCTION | 1 JAMESON | FASHION_CONSTRUCTION | 1 GREYSON | FASHION_CONSTRUCTION | 1 DYLAN | FASHION_CONSTRUCTION | 1 LIAM | HOME_ECONOMICS | 1 NOAH | HOME_ECONOMICS | 1 JACE | HOME_ECONOMICS | 1 WILLIAM | HOME_ECONOMICS | 1 ELIJAH | HOME_ECONOMICS | 1 CONNOR | HOME_ECONOMICS | 1 LEVI | HOME_ECONOMICS | 1 BENJAMIN | HOME_ECONOMICS | 1 EVERETT | HOME_ECONOMICS | 1 MATEO | HOME_ECONOMICS | 1 DECLAN | HOME_ECONOMICS | 1 LOGAN | HOME_ECONOMICS | 1 ISAAC | HOME_ECONOMICS | 1 GRAYSON | HOME_ECONOMICS | 1 EVAN | HOME_ECONOMICS | 1 MASON | HOME_ECONOMICS | 1 JAXON | HOME_ECONOMICS | 1 LIAM | INTERIOR_DESIGN | 1 KAYDEN | INTERIOR_DESIGN | 1 PARKER | INTERIOR_DESIGN | 1 WESLEY | INTERIOR_DESIGN | 1 KAI | INTERIOR_DESIGN | 1 BRAYDEN | INTERIOR_DESIGN | 1 BRYSON | INTERIOR_DESIGN | 1 WESTON | INTERIOR_DESIGN | 1 NOAH | INTERIOR_DESIGN | 1 ELIJAH | INTERIOR_DESIGN | 1 BENJAMIN | INTERIOR_DESIGN | 1 JOHN | INTERIOR_DESIGN | 1 CARTER | INTERIOR_DESIGN | 1 LOGAN | INTERIOR_DESIGN | 1 JULIAN | INTERIOR_DESIGN | 1 ISAAC | INTERIOR_DESIGN | 1 MASON | INTERIOR_DESIGN | 1 JASON | INTERIOR_DESIGN | 1 ELI | INTERIOR_DESIGN | 1 EMMETT | INTERIOR_DESIGN | 1 SAWYER | INTERIOR_DESIGN | 1 SILAS | INTERIOR_DESIGN | 1 LOGAN | NUTRITION | 1 BROOKS | NUTRITION | 1 MICAH | NUTRITION | 1 DAMIAN | NUTRITION | 1 MASON | NUTRITION | 1 HARRISON | NUTRITION | 1 ELI | NUTRITION | 1 WAYLON | NUTRITION | 1 AIDEN | NUTRITION | 1 AYDEN | NUTRITION | 1 VINCENT | NUTRITION | 1 LIAM | AMERICAN_SIGN_LANGUAGE | 1 NOAH | AMERICAN_SIGN_LANGUAGE | 1 ELIJAH | AMERICAN_SIGN_LANGUAGE | 1 BENJAMIN | AMERICAN_SIGN_LANGUAGE | 1 RYDER | AMERICAN_SIGN_LANGUAGE | 1 WYATT | AMERICAN_SIGN_LANGUAGE | 1 MASON | AMERICAN_SIGN_LANGUAGE | 1 LIAM | ANCIENT_GREEK | 1 NOAH | ANCIENT_GREEK | 1 ELIJAH | ANCIENT_GREEK | 1 ETHAN | ANCIENT_GREEK | 1 LIAM | ARABIC | 1 NOAH | ARABIC | 1 LOGAN | ARABIC | 1 JACKSON | ARABIC | 1 OWEN | ARABIC | 1 KINGSTON | ARABIC | 1 CHARLES | ARABIC | 1 JOSEPH | ARABIC | 1 LIAM | FRENCH | 1 AIDEN | FRENCH | 1 MATTHEW | FRENCH | 1 LIAM | GERMAN | 1 ELIJAH | GERMAN | 1 MATEO | GERMAN | 1 GRAYSON | GERMAN | 1 JAXON | GERMAN | 1 ELIJAH | HEBREW | 1 DYLAN | HEBREW | 1 JAXON | HEBREW | 1 LIAM | JAPANESE | 1 LIAM | KOREAN | 1 ANTHONY | KOREAN | 1 NOAH | KOREAN | 1 OLIVER | KOREAN | 1 ELIJAH | KOREAN | 1 THEODORE | KOREAN | 1 EZRA | KOREAN | 1 LEVI | KOREAN | 1 RYAN | KOREAN | 1 BENJAMIN | KOREAN | 1 LUCAS | KOREAN | 1 DAVID | KOREAN | 1 JOHN | KOREAN | 1 CARTER | KOREAN | 1 LOGAN | KOREAN | 1 JULIAN | KOREAN | 1 JACKSON | KOREAN | 1 LUKE | KOREAN | 1 DAMIAN | KOREAN | 1 ISAAC | KOREAN | 1 GRAYSON | KOREAN | 1 GAVIN | KOREAN | 1 MASON | KOREAN | 1 JASON | KOREAN | 1 HARRISON | KOREAN | 1 EMMETT | KOREAN | 1 JORDAN | KOREAN | 1 JAXON | KOREAN | 1 JOSEPH | KOREAN | 1 ADAM | KOREAN | 1 XAVIER | KOREAN | 1 ELIJAH | LATIN | 1 MATEO | LATIN | 1 JAXON | LATIN | 1 LIAM | PORTUGUESE | 1 LANDON | PORTUGUESE | 1 JONATHAN | PORTUGUESE | 1 NOAH | PORTUGUESE | 1 HUNTER | PORTUGUESE | 1 OLIVER | PORTUGUESE | 1 JACE | PORTUGUESE | 1 WILLIAM | PORTUGUESE | 1 ELIJAH | PORTUGUESE | 1 CAMERON | PORTUGUESE | 1 JAMES | PORTUGUESE | 1 CONNOR | PORTUGUESE | 1 BENJAMIN | PORTUGUESE | 1 LUCAS | PORTUGUESE | 1 EVERETT | PORTUGUESE | 1 MATEO | PORTUGUESE | 1 DAVID | PORTUGUESE | 1 WYATT | PORTUGUESE | 1 LOGAN | PORTUGUESE | 1 ISAAC | PORTUGUESE | 1 GRAYSON | PORTUGUESE | 1 MASON | PORTUGUESE | 1 DYLAN | PORTUGUESE | 1 LINCOLN | PORTUGUESE | 1 JAXON | PORTUGUESE | 1 RYAN | RUSSIAN | 1 RYDER | RUSSIAN | 1 DYLAN | RUSSIAN | 1 EMMETT | SPANISH | 1 NICHOLAS | ALGEBRA_1 | 1 LEONARDO | ALGEBRA_1 | 1 SANTIAGO | ALGEBRA_2 | 1 JEREMIAH | ALGEBRA_2 | 1 TYLER | ALGEBRA_2 | 1 NOAH | ALGEBRA_2 | 1 ASHER | ALGEBRA_2 | 1 THEODORE | ALGEBRA_2 | 1 EZRA | ALGEBRA_2 | 1 LEVI | ALGEBRA_2 | 1 RYAN | ALGEBRA_2 | 1 BENJAMIN | ALGEBRA_2 | 1 EZEKIEL | ALGEBRA_2 | 1 ANGEL | ALGEBRA_2 | 1 JOSIAH | ALGEBRA_2 | 1 ROMAN | ALGEBRA_2 | 1 EASTON | ALGEBRA_2 | 1 LOGAN | ALGEBRA_2 | 1 MILES | ALGEBRA_2 | 1 ROBERT | ALGEBRA_2 | 1 JAMESON | ALGEBRA_2 | 1 NICHOLAS | ALGEBRA_2 | 1 GREYSON | ALGEBRA_2 | 1 ISAAC | ALGEBRA_2 | 1 COOPER | ALGEBRA_2 | 1 GRAYSON | ALGEBRA_2 | 1 IAN | ALGEBRA_2 | 1 MASON | ALGEBRA_2 | 1 CARSON | ALGEBRA_2 | 1 AXEL | ALGEBRA_2 | 1 JAXSON | ALGEBRA_2 | 1 DOMINIC | ALGEBRA_2 | 1 ISAAC | CONSUMER_EDUCATION | 1 JAYDEN | ENTREPRENEURIAL_SKILLS | 1 THEODORE | MARKETING | 1 GABRIEL | ANIMATION | 1 RYAN | WEB_PROGRAMMING | 1 GABRIEL | ENGLISH_LITERATURE_AND_COMPOSITION | 1 CONNOR | CPR_TRAINING | 1 BENNETT | NUTRITION | 1 TYLER | ALGEBRA_1 | 1 NATHAN | CREATIVE_WRITING | 2 ADRIAN | CREATIVE_WRITING | 2 CHRISTIAN | CREATIVE_WRITING | 2 ROWAN | CHINESE | 3 GEORGE | CHINESE | 3 LUIS | CHINESE | 3 CHASE | CHINESE | 3 COLE | CHINESE | 3 NATHANIEL | CHINESE | 3 ZACHARY | CHINESE | 3 ASHTON | CHINESE | 3 BRAXTON | ITALIAN | 4
db<>fiddle here