Oracle 按查询分组时卡住重复行

Oracle 按查询分组时卡住重复行,oracle,group-by,pivot,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 Des

我在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放在我的类型和月份周围,这确实减少了重复,但也消除了结果

对于我的查询,我决定让它对我来说简单,因为我每个月都做子查询,然后选择子查询。我看了看枢轴,但不知道如何做枢轴

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
附录:我试图使用pivot,但收到一个错误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)
);

这与分组无关。你得到的是重复的,因为你没有加入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 (+)
如果我认为您看到的是虚假数据,那么很明显您没有发布DDL或insert语句来重现您的实际问题。第一个查询以与您相同的模式获取重复项;第二种方法使用此方法允许在两列上进行外部联接

虽然我宁愿看到它与ANSI连接;a中的交叉连接,然后在a和b、c和d之间留下外部连接,而不是旧的Oracle特定语法。用我的假数据。但这并不是问题的重点

这似乎也是实现这一目标的痛苦方式;大概一整年都会有12个子查询。在group by和pivot中包含月份的单个子查询将更易于读取和维护

如果您使用的是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));

使用相同的数据。同样,在接下来的几个月里,只需添加更多的sumcase子句。

Post table ddl、一些示例数据和预期输出。我同意pivot,但我对语法和如何实现pivot感到困惑。我花了一点时间在网上搜索,但还不够。是的……这将是一个难看的查询。但是每个子查询都是相同的,除了add_months,对吗?@user3308606-我已经添加了一个pivot,假设你在11g上,所以让它可用。在本例中,只有一个子查询的日期范围是开放的。您可以将mnth值调整为月份名称、缩写或数字,以使其与年份无关-然后您只需要在内部查询中更改日期范围,但必须确保它被限制为一年。当然,这可能与您真正需要的相差甚远……谢谢您提供的Pivot示例。我以为我们使用的是11g,但DBA纠正了我的错误,我正在处理的项目是版本10.2.0.4。所以我用了你的另一个例子,加入了这个类型,它起了作用。感谢您的帮助。@user3308606-好的,在11g之前,您可以使用sumcase和groupby获得相同的效果;答案中添加了示例。
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;