通过查询重复行来阻止Group

时间:2014-04-03 15:31:04

标签: oracle group-by pivot

我在Oracle中有以下查询,我试图显示每月进出的库存数量。输出看起来像一张记分卡,其中月份是列标题。

Part Nbr   part desc    Type    Jan   Feb   March ....
11111      some part     IN      2    5     20
11111      some part     OUT     30   10    5

但我最终会得到一个输出。对于我添加的每个月,我都会获得更多重复项。

Part Nbr   Part Description                Type    Jan     Feb
11291     UMTS TMA  AWS/AWS w/ VSWR         OUT     9       32
11291     UMTS TMA  AWS/AWS w/ VSWR          IN    247      32
11291     UMTS TMA  AWS/AWS w/ VSWR         OUT     9       29
11291     UMTS TMA  AWS/AWS w/ VSWR          IN    247      29
11291     UMTS TMA  AWS/AWS w/ VSWR         OUT     9       32
11291     UMTS TMA  AWS/AWS w/ VSWR          IN    247      32
11291     UMTS TMA  AWS/AWS w/ VSWR         OUT     9       29
11291     UMTS TMA  AWS/AWS w/ VSWR          IN    247      29

我已经尝试将Max放在我的类型和月份之间,这确实减少了重复项,但它也消除了Out结果。

对于我的查询,我决定保持简单(对我而言),因为我每个月都会进行子查询,然后选择子查询。我看着Pivot,但挂了如何进行旋转。

SELECT a.part_nbr as part_nbr, a.part_desc as part_desc,  b.InvType as "Type",b.recv_qty_1 as "January", c.recv_qty_2 as "February" FROM
(
SELECT part_nbr, part_desc
FROM tmadmin.customer_product
) a,
(
SELECT recv_part_nbr, SUM(inv_qty) as recv_qty_1, 'IN' as InvType
FROM tmadmin.ro_hist a
WHERE trunc(recv_date,'MM') = trunc(To_Date('01-01-2014', 'dd-mm-yyyy'), 'MM')
GROUP BY recv_part_nbr
UNION
SELECT x.pack_part_nbr, SUM(z.inv_qty) as ship_qty_1, 'OUT' as InvType
FROM tmadmin.ship_dtl x, tmadmin.ship_hdr y, tmadmin.ro_hist z
WHERE x.pack_nbr = y.pack_nbr
AND x.pack_asset_tag = z.asset_tag
AND trunc(y.ship_date,'MM') = trunc(To_Date('01-01-2014', 'dd-mm-yyyy'), 'MM')
GROUP BY x.pack_part_nbr
) b,
(
SELECT recv_part_nbr, SUM(inv_qty) as recv_qty_2, 'IN' as InvType
FROM tmadmin.ro_hist a
WHERE trunc(recv_date,'MM') = add_months(trunc(To_Date('01-01-2014', 'dd-mm-yyyy'), 'MM'),1)
GROUP BY recv_part_nbr
UNION
SELECT x.pack_part_nbr, SUM(z.inv_qty) as ship_qty_2, 'OUT' as InvType
FROM tmadmin.ship_dtl x, tmadmin.ship_hdr y, tmadmin.ro_hist z
WHERE x.pack_nbr = y.pack_nbr
AND x.pack_asset_tag = z.asset_tag
AND trunc(y.ship_date,'MM') = add_months(trunc(To_Date('01-01-2014', 'dd-mm-yyyy'), 'MM'),1)
GROUP BY x.pack_part_nbr
) c,
(
SELECT recv_part_nbr, SUM(inv_qty) as recv_qty_3, 'IN' as InvType
FROM tmadmin.ro_hist a
WHERE trunc(recv_date,'MM') = add_months(trunc(To_Date('01-01-2014', 'dd-mm-yyyy'), 'MM'),2)
GROUP BY recv_part_nbr
UNION
SELECT x.pack_part_nbr, SUM(z.inv_qty) as ship_qty_3, 'OUT' as InvType
FROM tmadmin.ship_dtl x, tmadmin.ship_hdr y, tmadmin.ro_hist z
WHERE x.pack_nbr = y.pack_nbr
AND x.pack_asset_tag = z.asset_tag
AND trunc(y.ship_date,'MM') = add_months(trunc(To_Date('01-01-2014', 'dd-mm-yyyy'), 'MM'),2)
GROUP BY x.pack_part_nbr
) d
WHERE a.part_nbr = b.recv_part_nbr(+)
AND a.part_nbr = c.recv_part_nbr(+)
AND a.part_nbr = d.recv_part_nbr(+)
order by part_nbr

附录:我尝试使用数据透视表,我收到错误SQL jcommand未正确结束。

select * from (
SELECT recv_part_nbr, a.inv_qty,  EXTRACT(MONTH FROM a.recv_date) as mth
FROM tmadmin.ro_hist a
WHERE trunc(recv_date,'MM') >= trunc(To_Date('01-01-2014', 'dd-mm-yyyy'), 'MM')
AND trunc(recv_date,'MM') <= trunc(To_Date('31-12-2014', 'dd-mm-yyyy'), 'MM')
UNION
SELECT x.pack_part_nbr, z.inv_qty, EXTRACT(MONTH FROM y.ship_date)  as mth 
FROM tmadmin.ship_dtl x, tmadmin.ship_hdr y, tmadmin.ro_hist z
WHERE x.pack_nbr = y.pack_nbr
AND x.pack_asset_tag = z.asset_tag
AND trunc(y.ship_date,'MM') >= trunc(To_Date('01-01-2014', 'dd-mm-yyyy'), 'MM')
AND trunc(y.ship_date,'MM') <= trunc(To_Date('31-12-2014', 'dd-mm-yyyy'), 'MM')
)
PIVOT
(
    SUM(a.inv_qty)  as "IN",
    SUM(z.inv_qty)  as "OUT"
    FOR (mth)
    IN (1 AS January,
          2 AS February,
          3 AS March,
          4 AS April,
          5 AS May,
          6 AS June,
          7 AS July,
          8 AS August,
          9 AS September,
          10 AS October,
          11 AS November,
          12 AS December)
);

