Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 一对多表联接?_Sql_Sql Server_Database Design - Fatal编程技术网

Sql 一对多表联接?

Sql 一对多表联接?,sql,sql-server,database-design,Sql,Sql Server,Database Design,我有一个表webRooms,其中有许多行与第二个表中的行相匹配。表1如下所示: ID | dorm_building | dorm_room | occupant_num student_ID | dorm_building | dorm_room ID | dorm_building | dorm_room | occupant_num | student_id 1 | my_dorm | 1 | 1

我有一个表webRooms,其中有许多行与第二个表中的行相匹配。表1如下所示:

ID  |  dorm_building  |  dorm_room |  occupant_num
student_ID  |  dorm_building  | dorm_room
ID | dorm_building | dorm_room | occupant_num | student_id 1 | my_dorm | 1 | 1 | 123 2 | my_dorm | 1 | 2 | 345 ID | dorm_building | dorm_room | occupant_num | student_id 1 | my_dorm | 1 | 1 | 123 2 | my_dorm | 1 | 2 | 123
select * from webRooms wR 
  LEFT JOIN RESIDENCY R on wR.dorm_building = r.DORM_BUILDING 
    and wr.dorm_room = r.DORM_ROOM 
表2如下所示:

ID  |  dorm_building  |  dorm_room |  occupant_num
student_ID  |  dorm_building  | dorm_room
ID | dorm_building | dorm_room | occupant_num | student_id 1 | my_dorm | 1 | 1 | 123 2 | my_dorm | 1 | 2 | 345 ID | dorm_building | dorm_room | occupant_num | student_id 1 | my_dorm | 1 | 1 | 123 2 | my_dorm | 1 | 2 | 123
select * from webRooms wR 
  LEFT JOIN RESIDENCY R on wR.dorm_building = r.DORM_BUILDING 
    and wr.dorm_room = r.DORM_ROOM 
我希望得到如下结果:

ID  |  dorm_building  |  dorm_room |  occupant_num
student_ID  |  dorm_building  | dorm_room
ID | dorm_building | dorm_room | occupant_num | student_id 1 | my_dorm | 1 | 1 | 123 2 | my_dorm | 1 | 2 | 345 ID | dorm_building | dorm_room | occupant_num | student_id 1 | my_dorm | 1 | 1 | 123 2 | my_dorm | 1 | 2 | 123
select * from webRooms wR 
  LEFT JOIN RESIDENCY R on wR.dorm_building = r.DORM_BUILDING 
    and wr.dorm_room = r.DORM_ROOM 
由于给出了一些答案,我在混合中添加了第三个表。此表已经存在-我使用它生成webRooms表,它被称为webDorms,如下所示:

ID  |  dorm_building  |  dorm_room |  occupant_num
student_ID  |  dorm_building  | dorm_room
ID | dorm_building | dorm_room | occupant_num | student_id 1 | my_dorm | 1 | 1 | 123 2 | my_dorm | 1 | 2 | 345 ID | dorm_building | dorm_room | occupant_num | student_id 1 | my_dorm | 1 | 1 | 123 2 | my_dorm | 1 | 2 | 123
select * from webRooms wR 
  LEFT JOIN RESIDENCY R on wR.dorm_building = r.DORM_BUILDING 
    and wr.dorm_room = r.DORM_ROOM 
ID |宿舍楼|宿舍房|最高入住率

其结果如下:

ID  |  dorm_building  |  dorm_room |  occupant_num
student_ID  |  dorm_building  | dorm_room
ID | dorm_building | dorm_room | occupant_num | student_id 1 | my_dorm | 1 | 1 | 123 2 | my_dorm | 1 | 2 | 345 ID | dorm_building | dorm_room | occupant_num | student_id 1 | my_dorm | 1 | 1 | 123 2 | my_dorm | 1 | 2 | 123
select * from webRooms wR 
  LEFT JOIN RESIDENCY R on wR.dorm_building = r.DORM_BUILDING 
    and wr.dorm_room = r.DORM_ROOM 
