用于计算组合并包括不存在的条目的SQL查询

时间:2013-01-10 19:10:59

标签: sql oracle count

这是我正在处理的表的简化版本,即Orders

+-------------------+------------------+---------------+
| 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)的所有可能组合,其计数显示在表格中找到组合的次数。我的问题是我想要包含所有可能的组合,如果组合不在Orders表中,我希望计数显示为零。所以,我正在寻找的输出是这样的。

+------+-----+-----------+
| 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      |
+------+-----+-----------+

我尝试了很多查询,但从未接近这一点,甚至不确定是否可以完成。现在我正在计算客户端的组合,因此我执行了太多查询来获取频率。

3 个答案:

答案 0 :(得分:1)

也许最明确的方法是从列表开始作为CTE:

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)
    )
. . .

这更简洁,但可能会导致查询效率降低。

答案 1 :(得分: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。

答案 2 :(得分:0)

我没有Oracle测试它,但这就是我要做的事情:

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