1 个答案:

答案 0 :(得分:0)

这与分组无关。你得到重复,因为你没有加入InvType;但是你不能外连接到多个表,所以你需要一个不同的机制。一种选择是使用另一个虚拟表来生成两个可能的值,例如:

SELECT a.part_nbr as part_nbr, a.part_desc as part_desc, a.InvType as "Type",
  b.recv_qty_1 as "January", c.recv_qty_2 as "February"
FROM
(
  SELECT part_nbr, part_desc, InvType
  FROM tmadmin.customer_product,
  (
    SELECT 'IN' as InvType from dual
    UNION ALL
    SELECT 'OUT' as Invtype from dual
  )
) a,
...
WHERE a.part_nbr = b.recv_part_nbr(+)
AND a.InvType = b.Invtype (+)
WHERE a.part_nbr = c.recv_part_nbr(+)
AND a.InvType = c.Invtype (+)
WHERE a.part_nbr = d.recv_part_nbr(+)
AND a.InvType = d.Invtype (+)

Here's an SQL Fiddle如果我认为你看到了什么,假冒数据清楚,因为你没有发布DDL或插入语句来重新创建你的实际问题。第一个查询以您所使用的相同模式获取重复项;第二个使用此方法让您在两列上进行外连接。

虽然我宁愿用ANSI连接看到它; cross join内的a,然后是left outer joinsabc之间的d,而不是旧的Oracle-具体语法。 (使用我的假数据like this)。但这不是问题的重点。

这似乎是实现这一目标的一种痛苦方式;据推测,你最终会得到12个子查询一整年。在group bypivot中包含月份的单个子查询将更易于阅读和维护...

如果您使用11g且可以访问pivot运营商,那么我认为:

SELECT *
FROM (
  SELECT cp.part_nbr as part_nbr, cp.part_desc as part_desc,
    it.inv_type, t.mnth, t.inv_qty
  FROM (
      SELECT 'IN' as inv_type FROM dual
      UNION ALL select 'OUT' as inv_type from dual
  ) it
  CROSS JOIN customer_product cp
  LEFT JOIN (
    SELECT extract(month from recv_date) as mnth, recv_part_nbr as part_nbr,
      inv_qty,
      'IN' as inv_type
    FROM ro_hist a
    WHERE recv_date >= date '2014-01-01'
    AND recv_date < date '2015-01-01'
    UNION
    SELECT extract(month from y.ship_date) as mnth, x.pack_part_nbr as part_nbr,
      z.inv_qty, 'OUT' as inv_type
    FROM ship_dtl x, ship_hdr y, ro_hist z
    WHERE x.pack_nbr = y.pack_nbr
    AND x.pack_asset_tag = z.asset_tag
    AND y.ship_date >= date '2014-01-01'
    AND y.ship_date < date '2015-01-01'
  ) t
  ON t.part_nbr = cp.part_nbr
  AND t.inv_type = it.inv_type
)
PIVOT (SUM(inv_qty) AS qty FOR (mnth) IN (1 as Jan, 2 as Feb, 3 as Mar));

...只需在今年剩余时间内添加更多IN条款。 SQL Fiddle使用与重复示例相匹配的虚拟数据(我想!)。

如果你不是11g,你可以用老式的方式进行转动:

SELECT cp.part_nbr as part_nbr, cp.part_desc as part_desc, it.inv_type,
  sum(case when t.mnth = 1 then t.inv_qty else 0 end) as Jan,
  sum(case when t.mnth = 2 then t.inv_qty else 0 end) as Feb,
  sum(case when t.mnth = 3 then t.inv_qty else 0 end) as Mar
FROM (
    SELECT 'IN' as inv_type FROM dual
    UNION ALL select 'OUT' as inv_type from dual
) it
CROSS JOIN customer_product cp
LEFT JOIN (
  SELECT extract(month from recv_date) as mnth, recv_part_nbr as part_nbr,
    inv_qty, 'IN' as inv_type
  FROM ro_hist a
  WHERE recv_date >= date '2014-01-01'
  AND recv_date < date '2015-01-01'
  UNION
  SELECT extract(month from y.ship_date) as mnth, x.pack_part_nbr as part_nbr,
    z.inv_qty, 'OUT' as inv_type
  FROM ship_dtl x, ship_hdr y, ro_hist z
  WHERE x.pack_nbr = y.pack_nbr
  AND x.pack_asset_tag = z.asset_tag
  AND y.ship_date >= date '2014-01-01'
  AND y.ship_date < date '2015-01-01'
) t
ON t.part_nbr = cp.part_nbr
AND t.inv_type = it.inv_type
GROUP BY cp.part_nbr, cp.part_desc, it.inv_type;

SQL Fiddle具有相同的数据。同样,只需在剩下的几个月中添加更多sum(case())条款。