[关闭]
@SovietPower 2022-03-18T15:06:26.000000Z 字数 23005 阅读 1973

数据库系统 实验2 SQL练习

ECNU



创建数据表并导入数据

运行实验1创建的mygauss容器,创建一个新文件夹:

  1. PS H:\> docker start opengauss
  2. PS H:\> docker exec -it opengauss bash
  3. root@97375c3acbd1:/# su omm
  4. omm@97375c3acbd1:/$ cd /home/omm
  5. omm@97375c3acbd1:~$ mkdir db2022
  6. omm@97375c3acbd1:~$ cd db2022
  7. omm@97375c3acbd1:~/db2022$

在一个新powershell窗口中,将下载的SQL脚本文件复制到容器中的相应目录:

  1. PS H:\> docker cp DDL+drop.sql opengauss:/home/omm/db2022/
  2. PS H:\> docker cp largeRelationsInsertFile.sql opengauss:/home/omm/db2022/
  3. omm@97375c3acbd1:~/db2022$ ls -l
  4. total 2248
  5. -rwxr-xr-x 1 root root 3693 Mar 15 01:53 DDL+drop.sql
  6. -rwxr-xr-x 1 root root 2296465 Mar 15 01:53 largeRelationsInsertFile.sql

使用客户端工具gsql通过脚本文件DDL+drop.sql, largeRelationsInsertFile.sql向数据表中插入数据:

  1. omm@97375c3acbd1:~/db2022$ gsql -d db2022 -f DDL+drop.sql
  2. DROP TABLE
  3. DROP TABLE
  4. DROP TABLE
  5. DROP TABLE
  6. DROP TABLE
  7. DROP TABLE
  8. DROP TABLE
  9. DROP TABLE
  10. DROP TABLE
  11. DROP TABLE
  12. DROP TABLE
  13. gsql:DDL+drop.sql:21: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "classroom_pkey" for table "classroom"
  14. CREATE TABLE
  15. ...
  16. gsql:DDL+drop.sql:130: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "prereq_pkey" for table "prereq"
  17. CREATE TABLE
  18. total time: 8857 ms
  19. omm@97375c3acbd1:~/db2022$ gsql -d db2022 -U gxb -W 'Gxb12345' -f largeRelationsInsertFile.sql
  20. ...
  21. INSERT 0 1
  22. INSERT 0 1
  23. INSERT 0 1
  24. INSERT 0 1
  25. total time: 3509318 ms

连接数据库,然后检查一下记录的数量:

  1. omm@97375c3acbd1:~/db2022$ gsql -d db2022 -U gxb -W 'Gxb12345' -r
  2. gsql ((openGauss 2.1.0 build 590b0f8e) compiled at 2021-09-30 14:29:04 commit 0 last mr )
  3. Non-SSL connection (SSL connection is recommended when requiring high-security)
  4. Type "help" for help.
  5. db2022=# select count(*) from advisor;
  6. count
  7. -------
  8. 2000
  9. (1 row)
  10. db2022=# select count(*) from classroom;
  11. count
  12. -------
  13. 30
  14. (1 row)
  15. ...
  16. db2022=# select count(*) from time_slot;
  17. count
  18. -------
  19. 20
  20. (1 row)

SQL练习 13-19

gsql -d [db] -c 'select * from table;' -o output.csv 可用客户端工具gsql执行单条SQL语句,并将查询结果保存到文件output.csv中。

  1. omm@97375c3acbd1:~/db2022$ gsql -d db2022 -c 'select * from department;' -o department.csv
  2. omm@97375c3acbd1:~/db2022$ ls -l
  3. total 2252
  4. -rwxr-xr-x 1 root root 3693 Mar 15 01:53 DDL+drop.sql
  5. -rw-rw-r-- 1 omm omm 871 Mar 15 03:25 department.csv
  6. -rwxr-xr-x 1 root root 2296465 Mar 15 01:53 largeRelationsInsertFile.sql
  7. omm@97375c3acbd1:~/db2022$ cat department.csv
  8. dept_name | building | budget
  9. -------------+-------------+-----------
  10. Civil Eng. | Chandler | 255041.46
  11. Biology | Candlestick | 647610.55
  12. History | Taylor | 699140.86
  13. Physics | Wrigley | 942162.76
  14. Marketing | Lambeau | 210627.58
  15. Pol. Sci. | Whitman | 573745.09
  16. English | Palmer | 611042.66
  17. Accounting | Saucon | 441840.92
  18. Comp. Sci. | Lamberton | 106378.69
  19. Languages | Linderman | 601283.60
  20. Finance | Candlestick | 866831.75
  21. Geology | Palmer | 406557.93
  22. Cybernetics | Mercer | 794541.46
  23. Astronomy | Taylor | 617253.94
  24. Athletics | Bronfman | 734550.70
  25. Statistics | Taylor | 395051.74
  26. Psychology | Thompson | 848175.04
  27. Math | Brodhead | 777605.11
  28. Elec. Eng. | Main | 276527.61
  29. Mech. Eng. | Rauch | 520350.65
  30. (20 rows)

