Oracle 按查询分组时卡住重复行
我在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
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;