简体   繁体   中英

SQL Server Finding Class Prerequisites Loop

Hello people of Stack Overflow,

I am stuck on the last question of my SQL assignment, and am in need of direction.

create table PREQUISITE (  
    Cno     varchar(9) REFERENCES COURSE(Cno), 
    Cpre    varchar(9) REFERENCES COURSE(Cno),
    primary key(Cno, Cpre)
);

I have this table, with these values:

('MATH 1910', 'MATH 1730'),
('CSCI 1170', 'MATH 1730'),
('CSCI 2170', 'CSCI 1170'),
('CSCI 3080', 'CSCI 1170'),
('CSCI 3080', 'MATH 1910'),
('CSCI 3110', 'CSCI 2170'),
('CSCI 3110', 'CSCI 3080'),
('CSCI 3130', 'CSCI 2170'),
('CSCI 3210', 'CSCI 3110'),
('CSCI 3210', 'COMM 2200'),
('CSCI 3240', 'CSCI 2170'),
('CSCI 3240', 'CSCI 3130'),
('CSCI 4610', 'CSCI 3110'),
('CSCI 4610', 'CSCI 3130'),
('CSCI 4700', 'CSCI 3110'),
('CSCI 4700', 'COMM 2200');

I am trying to write a function with a single parameter, for instance CSCI 4700 that returns a string containing all of the class's prerequisites, as well as those class's prerequisites and so on. I have tried to use a scroll cursor to loop through the table and reset back to the top of the table as well as a while exists loop, but am unsure of which path to follow to generate this output:

CSCI 4700 -- CSCI 3110, COMM 2200 
CSCI 3110 --  CSCI 3080, 2170 
COMM 2200 -- no perquisite 
CSCI 3080 -- CSCI 1170, MATH 1910 
CSCI 2170 -- CSCI 1170 CSCI 1170 -- MATH 1730 
MATH 1910 -- MATH 1730  
MATH 1730 -- no prequisite

Not looking for answers in code here, just suggestions on what SQL operations could achieve this

The following query gives tree-like structure. If you have circular references, the query will hang. For example this code does not handle the ALGEBRA -> MATH -> ALGEBRA case.

 with src as ( select 1 as id, 3 as req_id union all select 2 as id, 5 as req_id union all select 3 as id, 4 as req_id union all select 4 as id, null as req_id union all select 4 as id, 2 as req_id union all select 5 as id, 6 as req_id union all select 6 as id, null as req_id ), q0 as ( select * from src where id = 1 ), q1(src, req, lvl) as ( select id, req_id, 0 from q0 union all select id, req_id, lvl + 1 from src inner join q1 on req = id ) select * from q1 GO
 src | req | lvl --: | ---: |  --: 1 |  3 |  0 3 |  4 |  1 4 |  null | 2 4 |  2 |  2 2 |  5 |  3 5 |  6 |  4 6 |  null | 5 

db<>fiddle here

Here's a recursive CTE with some string aggregation that might give you an idea for your function.

DECLARE @Cno VARCHAR(9);
DECLARE @CpreList VARCHAR(4000);
SET @Cno = 'CSCI 4700';

WITH RCTE AS
(
    SELECT Cno AS BaseCno, 0 AS Lvl, Cno, Cpre
    FROM PREQUISITE
    WHERE Cno = @Cno

    UNION ALL

    SELECT c.BaseCno, Lvl+1, t.Cno, t.Cpre
    FROM RCTE c
    JOIN PREQUISITE t ON t.Cno = c.Cpre
    WHERE t.Cno != c.BaseCno
)
SELECT @CpreList = STRING_AGG(Cpre, ', ') WITHIN GROUP (ORDER BY Cpre)
FROM (SELECT DISTINCT BaseCno AS Cno, Cpre FROM RCTE) q
GROUP BY Cno;

SELECT @CpreList AS CpreList;

Returns:

CpreList
COMM 2200, CSCI 1170, CSCI 2170, CSCI 3080, CSCI 3110, MATH 1730, MATH 1910

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM