AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 242412
Accepted
Asrar Ahmad Ehsan
Asrar Ahmad Ehsan
Asked: 2019-07-09 22:35:42 +0800 CST2019-07-09 22:35:42 +0800 CST 2019-07-09 22:35:42 +0800 CST

在 SQL Server 中根据用户条件显示表记录

  • 772

我有一个由 SQL Server 数据库支持的 Web 应用程序。它有一份报告,结合了选定学期的学生和特定的方式。下图显示了选择学期和学生人数的界面。

在此处输入图像描述

用户选择学期并输入学生人数。为了清楚起见,假设用户输入3学生并选择1th学期2th。系统应返回所有注册的学生1th和2th学期如下:

------------------------
Id  StudentName Semester
------------------------
1       A          First
4       D          First
7       G          First
2       B          Second
3       C          Second
5       E          Second
9       I          First
10      J          First
12      L          First
6       F          Second
8       H          Second
11      K          Second

数据集如下:

学生桌

-----------------
Id  StudentName
-----------------
1       A
2       B
3       C
4       D
5       E
6       F
7       G
8       H
9       I
10      J
11      K
12      L

学期表

-----------------
Id  Semester
-----------------
1       First
2       Second
3       Third

报名表

----------------------------
Id  StudentID   SemesterID
----------------------------
1      1            1
2      2            2
3      3            2
4      4            1
5      5            2
6      6            2
7      7            1
8      8            2
9      9            1
10     10           1
11     11           2
12     12           1

关于如何显示上述表格的记录的任何想法?

sql-server t-sql
  • 1 1 个回答
  • 176 Views

1 个回答

  • Voted
  1. Best Answer
    Andriy M
    2019-07-13T14:34:10+08:002019-07-13T14:34:10+08:00

    解决此问题的一种方法是从Enrollment表格开始。使用ROW_NUMBER排名功能,您可以按以下组分配行号SemesterID:

    SELECT
      *,
      RN = ROW_NUMBER() OVER (PARTITION BY SemesterID ORDER BY Id ASC)
    FROM
      dbo.Enrollment
    ;
    

    对于您的示例,您将获得如下输出:

    Id  StudentID  SemesterID  RN
    --  ---------  ----------  --
    1   1          1           1
    2   2          2           1
    3   3          2           2
    4   4          1           2
    5   5          2           3
    6   6          2           4
    7   7          1           3
    8   8          2           5
    9   9          1           4
    10  10         1           5
    11  11         2           6
    12  12         1           6
    

    现在减去一个RN,然后将结果除以所需的学生人数。如果学生人数是3,那么你会发现前面的计算变成了一个序列

    1, 2, 3, 4, 5, 6, ...
    

    进入

    0, 0, 0, 1, 1, 1, ...
    

    也就是说,你会得到一个由多组重复数字组成的序列,每组三个(因为我们除以三)。您可以将该结果用作主要排序标准。

    选择SemesterID作为您的第二个标准和Id或StudentID作为第三个标准,所以现在查询将如下所示:

    SELECT
      *,
      GroupID = (ROW_NUMBER() OVER (PARTITION BY SemesterID ORDER BY Id ASC) - 1) / 3
    FROM
      dbo.Enrollment
    ORDER BY
      GroupID ASC,
      SemesterID ASC,
      Id ASC
    ;
    

    这将是基于提供的样本的输出:

    Id  StudentID  SemesterID  GroupID
    --  ---------  ----------  -------
    1   1          1           0
    4   4          1           0
    7   7          1           0
    2   2          2           0
    3   3          2           0
    5   5          2           0
    9   9          1           1
    10  10         1           1
    12  12         1           1
    6   6          2           1
    8   8          2           1
    11  11         2           1
    

    您可以看到行的顺序已经与预期的输出相匹配,您只需将StudentIDand替换SemesterID为它们的描述并去掉GroupID. 将上述查询声明为派生表或 CTE,然后将表连接Student到Semester它。对于我的回答,我选择了 CTE 选项,这就是我得到的:

    WITH
      RankedData AS
      (
        SELECT
          *,
          GroupID = (ROW_NUMBER() OVER (PARTITION BY SemesterID ORDER BY Id ASC) - 1) / 3
        FROM
          dbo.Enrollment
      )
    SELECT
      rd.Id,
      st.StudentName,
      sm.Semester
    FROM
      RankedData AS rd
      INNER JOIN dbo.Student AS st ON rd.StudentID = st.Id
      INNER JOIN dbo.Semester AS sm ON rd.SemesterID = sm.Id
    ORDER BY
      rd.GroupID ASC,
      rd.SemesterID ASC,
      rd.Id ASC
    ;
    

    输出:

    Id  StudentName Semester
    --  ----------- --------
    1   A           First
    4   D           First
    7   G           First
    2   B           Second
    3   C           Second
    5   E           Second
    9   I           First
    10  J           First
    12  L           First
    6   F           Second
    8   H           Second
    11  K           Second
    

    如您所见,到目前为止,我们的查询非常适合提供的示例:结果现在与您的预期输出精确匹配。但是查询还没有完成:缺少学期的过滤器。

    假设学期将以逗号分隔的名称/描述列表的形式提供,您可以做的是将该列表转换为行集,每行有一个名称/描述。然后,您可以将该行集与Semester表进行匹配,以仅包含选定的学期。出于此答案的目的,我假设您使用的是 SQL Server 2016 或更高版本,以便可以使用内置SPLIT_STRING函数来帮助实现学期过滤器:

    WITH
      RankedData AS
      (
        SELECT
          *,
          GroupID = (ROW_NUMBER() OVER (PARTITION BY SemesterID ORDER BY Id ASC) - 1) / 3
        FROM
          dbo.Enrollment
      )
    SELECT
      rd.Id,
      st.StudentName,
      sm.Semester
    FROM
      RankedData AS rd
      INNER JOIN dbo.Student  AS st ON rd.StudentID  = st.Id
      INNER JOIN dbo.Semester AS sm ON rd.SemesterID = sm.Id
    WHERE
      sm.Semester IN (SELECT value FROM STRING_SPLIT('First,Second', ','))
    ORDER BY
      rd.GroupID ASC,
      rd.SemesterID ASC,
      rd.Id ASC
    ;
    

    在 SQL Server 的早期版本中,您必须提供自己的方法将字符串列表转换为子字符串的行集。值得庆幸的是,互联网上的解决方案比比皆是,包括这里和 Stack Overflow 上专门针对这个问题的许多问题和答案。Aaron Bertrand在他的博客文章中讨论了各种方法,以正确的方式拆分字符串 - 或次佳方式,这可能是一个很好的起点。

    至于我们的查询,还有最后一步要做:参数化。在上述查询中,学生人数和所选学期列表都是硬编码的。最终解决方案将需要使用参数引用而不是硬编码值,如下所示:

    WITH
      RankedData AS
      (
        SELECT
          *,
          GroupID = (ROW_NUMBER() OVER (PARTITION BY SemesterID ORDER BY Id ASC) - 1) / @NumberOfStudents
        FROM
          dbo.Enrollment
      )
    SELECT
      rd.Id,
      st.StudentName,
      sm.Semester
    FROM
      RankedData AS rd
      INNER JOIN dbo.Student  AS st ON rd.StudentID  = st.Id
      INNER JOIN dbo.Semester AS sm ON rd.SemesterID = sm.Id
    WHERE
      sm.Semester IN (SELECT value FROM STRING_SPLIT(@SemesterList, ','))
    ORDER BY
      rd.GroupID ASC,
      rd.SemesterID ASC,
      rd.Id ASC
    ;
    

    此解决方案的现场演示可在dbfiddle 徽标db<>fiddle.uk 获得。


    披露:这个答案部分借用了Josh Darnell现在删除的答案。

    • 4

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve