2016-11-26 31 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恤衫。很長的故事。謝謝你的徹底回覆,當天發貨! –