【问题标题】:SQL join to get the cartesian product of 2 columns out of 3 columnsSQL 连接获取 3 列中 2 列的笛卡尔积
【发布时间】:2017-04-10 22:33:56
【问题描述】:

我有下表:

create table #table (
  time int,
  key  char(1),
  val  int
)

使用以下数据:

insert into #table (time, key, val) values (0,"a",1)
insert into #table (time, key, val) values (0,"b",2)
insert into #table (time, key, val) values (1,"a",10)
insert into #table (time, key, val) values (2,"b",20)

我想提出一个连接将产生以下行/列:

0  a  1
0  b  2
1  a  10
1  b  0
2  a  0
2  b  20

当值存在时,它基本上是前 2 列的值与它们在第 3 列中的关联值的笛卡尔积,否则为 null 时为 0。

我尝试了几种外连接组合,但似乎都不起作用。

请帮忙。

谢谢。

【问题讨论】:

  • 尝试将多个子表(即(select key from #table) as key_table)与整个表连接在一起。另外,key(关键字)和#table# 是注释开始(至少在 MySQL 中))有问题
  • SQL 中字符串常量需要用单引号括起来,而不是双引号。 "a" 是一个标识符,'a' 是一个字符串常量。您使用的是哪个 DBMS?
  • 对不起,我应该提到我使用的是 Sybase ASE(应该是和 MSSQL 一样的语法)。这解释了#table 来表示一个临时表

标签: sql join sybase outer-join cartesian-product


【解决方案1】:

试试这个:

SELECT DISTINCT t1.time, 
                t2.key, 
                IF(
                    t1.time = t2.time AND t1.key = t2.key AND t1.value = t2.value, 
                    t1.value, 
                    0
                ) AS value
FROM table_name t1
JOIN table_name t2
ORDER BY t1.time ASC,
         t2.key ASC;

【讨论】:

  • 这也会在存在值的情况下创建“0”行。
  • 我使用 Sybase ASE(与 MS SQL 相同),它似乎无法理解在不必指定应应用连接的列上进行连接。
  • @JeromeProvensal mybe 你可以使用这个:JOIN table_name t2 ON TRUEJOIN table_name t2 ON 1 = 1
  • 很高兴能帮上忙! :-)
【解决方案2】:
Select times.time, keys.key, coalesce(table.val, 0) as val
From (Select distinct time from table) times
    cross join
    (Select distinct key from table) keys
    left outer join table
    on times.time = table.time and keys.key = table.key

基本上,您首先构造叉积,然后执行left outer join

【讨论】:

  • 我用的是Sybase ASE,好像不喜欢cross join
  • 然后尝试join ... on 1=1
  • 感谢 Henning 的帮助,但它并没有达到我想要的效果,
【解决方案3】:

感谢 simhumileco,这是使其与 Sybase 兼容后的答案。

下面是表格的创建和填充:

create table #table (
  time int,
  fet  char(1),
  val  int
)

insert into #table (time, fet, val) values (0,"a",1)
insert into #table (time, fet, val) values (0,"b",2)
insert into #table (time, fet, val) values (1,"a",10)
insert into #table (time, fet, val) values (2,"b",20)

以及实际的解决方案:

Select times.time, fets.fet, coalesce(#table.val, 0) as val
From (Select distinct time from #table) times
JOIN (Select distinct fet from #table) fets on 1=1
    left outer join #table
    on times.time = #table.time and fets.fet = #table.fet
order by times.time ASC,
         fets.fet ASC

结果:

 time        fet val
 ----------- --- -----------
           0 a             1
           0 b             2
           1 a            10
           1 b             0
           2 a             0
           2 b            20

就像我想要的那样。

【讨论】:

    【解决方案4】:

    哇,这是我第一次看到有人在 SQL 问答论坛上专门询问笛卡尔积的结果!

    我的意思是,当人们回答想要谈论 SQL 的 CROSS PRODUCT,或者只是关系代数中的 product(由特德科德)。

    我不是数学背景,直到我开始想编写更好的 SQL 并且这个术语不断出现在答案中(有人记得 Usenet 新闻组吗?)之前,我才听说过笛卡尔积。我听说 SQL 是基于数学集合论的,同样来自人们回答说:“你应该寻找基于集合的方法......”所以一开始我并没有想太多关于它,“酷,我今天学到了一个新术语。”

    后来——也许有点太晚了——我开始研究 SQL 所基于的关系模型 (RM),发现自己质疑自己对笛卡尔积的理解。

    这是来自Wikipedia on the subject的一行:

    对于集合AB,笛卡尔积A x B 是所有有序对的集合(a, b) 其中a [是] A 的元素和b [是元素的]B.

    呃,“有序对”?我对 RM 有足够的了解,知道订购不合适。简而言之:在RM中,两个关系之间的操作产生一个关系,一个关系有一个标题,它是一组属性,而一个定义的集合没有顺序;虽然关系可以包含一个有序对属性首先,但不可能将有序对作为关系操作的结果来实现。

    另一方面,SQL 有很多从左到右的顺序依赖(例如,UNION 中的列顺序后来用UNION CORRESPONDING 修复),所以笛卡尔积在 SQL 中可能有一些意义? SQL 不像 RM 那样严格,但假设两个表表达式之间的操作会产生一个表表达式。当运算为CROSS JOIN时,结果是否是所有有序对的集合?

    首先,CROSS JOIN 的结果是一个集合吗?好吧,如果涉及的表表达式有重复的行,那么结果也会有重复的行,所以严格来说它不会是一个集合。然而,如果我们已经采取措施确保我们的表表达式符合第一范式(实际上我们应该),那么CROSS JOIN 的结果可以是一个集合。 [对于两个表表达式共有的属性名称,我们有类似的问题和解决方案。]

    第二,CROSS JOIN的结果是一对吗?举个例子:

    WITH Suppliers AS
         ( SELECT * FROM (
            VALUES
                ( 'S1', 'Smith', 'London' ),
                ( 'S2', 'Jones', 'Paris' )
            ) AS t ( SID, SNAME, CITY )
        ),
        Parts AS
         ( SELECT * FROM (
            VALUES
                ( 'S1', 'Nut', 'Red' ),
                ( 'S2', 'Bolt', 'Green' )
            ) AS t ( PID, SNAME, COLOR )
        )
    SELECT *
      FROM Suppliers
           CROSS JOIN Parts;
    

    结果是四行六列(没有重复的列名)。列不以任何方式分组。对我来说,结果中没有任何内容表明我有一组配对。

    三、CROSS JOIN的列结果是否有序?我们可以换桌...

    SELECT *
      FROM Parts
           CROSS JOIN Suppliers;
    

    ...而且,很有可能这些列将以从左到右的顺序出现,即Parts,然后是Suppliers。就个人而言,我不认为这是“有序”的。 SQL 标准对SELECT * 表示“实现定义”的效果,这意味着不保证任何固有顺序。我认为在 SO 上没有任何知识渊博的人会建议在未明确定义的结果中依赖任何从左到右的列排序。

    我的结论是 SQL 缺少真正的笛卡尔积运算符,CROSS JOIN 只是另一个导致表表达式(或类似表达式)的 SQL 操作。在 SQL 上下文中,我们应该停止使用术语笛卡尔积,而是使用 CROSS JOIN 或简单地使用 product

    【讨论】:

    • 我猜我的词汇量出卖了我的年龄以及我也知道什么是 usenet 组的事实......我什至有一件用于 rec.windsurfing 的 T 恤。很长的故事。感谢您的彻底回复,onedaywhen!
    【解决方案5】:

    在 sql server 查询中,交叉连接给出了两列的笛卡尔积(如果两个表都是一个列表)。

    【讨论】:

      猜你喜欢
      • 2011-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-16
      • 2012-03-24
      • 2012-08-17
      相关资源
      最近更新 更多