2 |我的宿舍| 1 | 2


我认为你的数据模型有缺陷。当前,您的模型每个房间有多个记录,每个插槽一个记录。因为您的查询只将学生限制在房间而不是插槽中,所以会生成交叉联接,这是错误的结果

为了克服模型的缺点,可以对查询进行模糊处理。DISTINCT关键字是这些场景中选择的生硬工具:

SQL> select *
  2      from ( select DISTINCT dorm_building, dorm_room from webRooms) wR
  3          LEFT JOIN residency R
  4          on wR.dorm_building = r.dorm_building
  5          and wr.dorm_room = r.dorm_room
  6  /

DORM_BUILDING         DORM_ROOM STUDENT_ID DORM_BUILDING         DORM_ROOM
-------------------- ---------- ---------- -------------------- ----------
my_dorm                       1        123 my_dorm                       1
my_dorm                       1        345 my_dorm                       1
my_dorm                       2

SQL>
解决这个问题的更好方法是使用老虎机桌。这样就不需要有多个WebRoom记录来表示单个物理房间。您说将学生分配到哪个时段无关紧要,但将学生分配到特定时段是应用程序成功运行的关键

以下是一些概念验证表:

create table webrooms
 (dorm_building varchar2(20)
    , dorm_room number)
/

create table slots
 (dorm_building varchar2(20)
    , dorm_room number
    , occupant_num number)
/

create table residency
 (student_id number
    , dorm_building varchar2(20)
    , dorm_room number
    , occupant_num number)
/
如您所见,修改后的查询提供了哪些插槽已被占用以及哪些插槽保持空闲的明确指示:

SQL> select wr.*, s.occupant_num, r.student_id
  2      from webrooms wr
  3          INNER JOIN slots s
  4              on wr.dorm_building = s.dorm_building
  5              and wr.dorm_room = s.dorm_room
  6          LEFT JOIN residency r
  7              on s.dorm_building = r.dorm_building
  8              and s.dorm_room = r.dorm_room
  9              and s.occupant_num = r.occupant_num
 10  order by 1, 2, 3, 4
 11  /

DORM_BUILDING         DORM_ROOM OCCUPANT_NUM STUDENT_ID
-------------------- ---------- ------------ ----------
my_dorm                       1            1        123
my_dorm                       1            2        345
my_dorm                       2            1        678
my_dorm                       2            2
my_dorm                       2            3        890
my_dorm                       3            1
my_dorm                       3            2
my_dorm                       3            3
my_dorm                       4            1
my_dorm                       4            2        666

9 rows selected.

SQL>
或者,如果我们有一个支持PIVOT查询的数据库,我在这里使用的是Oracle 11g:

SQL> select * from (
  2      select wr.dorm_building||' #'||wr.dorm_room as dorm_room
  3             , num_gen.num as slot_number
  4             , case
  5                  when r.student_id is not null then r.student_id
  6                  when s.occupant_num is not null then 0
  7                  else null
  8               end as occupancy
  9          from webrooms wr
 10              CROSS JOIN ( select rownum as num from dual connect by level <= 4) num_gen
 11              LEFT JOIN slots s
 12                  on wr.dorm_building = s.dorm_building
 13                  and wr.dorm_room = s.dorm_room
 14                  and num_gen.num = s.occupant_num
 15              LEFT JOIN residency r
 16                  on s.dorm_building = r.dorm_building
 17                  and s.dorm_room = r.dorm_room
 18                  and s.occupant_num = r.occupant_num
 19      )
 20  pivot
 21      ( sum (occupancy)
 22        for slot_number in ( 1, 2, 3, 4)
 23      )
 24  order by dorm_room
 25  /

