2013-01-10 62 views
1

這是我處理與該表的簡化版本是訂單SQL查詢不存在的

+-------------------+------------------+---------------+ 
| Order_Base_Number | Order_Lot_Number | Other Cols... | 
+-------------------+------------------+---------------+ 
|     1 |    3 |    | 
|     1 |    3 |    | 
|     1 |    4 |    | 
|     1 |    4 |    | 
|     1 |    4 |    | 
|     1 |    5 |    | 
|     2 |    3 |    | 
|     2 |    5 |    | 
|     2 |    9 |    | 
|     2 |    10 |    | 
+-------------------+------------------+---------------+ 

我想要做的是讓該計數基於基本和批號的唯一條目。我有兩組數字,一組是一組基數,另一組是一組批號。例如 ,可以說這兩套是Base In(1,2,3),Lot在(3,4,20)中。

我正在尋找一個SQL查詢,可以從兩組與展示多少次組合在表中找到的計數返回(基地地塊)的所有可能的組合。我的問題是我想包括所有可能的組合,如果一個組合不在訂單表中,我希望計數顯示爲零。所以,我正在尋找的輸出是這樣的。

+------+-----+-----------+ 
| Base | Lot | Frequency | 
+------+-----+-----------+ 
| 1 | 3 | 2  | 
| 1 | 4 | 3  | 
| 1 | 20 | 0  | 
| 2 | 3 | 1  | 
| 2 | 4 | 0  | 
| 2 | 20 | 0  | 
| 3 | 3 | 0  | 
| 3 | 4 | 0  | 
| 3 | 20 | 0  | 
+------+-----+-----------+ 

我試了很多查詢,但從來沒有接近這個,甚至不知道它是否可以完成。現在我正在搞清楚客戶端的組合,因此我正在執行太多的查詢來獲取頻率。

+0

哪個平臺您使用的是SQL服務器,Oracle,DB2 ....? – Hogan

+0

對不起,它是Oracle –

回答

1

也許最清晰的方式是先從名單爲熱膨脹係數:

with bases as (
    select 1 as base from dual union all 
    select 2 as base from dual union all 
    select 3 as base from dual 
    ), 
    lots as (
    select 3 as lot from dual union all 
    select 4 as lot from dual union all 
    select 20 as lot from dual 
    ) 
select b.base, l.lot, count(Order_Base_Number) as Frequency 
from bases b cross join lots l left outer join 
    Orders o 
    on o.base = b.base and o.lot = l.lot 
group by b.base, l.lot 

注意,這使得cross join明確,特意不使用,的笛卡爾乘積。

此查詢的第一部分也可以寫成類似如下(假設每個基地,很多在表中的至少一個記錄):

with bases as (
    select distinct base 
    from Orders -- or some other table, perhaps Orders ? 
    where base in (1, 2, 3) 
    ), 
    select distinct lot 
    from Orders -- or some other table, perhaps Lots ? 
    where lot in (3, 4, 20) 
    ) 
. . . 

這是更簡潔,但可能導致查詢效率較低。

+0

我的印象是SQL Server有CTE但Oracle沒有。 – Hogan

+0

@霍根。 。 。 Oracle可能會稱他們爲別的東西,但它支持'with'語法。你可以在SQLFiddle(www.sqlfiddle.com)上測試它。 –

+0

非常酷@GordonLinoff - 我將在下次回憶Oracle問題時記住這一點。謝謝。 – Hogan

0

你在最裏面的子查詢被稱爲CROSS JOIN,它得到的記錄笛卡爾產品(所有可能的組合)所需要的。這時候,你既沒有JOIN..ON condition也不WHERE你會得到什麼:

SELECT Base.Id as baseid, Lot.Id as lotid FROM Bases, Lots 

現在把它變成子查詢和LEFT JOIN到你的東西休息:

SELECT ... FROM 
    (SELECT Base.Id as baseid, Lot.Id as lotid 
      FROM Bases, Lots) baseslots 
    LEFT JOIN Orders ON Order_Base_Number = baseid, 
      Order_Lot_Number = lotid .... 

有了這個LEFT JOIN,你會得到爲NULL不存在的組合。使用COALESCE(或像這樣),把它們變成0

+0

請不要使用隱式連接語法,請始終明確聲明您的連接。此外,這假定存在「基礎」和「全部」,但情況可能並非如此。 –

+0

謝謝@ Clockwork-Muse,但我沒有基地也沒有很多。 –

0

我沒有甲骨文測試,但這個是我會做什麼:

CREATE TABLE pairs AS 
(
SELECT DISTINCT Base.Order_Base_Number, Lot.Order_Lot_Number 
FROM ORDERS Base 
CROSS JOIN ORDERS Lot 
); 

CREATE TABLE counts AS 
(
SELECT Order_Base_Number, Order_Lot_Number, Count(*) AS C 
FROM ORDERS 
GROUP BY Order_Base_Number, Order_Lot_Number 
); 

SELECT P.Order_Base_Number, P.Order_Lot_Number, COALESCE(C.C,0) AS [Count] 
FROM Pairs P 
LEFT JOIN counts C ON P.Order_Base_Number = C.Order_Base_Number 
      AND P.Order_Lot_Number = C.Order_Lot_Number 
+0

你可能不需要一張真正的表格 - 戈登使用的CTE應該沒問題。此外,「對」假定所有可能的組合都被表示出來,我懷疑是否有保證;如果你會在OP的問題中注意到,他提到當給定的組合不存在時他想要結果。考慮到你在最後的查詢中使用了'INNER JOIN','COALESCE(C.C,0)'是毫無意義的。 –

+0

@ Clockwork-Muse - 我不知道Oracle支持CTE(請參閱我對Gordon的文章的評論。)CROSS JOIN將使所有可能的組合(嘗試它)。您對最後一次加入是正確的,已修復。 – Hogan

+0

...說真的,我錯過了一個'CROSS JOIN',只認爲它有一個'FROM'子句。我不知道我發生了什麼... –