13. Find the names of all the instructors from Biology department.

  1. db2022=# select name
  2. db2022-# from instructor
  3. db2022-# where dept_name='Biology';
  4. name
  5. ----------
  6. Queiroz
  7. Valtchev
  8. (2 rows)

14. Find the names of courses in Computer science department which have 3 credits.

  1. db2022=# select title
  2. db2022-# from course
  3. db2022-# where dept_name='Comp. Sci.' and credits=3;
  4. title
  5. -----------------------
  6. International Finance
  7. Japanese
  8. Computability Theory
  9. (3 rows)

15. For the student with ID 13403 (or any other value), show all course_id and title of all courses taken by the student.

  1. db2022=# select course_id, title
  2. db2022-# from takes natural join course
  3. db2022-# where id=13403;
  4. course_id | title
  5. -----------+-------------------------------
  6. 486 | Accounting
  7. 349 | Networking
  8. 696 | Heat Transfer
  9. 319 | World History
  10. 400 | Visual BASIC
  11. 258 | Colloid and Surface Chemistry
  12. 443 | Journalism
  13. 158 | Elastic Structures
  14. 192 | Drama
  15. 489 | Journalism
  16. 795 | Death and Taxes
  17. 493 | Music of the 50s
  18. 352 | Compiler Design
  19. 338 | Graph Theory
  20. 366 | Computational Biology
  21. 400 | Visual BASIC
  22. 748 | Tort Law
  23. (17 rows)

16. As above, but show the total number of credits for such courses (taken by that student). Don’t display the tot_creds value from the student table, you should use SQL aggregation on courses taken by the student.

  1. db2022=# select sum(credits)
  2. db2022-# from takes natural join course
  3. db2022-# where id=13403;
  4. sum
  5. -----
  6. 61
  7. (1 row)
  8. db2022=# select tot_cred
  9. db2022-# from student
  10. db2022-# where id=13403;
  11. tot_cred
  12. ----------
  13. 82
  14. (1 row)

17. Display the total credits for each of the students, along with the ID of the student; don’t bother about the name of the student. (Don’t bother about students who have not registered for any course, they can be omitted).

  1. db2022=# select id, sum(credits)
  2. db2022-# from takes natural join course
  3. db2022-# group by id;
  4. id | sum
  5. -------+-----
  6. 3039 | 40
  7. 86327 | 44
  8. 22050 | 39
  9. 89551 | 71
  10. 12326 | 36
  11. 19321 | 48
  12. 68516 | 62
  13. 7035 | 56
  14. 81396 | 67
  15. ...

18. Find the names of all students who have taken any Comp. Sci. course ever (there should be no duplicate names).

  1. db2022=# select distinct name
  2. from student natural join takes join course using (course_id)
  3. where course.dept_name='Comp. Sci.';
  4. name
  5. -------------------
  6. Mowbray
  7. Mendelzon
  8. Umehara
  9. Kamae
  10. Srivastava
  11. ...

