我通过不同查询的UNION查询不同项类型的数据(多列)。如果特定项类型的任何列中没有值,则该记录不会显示。但是,我需要与每个项目类型相关的所有行(包括空行)。空行可以显示0。
我的数据是:
create table sales_table ([yr] int, [qtr] varchar(40), [item_type] varchar(40), [sale_price] int);
create table profit_table ([yr] int, [qtr] varchar(40), [item_type] varchar(40), [profit] int);
create table item_table ([item_type] varchar(40));
insert into sales_table values
(2010,'Q1','abc',31),(2010,'Q1','def',23),(2010,'Q1','mno',12),(2010,'Q1','xyz',7),(2010,'Q2','abc',54),(2010,'Q2','def',67),(2010,'Q2','mno',92),(2010,'Q2','xyz',8);
insert into profit_table values
(2010,'Q1','abc',10),(2010,'Q1','def',6),(2010,'Q1','mno',23),(2010,'Q1','xyz',7),(2010,'Q2','abc',21),(2010,'Q2','def',13),(2010,'Q2','mno',15),(2010,'Q2','xyz',2);
insert into item_table values
('abc'),('def'),('ghi'),('jkl'),('mno'),('xyz');
我的查询是:
SELECT a.yr, a.qtr, b.item_type, MAX(a.sales), MAX(a.avg_price), MAX(a.profit)
FROM
(SELECT [yr], [qtr],
CASE
WHEN item_type = 'abc' THEN 'ABC'
WHEN item_type = 'def' THEN 'DEF'
WHEN item_type = 'ghi' THEN 'GHI'
WHEN item_type = 'jkl' THEN 'JKL'
WHEN item_type IN ('mno', 'xyz') THEN 'Other'
END AS [item_type],
COUNT(sale_price) OVER (PARTITION BY yr, qtr, item_type) [sales],
AVG(sale_price) OVER (PARTITION BY yr, qtr, item_type) [avg_price],
NULL [profit]
FROM sales_table
WHERE yr >=2010
UNION ALL
SELECT yr, qtr,
CASE
WHEN item_type = 'abc' THEN 'ABC'
WHEN item_type = 'def' THEN 'DEF'
WHEN item_type = 'ghi' THEN 'GHI'
WHEN item_type = 'jkl' THEN 'JKL'
WHEN item_type IN ('mno', 'xyz') THEN 'Other'
END AS [item_type],
NULL [sales],
NULL [avg_price],
SUM(profit) OVER (PARTITION BY yr, qtr, item_type) [profit]
FROM profit_table
WHERE yr >=2010
) a
FULL OUTER JOIN
(SELECT
CASE
WHEN item_type = 'abc' THEN 'ABC'
WHEN item_type = 'def' THEN 'DEF'
WHEN item_type = 'ghi' THEN 'GHI'
WHEN item_type = 'jkl' THEN 'JKL'
WHEN item_type IN ('mno', 'xyz') THEN 'Other'
END AS [item_type]
FROM item_table
WHERE item_type in ('abc','def','ghi','jkl','mno','xyz')
) b
ON a.item_type = b.item_type
GROUP BY a.yr, a.qtr, b.item_type
ORDER BY a.yr, a.qtr, b.item_type;
目前的输出是这样的:
yr qtr item_type sales avg_price profit
(null) (null) GHI (null) (null) (null)
(null) (null) JKL (null) (null) (null)
2010 Q1 ABC 1 31 10
2010 Q1 DEF 1 23 6
2010 Q1 Other 1 12 23
2010 Q2 ABC 1 54 21
2010 Q2 DEF 1 67 13
2010 Q2 Other 1 92 15
我想要的是如下所示。
yr qtr item_type sales avg_price profit
2010 Q1 ABC 1 31 10
2010 Q1 DEF 1 23 6
2010 Q1 GHI 0 0 0
2010 Q1 JKL 0 0 0
2010 Q1 Other 2 9.5 30
2010 Q2 ABC 1 54 21
2010 Q2 DEF 1 67 13
2010 Q2 GHI 0 0 0
2010 Q2 JKL 0 0 0
2010 Q2 Other 2 50 17
请指教。
这是使用union all + group by
的另一种选择
select
max(max([year])) over ()
, max(max([quarter])) over ()
, [item_type]
, isnull(max([sales]), 0)
, isnull(max([avg price]), 0)
, isnull(max([profit]), 0)
from (
SELECT [year], [quarter], [item_type], [sales], [avg price], [profit]
FROM sales_table
union all
select distinct null, null, item_type, null, null, null
from item_table
) t
group by [item_type]
您使用full join
的查询应该有效,但您必须处理null
值。我认为它看起来应该是这样的:
SELECT
max(a.year) over ()
, max(a.quarter) over ()
, b.item_type
, isnull(a.sales, 0)
, isnull(a.avg_price, 0)
, isnull(a.profit, 0)
FROM
(SELECT [year], [quarter], [item_type], [sales], [avg price], [profit]
FROM sales_table) a
FULL OUTER JOIN
(SELECT item_type FROM item_table) b
ON a.item_type = b.item_type
ORDER BY a.year, a.quarter, b.item_type
得到它的工作。
关键是将Item_type与日期交叉连接(对于此示例,需要创建临时日历表),然后使用sales_table和profit_table的计算结果进行左连接。
insert into #date_table values
(2010,'Q1'),(2010,'Q2'), (2010,'Q3'),(2010,'Q4');
SELECT
b.yr
, b.qtr
, b.item_type
, COALESCE(MAX(a.sales),0) AS sales
, COALESCE(MAX(a.avg_price),0) AS avg_price
, COALESCE(MAX(a.profit),0) AS profit
FROM
(
SELECT
dt.[yr]
,dt.[qtr]
,CASE
WHEN it.[item_type] IN ('mno', 'xyz') THEN 'Other'
ELSE UPPER(it.[item_type])
END AS [item_type]
FROM
#date_table AS dt
CROSS JOIN
#item_table AS it
WHERE
dt.[yr] >=2010
GROUP BY
dt.[yr]
,dt.[qtr]
,CASE
WHEN it.[item_type] IN ('mno', 'xyz') THEN 'Other'
ELSE UPPER(it.[item_type])
END
) AS b
LEFT JOIN
(SELECT [yr], [qtr],
CASE
WHEN item_type IN ('mno', 'xyz') THEN 'Other'
ELSE UPPER([item_type])
END AS [item_type],
COUNT(sale_price) OVER (PARTITION BY yr, qtr, item_type) [sales],
AVG(sale_price) OVER (PARTITION BY yr, qtr, item_type) [avg_price],
NULL [profit]
FROM #sales_table
WHERE yr >=2010
UNION ALL
SELECT yr, qtr,
CASE
WHEN item_type IN ('mno', 'xyz') THEN 'Other'
ELSE UPPER([item_type])
END AS [item_type],
NULL [sales],
NULL [avg_price],
SUM(profit) OVER (PARTITION BY yr, qtr, item_type) [profit]
FROM #profit_table
WHERE yr >=2010
) a
ON
a.[yr] = b.[yr]
AND
a.[qtr] = b.[qtr]
AND
a.[item_type] = b.[item_type]
GROUP BY
b.yr, b.qtr, b.item_type
ORDER BY b.yr, b.qtr, b.item_type;