DORM_ROOM           1          2          3          4
---------- ---------- ---------- ---------- ----------
my_dorm #1        123        345
my_dorm #2        678          0        890
my_dorm #3          0          0          0
my_dorm #4          0        666

SQL>

您在APC帖子的评论中提到,您想要的只是可用性计数。如果真的是这样,那么我认为以下设计会更有效:

Create Table Rooms  (
                        dorm_building ... Not Null
                        , dorm_room ... Not Null
                        , capacity int Not Null default ( 0 )
                        , Constraint PK_Rooms Primary Key ( dorm_building, dorm_room )
                        , ...
                        )

Create Table Residency  (
                            student_id ... Not Null Primary Key
                            , dorm_building ... Not Null
                            , dorm_room ... Not Null
                            , Constraint FK_Residency_Rooms
                                Foreign Key ( dorm_building, dorm_room )
                                References Rooms ( dorm_building, dorm_room )
                            , ...
                            )
我之所以将学生id作为居住表中的主键,只是因为没有提到时间因素,学生不可能同时在两个房间。现在,要获得可用空间,我们可以执行以下操作:

Select Rooms.dorm_building, Rooms.dorm_room
    , Rooms.Capacity
    , Coalesce(RoomCounts.OccupantTotal,0) As TotalOccupants
    , Rooms.Capacity - Coalesce(RoomCounts.OccupantTotal,0) As AvailableSpace
From Rooms
    Left Join   (
                Select R1.dorm_building, R1.dorm_room, Count(*) As OccupantTotal
                From Residency As R1
                Group By R1.dorm_building, R1.dorm_room
                ) As RoomCounts
        On RoomCounts.dorm_building = Rooms.dorm_building
            And RoomCounts.dorm_room = Rooms.dorm_room
现在,如果您还想显示插槽,那么您应该计算一下,假设SQL Server 2005及更高版本:

With Numbers As
    (
    Select Row_Number() Over ( Order By C1.object_id ) As Value
    From sys.columns As C1
        Cross Join sys.columns As C2
    )
    , NumberedResidency As
    (
    Select dorm_building, dorm_room, student_id
        , Row_Number() Over ( Partition By dorm_building, dorm_room Order By student_id ) As OccupantNum
    From Residency
    )
Select Rooms.dorm_building, Rooms.dorm_room, R.OccupantNum, R.StudentId
From Rooms
    Join Numbers As N
        On N.Value <= Rooms.Capacity
    Left Join NumberedResidency As R
        On R.dorm_building = Rooms.dorm_building
            And R.dorm_room = Rooms.dorm_room
            And N.Value = R.OccupantNum

@davemackey你目前在你的电脑上使用的是什么query@msarchet:选择*从webRooms wR LEFT加入wR.dorm_building=R.dorm_building=R.dorm_building和wR.dorm_room=R.dorm_Rooms您检查数据了吗?也许你在居留表中有两次相同的记录。@davemackey你能将代码编辑到你的问题中,使其更具可读性吗?请发布你当前的查询,以便我们了解发生了什么。学生不应该也不应该被限制在房间内的特定位置。我只需要一种方式来证明一个房间是否已经满了——以及视觉上还有多少空位。Occupator_num只是一个占位符,表示此记录用于房间中的x插槽-但特定插槽无关紧要。问题是并非每个房间都已满-但我需要显示一个空占位符来表示这一事实。因此,在某些房间中,当前可能只有一个插槽被占用,但我希望报表查看器看到还有另一个可用插槽。此外,有些房间有更多的插槽-例如,五个。@DaveMackey-我的两个建议将为您提供占位符:要么将数据模型更改为单独的插槽表,要么保留当前模型,只需修改查询。我已更新了我的问题,我想我基本上得到了您的建议-如果我错了,请纠正我。我在每个房间的每个位置或床上都有一排网络教室,每个宿舍的每个房间都有一排网络宿舍——包括最大入住率值,每个学生都有一排居住权。