【问题标题】:cross joining two tables交叉连接两个表
【发布时间】:2012-11-15 20:15:56
【问题描述】:

我有一个看起来像这样的表,让我们将此表称为B

id    boardid    schoolid     subject     cnt1   cnt2  cnt3 ....
=================================================================
1       20         21           f     
2       20         21           r
3       20         21           w
4       20         21           m
5       20         30           r
6       20         30           w
7       20         30           m

假设计数只是整数。请注意,schoolid = 30 没有 subject = f。同样,对于大多数学校,一些subject dosnt 存在。你可能有一个schoolid,它只有r, w,或者一些只是r, m, f..

所以我想做的是为每所学校设置 4 个一致的行,而不存在的行我想要虚拟值。我想过创建一个辅助表

drop table #A
Select * into #A FROM 
(
select [subject_s] = 'r', orderNo = 1
union all
select [subject_s] = 'w', orderNo = 2
union all
select [subject_s] = 'm', orderNo = 3
union all
select [subject_s] = 'f', orderNo = 4
) z

并对它们进行一些连接,但我不知道在哪里。我试过内连接,左外连接,交叉连接,一切。我什至尝试过制作笛卡尔积。我认为我的笛卡尔积搞砸了,因为我在那里有orderno,所以它在主表中每行有 16 行。实际上输入这个,我意识到如果我删除orderno,应用笛卡尔积,然后在稍后添加 orderno,它可能会起作用,但我很想看看你们能想出什么。我被难住了。

最终结果

id    boardid    schoolid     subject     cnt1   cnt2  cnt3 ....
=================================================================
1       20         21           r     
2       20         21           w
3       20         21           m
4       20         21           f
5       20         30           r
6       20         30           w
7       20         30           m
7       20         30           f

【问题讨论】:

  • 你有一张包含所有科目的表格吗?如何确定每个 schoolid 中需要出现的所有科目?
  • 您使用的是什么 RDBMS?为什么最终结果的最后一行的 id 为 7?
  • 错字,id 是自动生成的数字。我已经创建了一个临时表将我的所有科目(只有四个)

标签: sql


【解决方案1】:

尝试以下方法:

SELECT S.boardid, S.schoolid, A.[subject], B.cnt1, B.cnt2, B.cnt3
FROM (SELECT DISTINCT boardid, schoolid FROM YourTable) S
CROSS JOIN #A A
LEFT JOIN YourTable B
    ON B.boardid = S.boardid AND  B.schoolid = S.schoolid 
    AND A.[subject] = B.[subject]

【讨论】:

    【解决方案2】:

    由于我不知道您使用的是哪个 RDBMS,因此我使用 sqlite 和一个更简单的表尝试了以下操作:

    sqlite> create table schools (name varchar, subject varchar, teacher varchar);
    
    sqlite> select * from schools;
    School1|Maths|Mr Smith
    School2|English|Jack
    School3|English|Jimmy
    School3|Maths|Jane
    School4|Computer Science|Bob
    
    sqlite> select
                schoolnames.name, 
                subjects.subject, 
                ifnull(teachers.teacher, "Unknown") 
            from (select distinct name from schools) schoolnames
            join (select distinct subject from schools) subjects
            left join schools teachers
               on schoolnames.name = teachers.name
                  and subjects.subject = teachers.subject;
    
    School1|Maths|Mr Smith
    School1|English|Unknown
    School1|Computer Science|Unknown
    
    School2|Maths|Unknown
    School2|English|Jack
    School2|Computer Science|Unknown
    
    School3|Maths|Jane
    School3|English|Jimmy
    School3|Computer Science|Unknown
    
    School4|Maths|Unknown
    School4|English|Unknown
    School4|Computer Science|Bob
    

    【讨论】:

      【解决方案3】:

      我会使用:

      SELECT 
          boardid, schoolid, dist_subject, id, cnt1, ...
      FROM
          (SELECT 
              boardid, schoolid, dist_subject
          FROM
              (SELECT 
                  DISTINCT subject AS dist_subject 
              FROM b ) s full outer join
              (SELECT 
                  boardid, schoolid 
              FROM b 
              GROUP BY 
                  boardid, schoolid   ) g ) sg LEFT OUTER JOIN
          b ON 
          sg.boardID = b.boardID AND
          sg.schoolid = b.schoolID
          sg.dist_subject = b.subject
      

      【讨论】:

      • 永远不要使用隐式连接。它们是 SQL 反模式。改用交叉连接,然后维护脚本的人就会知道这不是意外的交叉连接,而是有意的。
      猜你喜欢
      • 1970-01-01
      • 2016-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多