这是漫长的一天,也许这是一个简单的问题,但无论如何我都被卡住了。
基本上我有两个类似的表Sales
和Forecasts
。我正在尝试创建一个视图,从两个表中选择行,并选择给定模型+月份+国家/地区的任何内容。如果两个表都包含数据,Sales
具有优先级,这意味着应省略Forecast
行。
为了简化查询我正在使用CTE。实际上两个表的模式是不同的,并且连接了许多表,Forecasts
包含只显示最后一个的历史行。
我创建了一个简化的架构和数据来向您展示我正在尝试做的事情:
WITH Sales AS
(
SELECT
ID, Model, Month, Country,
Amount = Count,
[Forecast / Sales] = 'Sales'
FROM dbo.Sales
)
, Forecasts AS
(
SELECT
ID, Model, Month, Country,
Amount = Count,
[Forecast / Sales] = 'Forecast'
FROM dbo.Forecast
)
SELECT ID = COALESCE(s.ID, fc.ID),
Model = COALESCE(s.Model, fc.Model),
Month = COALESCE(s.Month, fc.Month),
Country = COALESCE(s.Country, fc.Country),
Amount = COALESCE(s.Amount, fc.Amount),
[Forecast / Sales] = COALESCE(s.[Forecast / Sales], fc.[Forecast / Sales])
FROM Sales s
FULL OUTER JOIN Forecasts fc
ON s.Model = fc.Model
AND s.Month = fc.Month
AND s.Country = fc.Country
ORDER BY ID,Month,Country,Model
这是一个带有示例数据的sql-fiddle:http://sqlfiddle.com/#!3/9081b/9/2
结果:
ID MODEL MONTH COUNTRY AMOUNT FORECAST / SALES
1 ABC December, 01 2013 00:00:00+0000 Germany 777 Sales
2 ABC January, 01 2014 00:00:00+0000 Germany 999 Sales
3 ABC February, 01 2014 00:00:00+0000 Germany 900 Sales
3 ABC February, 01 2014 00:00:00+0000 Germany 900 Sales
4 ABC January, 01 2014 00:00:00+0000 UK 600 Forecast
4 ABC February, 01 2014 00:00:00+0000 UK 444 Sales
5 ABC March, 01 2014 00:00:00+0000 UK 500 Forecast
此查询根据ID
和源(最后一列)返回重复项。
3 ABC February, 01 2014 00:00:00+0000 Germany 900 Sales
3 ABC February, 01 2014 00:00:00+0000 Germany 900 Sales
显然,Sales
行被多个Forecast
重复 - 该模型+月份+国家/地区组合的行。如果Sales
+ Sales
行没有重复项,那么我如何只获得Forecast
行?如果没有Forecast
行,我如何获得Sales
行?
答案 0 :(得分:6)
您的查询问题不在于使用COALESCE
,而在于使用JOIN
。 Forecast
表格中有2行具有Model, Month, Country
的相同组合,ID
2和3的行:
╔════╦═══════╦═════════════════════════╦═════════╦═══════╗
║ ID ║ Model ║ Month ║ Country ║ Count ║
╠════╬═══════╬═════════════════════════╬═════════╬═══════╣
║ 2 ║ ABC ║ 2014-02-01 00:00:00.000 ║ Germany ║ 1100 ║
║ 3 ║ ABC ║ 2014-02-01 00:00:00.000 ║ Germany ║ 900 ║
╚════╩═══════╩═════════════════════════╩═════════╩═══════╝
它们都与ID
表中的行Sales
3连接:
╔════╦═══════╦═════════════════════════╦═════════╦═══════╗
║ ID ║ Model ║ Month ║ Country ║ Count ║
╠════╬═══════╬═════════════════════════╬═════════╬═══════╣
║ 3 ║ ABC ║ 2014-02-01 00:00:00.000 ║ Germany ║ 900 ║
╚════╩═══════╩═════════════════════════╩═════════╩═══════╝
由于您的查询正在使用COALESCE(s.ID, fc.ID)
,因此您在结果中获得了2行ID
3
答案 1 :(得分:5)
Lamak's answer 提供了结果中重复行的原因。这是一个解决方案:
WITH Sales AS
( ... )
, Forecasts AS
( ...)
, Combos AS -- get all distinct
( -- model + month + country
SELECT Model, Month, Country -- combinations
FROM Sales -- from Sales
UNION -- this is UNION DISTINCT
SELECT Model, Month, Country
FROM Forecasts -- and Forecasts
)
SELECT ID = COALESCE(s.ID, f.ID),
c.Model,
c.Month,
c.Country,
Amount = COALESCE(s.Amount, f.Amount),
[Forecast / Sales] = COALESCE(s.[Forecast / Sales],
f.[Forecast / Sales])
FROM Combos c
LEFT JOIN Sales s
ON s.Model = c.Model
AND s.Month = c.Month
AND s.Country = c.Country
LEFT JOIN Forecasts f
ON s.Model IS NULL -- join Forecasts only if there is no Sales
AND f.Model = c.Model
AND f.Month = c.Month
AND f.Country = c.Country
ORDER BY ID, Month, Country, Model ;
测试时间: SQL-Fiddle
答案 2 :(得分:2)
您似乎只想返回整个Sales
集,并使用Forecasts
中未找到的Sales
条目对其进行补充。为此,我可能只使用UNION ALL like this:
WITH Sales AS
(
...
)
, Forecasts AS
(
...
)
SELECT ID, Model, Month, Country, Amount, [Forecast / Sales]
FROM Sales
UNION ALL
SELECT ID, Model, Month, Country, Amount, [Forecast / Sales]
FROM Forecasts
WHERE NOT EXISTS
(
SELECT Model, Month, Country
INTERSECT
SELECT Model, Month, Country
FROM Sales
);