2016-11-26 85 views
3

我有如下表:SQL连接获得2列的笛卡尔积了3列

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列ns以及它们在第三列中的相关值(当值存在时),否则为0。

我尝试了一些外连接的组合,但它们都没有工作。

请帮忙。

谢谢。

+2

尝试连同多个子表(即'(从#table中选择键)作为key_table')以及整个表。另外,我在'key'(一个关键字)和'#table'('#'是一个注释开始(至少在MySQL中)“)时遇到了问题 –

+0

字符串常量需要用SQL中的单引号括起来,而不是双引号。 '“a”是一个标识符,''a''是一个字符串常量。你正在使用哪个DBMS? –

+0

对不起,我应该提到我使用Sybase ASE(应与MSSQL的语法相同)。这解释了#table表示一个临时表 –

回答

2

试试这个:

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

这也会在存在值的情况下创建'0'行。 –

+0

我使用Sybase ASE(与MS SQL相同),它似乎不理解做一个连接,而不必指定应该应用连接的列。 –

+0

@JeromeProvensal mybe你可以使用这个:'JOIN table_name t2 ON TRUE'或'JOIN table_name t2 ON 1 = 1' – simhumileco

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

+0

我使用Sybase ASE,它似乎不喜欢交叉连接 –

+0

尝试'加入... on 1 = 1'而不是然后 –

+0

感谢您的帮助,Henning,但它并没有完全符合我的要求, –

0

感谢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 

就像我想它。

1

哇,这是我第一次见到某人特意要求在一个SQL Q &论坛的笛卡尔产品结果!

我的意思是,一个笛卡尔乘积结果往往是在SQL技术问答&一个论坛上提到,当人们回答想谈谈SQL的CROSS PRODUCT,或在关系代数(由特德·科德创造了运营商名称)只是product

我不是来自数学背景,直到我开始想写更好的SQL,并且该术语不断出现在答案中(任何人都记得Usenet新闻组?),我还没有听说过笛卡儿积。我听说SQL是基于数学集合理论的,同样来自人们回答说:“你应该寻找一个基于集合的方法......”所以起初我没有考虑太多,“很酷,我今天学了一个新名词。“

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

下面是从Wikipedia on the subject一行:

为套AB,笛卡尔乘积A x B是该组的所有有序对(a, b)其中a [是的元素]的Ab [是的元件] 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

+0

我猜我的词汇量背叛了我的年龄,并且我也知道usenet团队的事实......我甚至有一个rec.windsurfing的T恤衫。很长的故事。谢谢你的彻底回复,当天发货! –