我在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)
);
答案 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 joins
和a
,b
和c
之间的d
,而不是旧的Oracle-具体语法。 (使用我的假数据like this)。但这不是问题的重点。
这似乎是实现这一目标的一种痛苦方式;据推测,你最终会得到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));
...只需在今年剩余时间内添加更多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())
条款。