学习记录--查询没有学全所有课的同学的学号、姓名、以及未学科目

逛贴吧的时候遇到了这样一个问题

这样的表结构需要【查询没有学全所有课的同学的学号、姓名、以及未学科目】

------------脚本-------------------------

CREATE TABLE [dbo].[课程表](
    课程id [INT] NULL,
    课程名称 [NVARCHAR](50) NULL,
    讲师id [INT] NULL
) ON [PRIMARY]

CREATE TABLE [dbo].成绩表(
    学生id [int] NULL,
    课程id [int] NULL,
    成绩 [int] NULL
) ON [PRIMARY]

CREATE TABLE [dbo].学生表(
    学生id [int] NULL,
    学生名称 [nvarchar](50) NULL,
    年龄 [int] NULL,
    性别 [nvarchar](50) NULL
) ON [PRIMARY]


CREATE TABLE [dbo].讲师表(
    讲师id [int] NULL,
    讲师名称 [nvarchar](50) NULL
) ON [PRIMARY]


INSERT [dbo].[成绩表] ([学生id], [课程id], [成绩]) VALUES (1, 1, 20)
GO
INSERT [dbo].[成绩表] ([学生id], [课程id], [成绩]) VALUES (1, 2, 20)
GO
INSERT [dbo].[成绩表] ([学生id], [课程id], [成绩]) VALUES (1, 3, 20)
GO
INSERT [dbo].[成绩表] ([学生id], [课程id], [成绩]) VALUES (2, 1, 20)
GO
INSERT [dbo].[成绩表] ([学生id], [课程id], [成绩]) VALUES (2, 2, 20)
GO
INSERT [dbo].[成绩表] ([学生id], [课程id], [成绩]) VALUES (3, 3, 20)
GO


INSERT [dbo].[讲师表] ([讲师id], [讲师名称]) VALUES (1, N'张老师')
GO
INSERT [dbo].[讲师表] ([讲师id], [讲师名称]) VALUES (2, N'李老师')
GO
INSERT [dbo].[讲师表] ([讲师id], [讲师名称]) VALUES (3, N'王老师')
GO
INSERT [dbo].[讲师表] ([讲师id], [讲师名称]) VALUES (4, N'宋老师')
GO

INSERT [dbo].[课程表] ([课程id], [课程名称], [讲师id]) VALUES (1, N'语文', 1)
GO
INSERT [dbo].[课程表] ([课程id], [课程名称], [讲师id]) VALUES (2, N'数学', 2)
GO
INSERT [dbo].[课程表] ([课程id], [课程名称], [讲师id]) VALUES (3, N'英语', 3)
GO
INSERT [dbo].[课程表] ([课程id], [课程名称], [讲师id]) VALUES (4, N'体育', 4)
GO

INSERT [dbo].[学生表] ([学生id], [学生名称], [年龄], [性别]) VALUES (1, N'张三', 12, N'')
GO
INSERT [dbo].[学生表] ([学生id], [学生名称], [年龄], [性别]) VALUES (2, N'李四', 12, N'')
GO
INSERT [dbo].[学生表] ([学生id], [学生名称], [年龄], [性别]) VALUES (3, N'王五', 12, N'')
GO
INSERT [dbo].[学生表] ([学生id], [学生名称], [年龄], [性别]) VALUES (4, N'赵六', 12, N'')

解决问题,想法是【构造笛卡尔积】,然后通过【左连接】选出【成绩表】中不存在的【学生id】

  SELECT    s.学生id,
            s.学生名称,
            s.年龄,
            s.性别,
            c.课程id,
            c.课程名称,
            c.讲师id
  FROM      dbo.学生表 s
  LEFT JOIN dbo.课程表 c ON 1=1
  LEFT JOIN dbo.成绩表 ON s.学生id = dbo.成绩表.学生id AND 成绩表.课程id = c.课程id
  WHERE dbo.成绩表.学生id IS NULL

得到的结果:

接下来,我用的是SQLServer,所以使用【for xml】来构造

SELECT B.学生id,
       B.学生名称,
       B.年龄,
       LEFT(B.未学科目, LEN(B.未学科目) - 1) AS 未学科目
  FROM (   SELECT A.学生id,
                  A.学生名称,
                  A.年龄,
                  (   SELECT Z.课程名称 + ','
                        FROM (   SELECT      s.学生id,
                                             s.学生名称,
                                             s.年龄,
                                             s.性别,
                                             c.课程id,
                                             c.课程名称,
                                             c.讲师id
                                   FROM      dbo.学生表 s
                                   LEFT JOIN dbo.课程表 c
                                     ON 1        = 1
                                   LEFT JOIN dbo.成绩表
                                     ON s.学生id   = dbo.成绩表.学生id
                                    AND 成绩表.课程id = c.课程id
                                  WHERE      dbo.成绩表.学生id IS NULL) Z
                       WHERE Z.学生id = A.学生id
                      FOR XML PATH('')) AS 未学科目
             FROM (   SELECT      s.学生id,
                                  s.学生名称,
                                  s.年龄,
                                  s.性别,
                                  c.课程id,
                                  c.课程名称,
                                  c.讲师id
                        FROM      dbo.学生表 s
                        LEFT JOIN dbo.课程表 c
                          ON 1        = 1
                        LEFT JOIN dbo.成绩表
                          ON s.学生id   = dbo.成绩表.学生id
                         AND 成绩表.课程id = c.课程id
                       WHERE      dbo.成绩表.学生id IS NULL) A
            GROUP BY A.学生id,
                     A.学生名称,
                     A.年龄,
                     A.性别) AS B;

最后结果

 

 

问题是解决了,但可能效率不高,毕竟笛卡尔积。

 

posted @ 2019-06-04 16:05 Simona' 阅读(...) 评论(...) 编辑 收藏