在postgres中加入动态行数

时间:2014-04-25 16:07:00

标签: sql postgresql join

假设我有以下表格:

Batch        Items
---+-----    ---+----------+--------
id | size    id | batch_id | quality
---+-----    ---+----------+--------
1  | 10      1  | 1        | 9
2  | 2       2  | 1        | 10
             3  | 2        | 1
             4  | 2        | 2
             5  | 2        | 1
             6  | 2        | 9

我有批次的物品。它们是按批量batch.size批量发送的。如果一个项目的质量是< = 3。

,则该项目被破坏

我想知道发送的最后一批产品中已损坏的商品数量:

batch_id | broken_item_count
---------+---------------------
1        | 0
2        | 2 (and not 3)

我的想法如下:

SELECT batch.id as batch_id, COUNT(broken_items.*) as broken_item_count
FROM batch
INNER JOIN (
  SELECT id
  FROM items
  WHERE items.quality <= 3
  ORDER BY items.id asc 
  LIMIT batch.size -- invalid reference to FROM-clause entry for table "batch"
) broken_items ON broken_items.batch_id = batch.id

(我会ORDER BY items.shipped_at。但为了简单起见,我按items.id订购

但是这个查询向我显示了我作为评论的错误。 如何根据每行不同的batch.size 来限制已加入项目的数量?

还有其他方法可以实现我的目标吗?

3 个答案:

答案 0 :(得分:1)

SQL Fiddle

select
    b.id as batch_id,
    count(quality <= 3 or null) as broken_item_count
from
    batch b
    inner join (
        select
            id, quality, batch_id,
            row_number() over (partition by batch_id order by id) as rn
        from items
    ) i on i.batch_id = b.id
where rn <= b.size
group by b.id
order by b.id

答案 1 :(得分:1)

SELECT b.id AS batch_id
     , count(i.quality < 4 OR NULL) AS broken_item_count
FROM   batch b
LEFT   JOIN (
    SELECT batch_id, quality
         , row_number() OVER (PARTITION BY batch_id ORDER BY id DESC) AS rn
    FROM   items
    ) i ON i.batch_id = b.id
       AND i.rn <= b.size
GROUP  BY 1
ORDER  BY 1;

SQL Fiddle with added examples.

这很像@Clodoaldos's answer,但有一些不同之处。最重要的是:

  • 您想要计算broken items in the last batches sent,因此我们必须ORDER BY id DESC
  • 如果可以批量生产没有商品,则需要使用 LEFT JOIN 而不是普通JOIN,否则将排除这些批次。
    因此,检查i.rn <= b.size需要从WHERE子句移到JOIN子句。

答案 2 :(得分:0)

据我所知,缺陷物品的数量不能大于批量大小。

编辑:在阅读您的评论后,我认为使用RANK()功能,然后按等级和大小加入应该适合您。以下查询尝试使用。

SELECT b.id,
     SUM(CASE WHEN i1.quality <= 3 THEN 1 ELSE 0END) as broken_item_count
FROM BATCH as b
    LEFT JOIN (SELECT i.id, i.batch_id, i.quality, 
               RANK() OVER(PARTITION BY i.batch_id ORDER BY i.id) as RANK
           FROM ITEMS as i) as i1 ON b.id = i1.batch_id AND i1.RANK <= b.size
GROUP BY b.id

EDIT2 :使用LEFT JOIN更新了查询,以涵盖某些batch中没有样本的情况。