19. Display the IDs of all instructors who have never taught a couse (interpret “taught” as “taught or is scheduled to teach”).

  1. db2022=# (select id
  2. db2022(# from instructor)
  3. db2022-# except
  4. db2022-# (select id
  5. db2022(# from instructor natural join teaches);
  6. id
  7. -------
  8. 37687
  9. 35579
  10. 74426
  11. 78699
  12. 64871
  13. 50885
  14. 59795
  15. 97302
  16. 57180
  17. 79653
  18. 52647
  19. 31955
  20. 96896
  21. 58558
  22. 63395
  23. 72553
  24. 16807
  25. 95030
  26. 40341
  27. (19 rows)

SQL练习 20-29

20. As above, but display the names of the instructors also, not just the IDs.

  1. db2022=# select id, name
  2. db2022-# from instructor
  3. db2022-# where id not in (select id
  4. db2022(# from instructor natural join teaches);
  5. id | name
  6. -------+-------------------
  7. 63395 | McKinnon
  8. 78699 | Pingr
  9. 96896 | Mird
  10. 40341 | Murata
  11. 50885 | Konstantinides
  12. 79653 | Levine
  13. 97302 | Bertolino
  14. 57180 | Hau
  15. 35579 | Soisalon-Soininen
  16. 31955 | Moreira
  17. 37687 | Arias
  18. 16807 | Yazdi
  19. 95030 | Arinb
  20. 74426 | Kenje
  21. 58558 | Dusserre
  22. 59795 | Desyl
  23. 52647 | Bancilhon
  24. 72553 | Yin
  25. 64871 | Gutierrez
  26. (19 rows)

21. You need to create a movie database. Create three tables, one for actors(AID, name), one for movies(MID, title) and one for actor_role(MID, AID, rolename). Use appropriate data types for each of the attributes, and add appropriate primary/foreign key constraints.

  1. db2022=# create table actors
  2. db2022-# (AID varchar(20),
  3. db2022(# name varchar(50) not null,
  4. db2022(# primary key (AID));
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "actors_pkey" for table "actors"
  6. CREATE TABLE
  7. db2022=# create table movies
  8. db2022-# (MID varchar(20),
  9. db2022(# title varchar(50),
  10. db2022(# primary key (MID));
  11. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "movies_pkey" for table "movies"
  12. CREATE TABLE
  13. db2022=# create table actor_role
  14. db2022-# (MID varchar(20),
  15. db2022(# AID varchar(20),
  16. db2022(# rolename varchar(20) not null,
  17. db2022(# primary key (MID, AID, rolename),
  18. db2022(# foreign key (MID) references movies,
  19. db2022(# foreign key (AID) references actors);
  20. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "actor_role_pkey" for table "actor_role"
  21. CREATE TABLE

22. Insert data to the above tables (approx 3 to 6 rows in each table), including data for actor “Charlie Chaplin”, and for yourself (using your student number as ID).

  1. db2022=# insert into actors values
  2. db2022-# ('10205', 'GXB'),
  3. db2022-# ('10000', 'Charlie Chaplin'),
  4. db2022-# ('10001', 'Paulette Goddard'),
  5. db2022-# ('10002', 'Emma Watson');
  6. INSERT 0 4
  7. db2022=# insert into movies values
  8. db2022-# ('10000', 'City Lights'),
  9. db2022-# ('10001', 'Modern Times'),
  10. db2022-# ('10002', 'The Gold Rush'),
  11. db2022-# ('10003', 'Harry Potter');
  12. INSERT 0 4
  13. db2022=# insert into actor_role values
  14. ('10000', '10000', 'A Tramp'),
  15. ('10000', '10000', 'Director'),
  16. ('10001', '10000', 'Charles'),
  17. ('10001', '10001', 'An Orphan'),
  18. ('10002', '10000', 'Charles'),
  19. ('10003', '10002', 'Hermione Granger');
  20. INSERT 0 6

23. Write a query to list all movies in which actor “Charlie Chaplin” has acted, along with the number of roles he had in that movie.

  1. db2022=# select MID, title, cnt
  2. db2022-# from movies natural join (select MID, count(*) as cnt
  3. db2022(# from actor_role
  4. db2022(# where AID='10000'
  5. db2022(# group by MID);
  6. mid | title | cnt
  7. -------+---------------+-----
  8. 10000 | City Lights | 2
  9. 10001 | Modern Times | 1
  10. 10002 | The Gold Rush | 1
  11. (3 rows)

24. Write a query to list the names of actors who have not acted in any movie.

  1. db2022=# select AID, name
  2. db2022-# from actors
  3. db2022-# where AID not in (select AID from actor_role);
  4. aid | name
  5. -------+------
  6. 10205 | GXB
  7. (1 row)

25. List names of actors, along with titles of movies they have acted in. If they have not acted in any movie, show the movie title as null. (Do not use SQL outerjoin syntax here, write it from scratch.)

  1. with temp(AID, name, title) as
  2. (select AID, name, title
  3. from actors natural join actor_role natural join movies)
  4. (select name, 'null' as title from actors
  5. where AID not in (select AID from temp))
  6. union
  7. (select name, title from temp);
  1. db2022=# with temp(AID, name, title) as
  2. db2022-# (select AID, name, title
  3. db2022(# from actors natural join actor_role natural join movies)
  4. db2022-# (select name, 'null' as title from actors
  5. db2022(# where AID not in (select AID from temp))
  6. db2022-# union
  7. db2022-# (select name, title from temp);
  8. name | title
  9. ------------------+---------------
  10. Charlie Chaplin | The Gold Rush
  11. GXB | null
  12. Emma Watson | Harry Potter
  13. Charlie Chaplin | City Lights
  14. Charlie Chaplin | Modern Times
  15. Paulette Goddard | Modern Times
  16. (6 rows)

26. Find the maximum and minimum enrollment across all sections, considering only sections that had some enrollment, don’t worry about those that had no students taking that section.
一个学生在一个section内上了两节课,是算2还是算1?感觉两种都有意义?按2计算了。

  1. db2022=# select min(cnt), max(cnt)
  2. db2022-# from (select count(*) as cnt
  3. db2022(# from takes
  4. db2022(# group by sec_id);
  5. min | max
  6. -----+-------
  7. 322 | 25512
  8. (1 row)
  9. db2022=# select min(cnt), max(cnt)
  10. db2022-# from (select count(*) as cnt
  11. db2022(# from (select distinct ID, sec_id from takes)
  12. db2022(# group by sec_id);
  13. min | max
  14. -----+------
  15. 322 | 2000
  16. (1 row)

27. Find all sections that had the maximum enrollment (along with the enrollment).

  1. with max_enroll as
  2. (select max(cnt) as mx
  3. from (select sec_id, count(*) as cnt
  4. from takes
  5. group by sec_id))
  6. select sec_id, count(*) as cnt
  7. from takes
  8. group by sec_id
  9. having cnt in (select mx from max_enroll);
  1. db2022=# with max_enroll as
  2. db2022-# (select max(cnt) as mx
  3. db2022(# from (select sec_id, count(*) as cnt
  4. db2022(# from takes
  5. db2022(# group by sec_id))
  6. db2022-# select sec_id, count(*) as cnt
  7. db2022-# from takes
  8. db2022-# group by sec_id
  9. db2022-# having cnt in (select mx from max_enroll);
  10. sec_id | cnt
  11. --------+-------
  12. 1 | 25512
  13. (1 row)

28. As in step 26, but now also include sections with no students taking them; the enrollment for such sections should be treated as 0. Do this in two different ways.
a. Using a scalar subquery;

  1. select min(cnt), max(cnt)
  2. from (
  3. select distinct sec_id,
  4. (select count(*)
  5. from takes
  6. where section.sec_id=takes.sec_id)
  7. as cnt
  8. from section);

b. Using aggregation on a left outer join (use the SQL natural left outer join syntax);

  1. select min(cnt), max(cnt)
  2. from (select count(grade) as cnt
  3. from section natural left outer join takes
  4. group by sec_id);
  1. db2022=# select min(cnt), max(cnt)
  2. db2022-# from (
  3. db2022(# select distinct sec_id,
  4. db2022(# (select count(*)
  5. db2022(# from takes
  6. db2022(# where section.sec_id=takes.sec_id)
  7. db2022(# as cnt
  8. db2022(# from section);
  9. min | max
  10. -----+-------
  11. 0 | 25512
  12. (1 row)
  13. db2022=# select min(cnt), max(cnt)
  14. db2022-# from (select count(grade) as cnt
  15. db2022(# from section natural left outer join takes
  16. db2022(# group by sec_id);
  17. min | max
  18. -----+-------
  19. 0 | 25512
  20. (1 row)

29. Find all courses whose title starts with the string “Comp”.

  1. db2022=# select course_id, title
  2. db2022-# from course
  3. db2022-# where title like 'Comp%';
  4. course_id | title
  5. -----------+----------------------------
  6. 814 | Compiler Design
  7. 328 | Composition and Literature
  8. 366 | Computational Biology
  9. 781 | Compiler Design
  10. 805 | Composition and Literature
  11. 919 | Computability Theory
  12. 877 | Composition and Literature
  13. 352 | Compiler Design
  14. 584 | Computability Theory
  15. 348 | Compiler Design
  16. (10 rows)

SQL练习 30-39

30. Find instructors who have taught all courses in Comp. Sci. department.
a. Using the “not exists … except …” structure;
注意要用instructor.IDID, t.ID都指t.ID

  1. select ID, name
  2. from instructor as I
  3. where not exists (
  4. (select course_id from course where dept_name='Comp. Sci.')
  5. except
  6. (select course_id from teaches as t where I.ID=t.ID));

b. Using matching of counts (don’t forget the distinct clause!).
如果用with cnt代替select count(*) from course where dept_name='Comp. Sci.',则不能直接写cnt=...,还是要写(select tot from cnt)=...

  1. select ID, name
  2. from instructor as I
  3. where (select count(*) from course where dept_name='Comp. Sci.')=(select count(distinct course_id) from teaches as t where I.ID=t.ID);
  1. db2022=# select ID, name
  2. db2022-# from instructor as I
  3. db2022-# where not exists (
  4. db2022(# (select course_id from course where dept_name='Comp. Sci.')
  5. db2022(# except
  6. db2022(# (select course_id from teaches as t where I.ID=t.ID));
  7. id | name
  8. -------+-------
  9. 34175 | Bondi
  10. (1 row)
  11. db2022=# select * from teaches where ID=34175;
  12. id | course_id | sec_id | semester | year
  13. -------+-----------+--------+----------+------
  14. 34175 | 747 | 1 | Spring | 2004
  15. 34175 | 274 | 1 | Fall | 2002
  16. 34175 | 571 | 1 | Spring | 2004
  17. 34175 | 539 | 1 | Spring | 2022
  18. 34175 | 949 | 1 | Spring | 2022
  19. 34175 | 647 | 1 | Spring | 2022
  20. 34175 | 584 | 1 | Spring | 2022
  21. 34175 | 276 | 1 | Spring | 2022
  22. 34175 | 359 | 1 | Spring | 2022
  23. 34175 | 284 | 1 | Spring | 2022
  24. (10 rows)
  25. db2022=# select ID, name
  26. db2022-# from instructor as I
  27. db2022-# where (select count(*) from course where dept_name='Comp. Sci.')=(select count(distinct course_id) from teaches as t where I.ID=t.ID);
  28. id | name
  29. -------+-------
  30. 34175 | Bondi
  31. (1 row)

31. Insert each instructor as a student, with tot_creds = 0, in the same department.

  1. db2022=# insert into student
  2. db2022-# select ID, name, dept_name, 0
  3. db2022-# from instructor;
  4. INSERT 0 50
  5. db2022=# select count(*) from instructor;
  6. count
  7. -------
  8. 50
  9. (1 row)

32. Now delete all the newly added “students” above (note: already existing students who happened to have tot_creds = 0 should not get deleted).

  1. db2022=# delete from student
  2. db2022-# where (ID, name) in (select ID, name from instructor);
  3. DELETE 50

33. Some of you may have noticed that the tot_creds value for students did not match the credits from courses they have taken. Write and execute query to update tot_creds based on the credits passed, to bring the database back to consistency.

  1. update student
  2. set tot_cred=(
  3. select sum(credits)
  4. from takes natural join course
  5. where takes.id=student.id);
  6. select sum(credits)
  7. from takes natural join course
  8. where id=13403;
  9. select tot_cred
  10. from student
  11. where id=13403;
  1. db2022=# update student
  2. db2022-# set tot_cred=(
  3. db2022(# select sum(credits)
  4. db2022(# from takes natural join course
  5. db2022(# where takes.id=student.id);
  6. UPDATE 2000
  7. db2022=# select sum(credits)
  8. db2022-# from takes natural join course
  9. db2022-# where id=13403;
  10. sum
  11. -----
  12. 61
  13. (1 row)
  14. db2022=# select tot_cred
  15. db2022-# from student
  16. db2022-# where id=13403;
  17. tot_cred
  18. ----------
  19. 61
  20. (1 row)

34. Increase the salaries of instructors by 1000 times the number of course sections they have taught.

  1. select salary from instructor where ID=34175;
  2. select count(*) from teaches where ID=34175;
  3. update instructor
  4. set salary=salary+1000*
  5. (select count(*) from teaches where teaches.ID=instructor.ID);
  6. select salary from instructor where ID=34175;
  1. db2022=# select count(*) from teaches where ID=34175;
  2. count
  3. -------
  4. 10
  5. (1 row)
  6. db2022=# select salary from instructor where ID=34175;
  7. salary
  8. -----------
  9. 115469.11
  10. (1 row)
  11. db2022=# select count(*) from teaches where ID=34175;
  12. count
  13. -------
  14. 10
  15. (1 row)
  16. db2022=# update instructor
  17. db2022-# set salary=salary+1000*
  18. db2022-# (select count(*) from teaches where teaches.ID=instructor.ID);
  19. UPDATE 50
  20. db2022=# select salary from instructor where ID=34175;
  21. salary
  22. -----------
  23. 125469.11
  24. (1 row)

35. The university rules allow an F grade to be overridden by any pass grade (A, A-, B+, B, B-, C+, C, C-, D, D-). Now, create a view that lists information about all fail grades that have not been overridden (the view should contain all attributes from the takes relation).

  1. db2022=# create view failed_takes as
  2. db2022-# select * from takes
  3. db2022-# where grade='F';
  4. CREATE VIEW
  5. db2022=# select *
  6. db2022-# from failed_takes;
  7. id | course_id | sec_id | semester | year | grade
  8. -------+-----------+--------+----------+------+-------
  9. 79446 | 808 | 1 | Fall | 2003 | F
  10. 99710 | 169 | 2 | Fall | 2002 | F
  11. 56598 | 192 | 1 | Fall | 2002 | F
  12. 41890 | 599 | 1 | Spring | 2003 | F
  13. ...
  14. 52019 | 200 | 2 | Fall | 2002 | F
  15. 19321 | 200 | 2 | Fall | 2002 | F
  16. (961 rows)

36. Find all students who have 2 or more non-overridden F grades, and list them along with the F grades.

  1. db2022=# select ID, name, 'F' as grade
  2. from student
  3. where 1<(
  4. select count(*)
  5. from failed_takes
  6. where failed_takes.ID=student.ID)
  7. order by ID;
  8. id | name | grade
  9. -------+-------------+-------
  10. 1018 | Colin | F
  11. 10481 | Grosch | F
  12. 107 | Shabuno | F
  13. ...
  14. 99710 | Savolainen | F
  15. 99949 | Samo | F
  16. (176 rows)
  17. db2022=# select * from failed_takes where ID=1018;
  18. id | course_id | sec_id | semester | year | grade
  19. ------+-----------+--------+----------+------+-------
  20. 1018 | 274 | 1 | Fall | 2002 | F
  21. 1018 | 599 | 1 | Spring | 2003 | F
  22. (2 rows)

37. Grades are mapped to a grade point as follows.
Create a table to store these mappings, and write a query to find the GPA (Grade Point Average) of each student, using this table. Make sure students who have not got a non-null grade in any course are displayed with a GPA of null.
'A ''A'是不一样的,而原表中用的'A ', 'B ', 'C ', 'D ', 'F',所以必须要一致才可正确比较?
原表中有A+,给的表没有。

  1. create table grade_point
  2. (grade varchar(2),
  3. point numeric(2,1),
  4. primary key (grade));
  5. insert into grade_point values
  6. ('A+', 4.3), ('A ', 4.0), ('A-', 3.7), ('B+', 3.3), ('B ', 3.0), ('B-', 2.7), ('C+', 2.3), ('C ', 2.0), ('C-', 1.5), ('D ', 1.3), ('D-', 1.0), ('F', 0);
  7. select * from grade_point;
  8. create or replace function gradeToPoint(in g varchar(2))
  9. returns numeric(2,1) as $$
  10. declare
  11. res numeric(2,1);
  12. begin
  13. select point into res
  14. from grade_point
  15. where grade=g;
  16. return res;
  17. end;
  18. $$ LANGUAGE plpgsql;
  19. select ID, sum(gradeToPoint(coalesce(grade, 'F')))/(select count(*) as GPA from takes as S where S.ID=T.ID)
  20. from takes as T
  21. group by ID;
  1. db2022=# create table grade_point
  2. db2022-# (grade varchar(2),
  3. db2022(# point numeric(2,1),
  4. db2022(# primary key (grade));
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "grade_point_pkey" for table "grade_point"
  6. CREATE TABLE
  7. db2022=# insert into grade_point values
  8. db2022-# ('A+', 4.3), ('A ', 4.0), ('A-', 3.7), ('B+', 3.3), ('B ', 3.0), ('B-', 2.7), ('C+', 2.3), ('C ', 2.0), ('C-', 1.5), ('D ', 1.3), ('D-', 1.0), ('F', 0);
  9. INSERT 0 12
  10. db2022=# select * from grade_point;
  11. grade | point
  12. -------+-------
  13. A+ | 4.3
  14. A | 4.0
  15. A- | 3.7
  16. B+ | 3.3
  17. B | 3.0
  18. B- | 2.7
  19. C+ | 2.3
  20. C | 2.0
  21. C- | 1.5
  22. D | 1.3
  23. D- | 1.0
  24. F | 0.0
  25. (12 rows)
  26. db2022=# create or replace function gradeToPoint(in g varchar(2))
  27. db2022-# returns numeric(2,1) as $$
  28. db2022$# declare
  29. db2022$# res numeric(2,1);
  30. db2022$# begin
  31. db2022$# select point into res
  32. db2022$# from grade_point
  33. db2022$# where grade=g;
  34. db2022$# return res;
  35. db2022$# end;
  36. db2022$# $$ LANGUAGE plpgsql;
  37. CREATE FUNCTION
  38. db2022=# select ID, sum(gradeToPoint(coalesce(grade, 'F')))/(select count(*) as GPA from takes as S where S.ID=T.ID)
  39. db2022-# from takes as T
  40. db2022-# group by ID;
  41. id | ?column?
  42. -------+--------------------
  43. 3039 | 2.8000000000000000
  44. 86327 | 2.9333333333333333
  45. 22050 | 2.9272727272727273
  46. ...
  47. 53496 | 3.0750000000000000
  48. 25785 | 3.2533333333333333
  49. (2000 rows)

38. Find all classrooms that have been assigned to more than one section at the same time. Display the rooms along with the assigned sections; Using a with clause or a view to simplify this query.

  1. with conflicted(building, room_number) as
  2. (select building, room_number
  3. from classroom as C
  4. where 1<(
  5. select count(*) from section as S
  6. where S.building=C.building and S.room_number=C.room_number))
  7. select building, room_number, course_id, sec_id, semester, year
  8. from section natural join conflicted
  9. order by building, room_number;
  1. db2022=# with conflicted(building, room_number) as
  2. db2022-# (select building, room_number
  3. db2022(# from classroom as C
  4. db2022(# where 1<(
  5. db2022(# select count(*) from section as S
  6. db2022(# where S.building=C.building and S.room_number=C.room_number))
  7. db2022-# select building, room_number, course_id, sec_id, semester, year
  8. db2022-# from section natural join conflicted
  9. db2022-# order by building, room_number;
  10. building | room_number | course_id | sec_id | semester | year
  11. -----------+-------------+-----------+--------+----------+------
  12. Alumni | 547 | 362 | 2 | Fall | 2006
  13. Alumni | 547 | 445 | 1 | Spring | 2001
  14. Alumni | 547 | 581 | 1 | Spring | 2005
  15. Bronfman | 700 | 604 | 1 | Spring | 2009
  16. Bronfman | 700 | 362 | 3 | Spring | 2008
  17. ...
  18. Whitman | 434 | 482 | 1 | Fall | 2021
  19. Whitman | 434 | 482 | 1 | Fall | 2005
  20. (114 rows)

39. Create a view faculty showing only the ID, name, and department of instructors.

  1. db2022=# create view faculty as
  2. db2022-# select ID, name, dept_name
  3. db2022-# from instructor;
  4. CREATE VIEW
  5. db2022=# select * from faculty;
  6. id | name | dept_name
  7. -------+-------------------+-------------
  8. 63395 | McKinnon | Cybernetics
  9. 78699 | Pingr | Statistics
  10. ...
  11. 99052 | Dale | Cybernetics
  12. (50 rows)

SQL练习 40-43

40. Create a view CSinstructors, showing all information about instructors from the Comp. Sci. department.

  1. db2022=# create view CSinstructors as
  2. db2022-# select ID, name, dept_name, salary
  3. db2022-# from instructor
  4. db2022-# where dept_name='Comp. Sci.';
  5. CREATE VIEW
  6. db2022=# select * from CSinstructors;
  7. id | name | dept_name | salary
  8. -------+----------+------------+-----------
  9. 34175 | Bondi | Comp. Sci. | 125469.11
  10. 33351 | Bourrier | Comp. Sci. | 91797.83
  11. (2 rows)

41. Insert appropriate tuple into each of the views faculty and CSinstructors, to see what updates your database allows on views; explain what happens.
不能直接插入,必须声明有instead of的触发器,指定insert时要干什么。

  1. insert into faculty values (0, 'new', 'Comp. Sci.');
  2. create or replace rule r1_faculty_insert as
  3. on insert to faculty do instead
  4. insert into instructor values(new.ID, new.name, new.dept_name)
  5. returning instructor.ID, instructor.name, instructor.dept_name;
  6. insert into faculty values (0, 'new', 'Comp. Sci.');
  7. select * from faculty order by ID;
  8. create or replace rule r1_CSinstructors_insert as
  9. on insert to CSinstructors do instead
  10. insert into instructor values(new.ID, new.name, new.dept_name, new.salary);
  11. insert into CSinstructors values
  12. (0, 'new', 'Unknown Dept', 100);
  13. insert into CSinstructors values
  14. (0, 'new', 'Unknown Dept', 100000);
  15. insert into CSinstructors values
  16. (1, 'new', 'Unknown Dept', 100000);
  17. insert into CSinstructors values
  18. (1, 'new', 'Biology', 100000);
  19. insert into CSinstructors values
  20. (2, 'new', 'Comp. Sci.', 100000);
  21. select * from CSinstructors order by ID;

CSinstructors的前三条插入均失败,第一条不满足salary范围限制,第二条0重复,第三条违反instructordepartment的外键引用。
第四条成功,但其实不满足视图的where子句,需要自己在rule中修改。
第五条成功。

  1. db2022=# insert into faculty values
  2. db2022-# (0, 'new', 'Comp. Sci.');
  3. ERROR: cannot insert into view "faculty"
  4. HINT: You need an unconditional ON INSERT DO INSTEAD rule or an INSTEAD OF INSERT trigger.
  5. db2022=# create or replace rule r1_faculty_insert as
  6. db2022-# on insert to faculty do instead
  7. db2022-# insert into instructor values(new.ID, new.name, new.dept_name)
  8. db2022-# returning instructor.ID, instructor.name, instructor.dept_name;
  9. CREATE RULE
  10. db2022=# insert into faculty values (0, 'new', 'Comp. Sci.');
  11. INSERT 0 1
  12. db2022=# select * from faculty order by ID;
  13. id | name | dept_name
  14. -------+-------------------+-------------
  15. 0 | new | Comp. Sci.
  16. 14365 | Lembr | Accounting
  17. 15347 | Bawa | Athletics
  18. ...
  19. db2022=# create or replace rule r1_CSinstructors_insert as
  20. db2022-# on insert to CSinstructors do instead
  21. db2022-# insert into instructor values(new.ID, new.name, new.dept_name, new.salary)
  22. db2022-# ;
  23. CREATE RULE
  24. db2022=# insert into CSinstructors values
  25. db2022-# (0, 'new', 'Unknown Dept', 100);
  26. ERROR: new row for relation "instructor" violates check constraint "instructor_salary_check"
  27. DETAIL: N/A
  28. db2022=# insert into CSinstructors values
  29. (0, 'new', 'Unknown Dept', 100000);
  30. ERROR: duplicate key value violates unique constraint "instructor_pkey"
  31. DETAIL: Key (id)=(0) already exists.
  32. db2022=# insert into CSinstructors values
  33. db2022-# (1, 'new', 'Unknown Dept', 100000);
  34. ERROR: insert or update on table "instructor" violates foreign key constraint "instructor_dept_name_fkey"
  35. DETAIL: Key (dept_name)=(Unknown Dept) is not present in table "department".
  36. db2022=# insert into CSinstructors values
  37. db2022-# (1, 'new', 'Biology', 100000);
  38. INSERT 0 1

42. Create a new user and grant permission to the user to view all data in your student relation.

  1. create user user1 with password 'Password123';
  2. grant select on student to user1;
  3. gsql -d db2022 -U user1 -W 'Password123' -r
  4. select * from student;
  5. select * from faculty;
  1. db2022=# create user user1 with password 'Password123';
  2. CREATE ROLE
  3. db2022=# grant select on student to user1;
  4. GRANT
  5. db2022=# \q
  6. omm@97375c3acbd1:/$ gsql -d db2022 -U user1 -W 'Password123' -r
  7. gsql ((openGauss 2.1.0 build 590b0f8e) compiled at 2021-09-30 14:29:04 commit 0 last mr )
  8. Non-SSL connection (SSL connection is recommended when requiring high-security)
  9. Type "help" for help.
  10. db2022=> select * from student;
  11. id | name | dept_name | tot_cred
  12. -------+--------------------+-------------+----------
  13. 5925 | Maw | Languages | 44
  14. 25611 | Sve | English | 57
  15. 94569 | Yip | English | 46
  16. ...
  17. db2022=> select * from faculty;
  18. ERROR: permission denied for relation faculty
  19. DETAIL: N/A

43. Now grant permission to all users to see all data in your faculty view.

  1. grant select on faculty to public;
  2. select * from faculty;
  1. db2022=> grant select on faculty to public;
  2. ERROR: permission denied for relation faculty
  3. DETAIL: N/A
  4. db2022=> \q
  5. omm@97375c3acbd1:/$ gsql -d db2022 -r
  6. gsql ((openGauss 2.1.0 build 590b0f8e) compiled at 2021-09-30 14:29:04 commit 0 last mr )
  7. Non-SSL connection (SSL connection is recommended when requiring high-security)
  8. Type "help" for help.
  9. db2022=# grant select on faculty to public;
  10. GRANT
  11. db2022=# \q
  12. omm@97375c3acbd1:/$ gsql -d db2022 -U user1 -W 'Password123' -r
  13. gsql ((openGauss 2.1.0 build 590b0f8e) compiled at 2021-09-30 14:29:04 commit 0 last mr )
  14. Non-SSL connection (SSL connection is recommended when requiring high-security)
  15. Type "help" for help.
  16. db2022=> select * from faculty;
  17. id | name | dept_name
  18. -------+-------------------+-------------
  19. 63395 | McKinnon | Cybernetics
  20. 78699 | Pingr | Statistics
  21. ...
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注