我有一个返回多个值的查询,所有值都围绕“交易类型”分组(可以是卡/现金/支票)。某些值是从内联表构建的。
所有内联表都返回一个公共列,我可以用它将它们连接到我原来的一个表。
但是,在测试期间可能会发现一些内联表可能什么都没有返回,这会破坏我的查询。
例如,一个内联表按transaction_type返回今年的总销售额,另一个内联表按transaction_type返回去年的总销售额。
这两个内联表都按事务类型分组,并通过transaction_type连接到查询的其余部分。
这一切在开发中都运行良好,但在测试过程中我发现,如果我们有一个去年没有销售的新部门(每个部门使用一个单独的数据库),我去年销售收入的内联表什么都没有。
但是因为我在代码中加入了这些内联表,所以我什么都没有加入,我的查询什么也没有返回。
我尝试在内联表中使用LEFT JOIN,当有DATA时,此LEFT JOIN查询也可正常工作。
但是,如果没有来自某些内联表的数据(例如去年没有数据),则左连接查询将永远运行(我在15分钟时将其取消)但原始查询会立即返回所有列但是没有数据。
所以我可以看到问题,我正在尝试加入可能不存在的事情!有谁知道如何解决这个问题?我下班回家途中的想法是返回一个空值并使用COALESCE将其替换为0,但这对我的连接没有帮助,所以我回到了#1。
我希望我提供了足够的信息。
- 原始查询 -
declare @ToDate datetime,
@FromDate datetime,
@StartYear datetime,
@Active datetime
set @ToDate = '30-nov-2010'
set @FromDate = '1-Jan-2010'
set @StartYear = '1-jan-2010'
set @active = '1-jan-2010'
select SUM(th.total_net_retail_central) as 'Net Purchases TY',
IL2.total_sum as 'Net Purchases LY',
IL3.total_sum as 'Net Purchases YTD',
IL6.total_sum as 'Net Purchases YTD (LY)',
tt.Transaction_type_description as 'Channel',
COUNT(DISTINCT th.customer_id) as 'Number of Customers TY',
IL7.total_sum as 'Number of Customers LY',
IL1.Active as 'Number of Active Customers TY',
COUNT(th.transaction_id) as 'Number of Transactions TY',
IL8.total_sum as 'Number of Transactions LY',
IL4.total_sum as 'Total Number of Units TY',
IL5.total_sum as 'Total Number of Units LY'
FROM
(SELECT transaction_type, COUNT(DISTINCT customer_id) as 'Active' from transaction_header
where transaction_date BETWEEN @Active and @ToDate group by transaction_type)IL1,
(SELECT SUM(th.total_net_retail_central) as 'total_sum', th.transaction_type from transaction_header th
where th.transaction_date BETWEEN DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate) GROUP BY th.transaction_type)IL2,
(SELECT SUM(th.total_net_retail_central) as 'total_sum', th.transaction_type FROM transaction_header th
where th.transaction_date BETWEEN @StartYear AND GETDATE() GROUP BY th.transaction_type)IL3,
(SELECT SUM(td.quantity) as 'total_sum', th.transaction_type from transaction_detail td, transaction_header th
where th.transaction_date BETWEEN @FromDate AND @ToDate AND th.transaction_id = td.transaction_id GROUP BY th.transaction_type)IL4,
(SELECT SUM(td.quantity) as 'total_sum', th.transaction_type from transaction_detail td, transaction_header th
where th.transaction_date BETWEEN DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate) AND th.transaction_id = td.transaction_id GROUP BY th.transaction_type)IL5,
(SELECT SUM(th.total_net_retail_central) as 'total_sum', th.transaction_type from transaction_header th
where th.transaction_date BETWEEN DATEADD(yy, -1, @StartYear) AND DATEADD(yy, -1, GETDATE()) GROUP BY th.transaction_type)IL6,
(SELECT COUNT(DISTINCT th.customer_id) as 'total_sum', th.transaction_type from transaction_header th
where th.transaction_date between DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate) GROUP BY th.transaction_type)IL7,
(SELECT COUNT(th.customer_id) as 'total_sum', th.transaction_type from transaction_header th
where th.transaction_date between DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate) GROUP BY th.transaction_type)IL8,
transaction_header th
INNER JOIN
transaction_type tt ON th.transaction_type = tt.transaction_type
WHERE
th.transaction_date Between @FromDate AND @ToDate
AND IL1.transaction_type = th.transaction_type
AND IL2.transaction_type = th.transaction_type
AND IL3.transaction_type = th.transaction_type
AND IL4.transaction_type = th.transaction_type
AND IL5.transaction_type = th.transaction_type
AND IL6.transaction_type = th.transaction_type
AND IL7.transaction_type = th.transaction_type
AND IL8.transaction_type = th.transaction_type
GROUP BY
tt.transaction_type_description, IL1.Active, IL2.total_sum, IL3.total_sum, IL4.total_sum, IL5.total_sum, IL6.total_sum, IL7.total_sum, IL8.total_sum
- 使用左连接查询 -
declare @ToDate datetime,
@FromDate datetime,
@StartYear datetime,
@Active datetime
set @ToDate = '30-nov-2010'
set @FromDate = '1-Jan-2010'
set @StartYear = '1-jan-2010'
set @active = '1-jan-2010'
select SUM(th.total_net_retail_central) as 'Net Purchases TY',
IL2.total_sum as 'Net Purchases LY',
IL3.total_sum as 'Net Purchases YTD',
IL6.total_sum as 'Net Purchases YTD (LY)',
tt.Transaction_type_description as 'Channel',
COUNT(DISTINCT th.customer_id) as 'Number of Customers TY',
IL7.total_sum AS 'Number of Active Customers TY',
IL1.Active AS 'Number of Active Customers TY',
COUNT(th.transaction_id) as 'Number of Transactions TY',
IL8.total_sum as 'Number of Transactions LY',
IL4.total_sum as 'Total Number of Units TY',
IL5.total_sum as 'Total Number of Units LY'
FROM transaction_header th
INNER JOIN transaction_type tt ON th.transaction_type = tt.transaction_type
LEFT JOIN (SELECT transaction_type, COUNT(DISTINCT customer_id) as 'Active' from transaction_header
where transaction_date BETWEEN @Active and @ToDate group by transaction_type)IL1 ON th.transaction_type = IL1.transaction_type
LEFT JOIN (SELECT SUM(th.total_net_retail_central) as 'total_sum', th.transaction_type from transaction_header th
where th.transaction_date BETWEEN DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate) GROUP BY th.transaction_type)IL2 on th.transaction_type = IL2.transaction_type
LEFT JOIN (SELECT SUM(th.total_net_retail_central) as 'total_sum', th.transaction_type FROM transaction_header th
where th.transaction_date BETWEEN @StartYear AND GETDATE() GROUP BY th.transaction_type)IL3 on th.transaction_type = IL3.transaction_type
LEFT JOIN (SELECT SUM(td.quantity) as 'total_sum', th.transaction_type from transaction_detail td, transaction_header th
where th.transaction_date BETWEEN @FromDate AND @ToDate AND th.transaction_id = td.transaction_id GROUP BY th.transaction_type)IL4 on th.transaction_type = IL4.transaction_type
LEFT JOIN (SELECT SUM(td.quantity) as 'total_sum', th.transaction_type from transaction_detail td, transaction_header th
where th.transaction_date BETWEEN DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate) AND th.transaction_id = td.transaction_id GROUP BY th.transaction_type)IL5 on th.transaction_type = IL5.transaction_type
LEFT JOIN (SELECT SUM(th.total_net_retail_central) as 'total_sum', th.transaction_type from transaction_header th
where th.transaction_date BETWEEN DATEADD(yy, -1, @StartYear) AND DATEADD(yy, -1, GETDATE()) GROUP BY th.transaction_type)IL6 on th.transaction_type = IL6.transaction_type
LEFT JOIN (SELECT COUNT(DISTINCT th.customer_id) as 'total_sum', th.transaction_type from transaction_header th
where th.transaction_date between DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate) GROUP BY th.transaction_type)IL7 on th.transaction_type = IL7.transaction_type
LEFT JOIN (SELECT COUNT(th.customer_id) as 'total_sum', th.transaction_type from transaction_header th
where th.transaction_date between DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate) GROUP BY th.transaction_type)IL8 on th.transaction_type = IL8.transaction_type
WHERE
th.transaction_date Between @FromDate AND @ToDate
GROUP BY
tt.transaction_type_description, IL1.Active, IL2.total_sum, IL3.total_sum, IL4.total_sum, IL5.total_sum, IL6.total_sum, IL7.total_sum, IL8.total_sum
答案 0 :(得分:1)
试试这个。它是原始查询的修改版本,使用SQL Server显式JOIN
语法:
您原来的左连接版本上的性能问题可能是由于查询缓存造成的 - 我怀疑这两个版本都很慢,但您一直在运行第一个版本,因此缓存了结果。您运行了第二个,并且没有缓存的结果。
使用INNER JOIN
,如果您有NULL
,则总是会遇到问题,因此您需要使用LEFT JOIN
。如果它仍然永远运行,您需要检查执行计划并查看发生的情况。
declare @ToDate datetime,
@FromDate datetime,
@StartYear datetime,
@Active datetime
set @ToDate = '30-nov-2010'
set @FromDate = '1-Jan-2010'
set @StartYear = '1-jan-2010'
set @active = '1-jan-2010'
select SUM(th.total_net_retail_central) as 'Net Purchases TY',
IL2.total_sum as 'Net Purchases LY',
IL3.total_sum as 'Net Purchases YTD',
IL6.total_sum as 'Net Purchases YTD (LY)',
tt.Transaction_type_description as 'Channel',
COUNT(DISTINCT th.customer_id) as 'Number of Customers TY',
IL7.total_sum as 'Number of Customers LY',
IL1.Active as 'Number of Active Customers TY',
COUNT(th.transaction_id) as 'Number of Transactions TY',
IL8.total_sum as 'Number of Transactions LY',
IL4.total_sum as 'Total Number of Units TY',
IL5.total_sum as 'Total Number of Units LY'
FROM
transaction_header th
LEFT JOIN ( SELECT transaction_type, COUNT(DISTINCT customer_id) as 'Active'
from transaction_header
where transaction_date BETWEEN @Active and @ToDate
group by transaction_type) IL1 ON IL1.transaction_type = th.transaction_type
LEFT JOIN ( SELECT SUM(th.total_net_retail_central) as 'total_sum', th.transaction_type
from transaction_header th
where th.transaction_date BETWEEN DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate)
GROUP BY th.transaction_type) IL2 ON IL2.transaction_type = th.transaction_type
LEFT JOIN ( SELECT SUM(th.total_net_retail_central) as 'total_sum', th.transaction_type
FROM transaction_header th
where th.transaction_date BETWEEN @StartYear AND GETDATE()
GROUP BY th.transaction_type) IL3 ON IL3.transaction_type = th.transaction_type
LEFT JOIN ( SELECT SUM(td.quantity) as 'total_sum', th.transaction_type
from transaction_detail td, transaction_header th
where th.transaction_date BETWEEN @FromDate AND @ToDate AND th.transaction_id = td.transaction_id
GROUP BY th.transaction_type) IL4 ON IL4.transaction_type = th.transaction_type
LEFT JOIN ( SELECT SUM(td.quantity) as 'total_sum', th.transaction_type
from transaction_detail td, transaction_header th
where th.transaction_date BETWEEN DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate) AND th.transaction_id = td.transaction_id
GROUP BY th.transaction_type) IL5 ON IL5.transaction_type = th.transaction_type
LEFT JOIN ( SELECT SUM(th.total_net_retail_central) as 'total_sum', th.transaction_type
from transaction_header th
where th.transaction_date BETWEEN DATEADD(yy, -1, @StartYear) AND DATEADD(yy, -1, GETDATE())
GROUP BY th.transaction_type) IL6 ON IL6.transaction_type = th.transaction_type
LEFT JOIN ( SELECT COUNT(DISTINCT th.customer_id) as 'total_sum', th.transaction_type
from transaction_header th
where th.transaction_date between DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate)
GROUP BY th.transaction_type) IL7 ON IL7.transaction_type = th.transaction_type
LEFT JOIN ( SELECT COUNT(th.customer_id) as 'total_sum', th.transaction_type
from transaction_header th
where th.transaction_date between DATEADD(yy, -1, @FromDate) AND DATEADD(yy, -1, @ToDate)
GROUP BY th.transaction_type) IL8 ON IL8.transaction_type = th.transaction_type
INNER JOIN transaction_type tt ON th.transaction_type = tt.transaction_type
WHERE
th.transaction_date Between @FromDate AND @ToDate
GROUP BY
tt.transaction_type_description, IL1.Active, IL2.total_sum, IL3.total_sum, IL4.total_sum, IL5.total_sum, IL6.total_sum, IL7.total_sum, IL8.total_sum