如何不加入内联表或如果结果集为空则返回NULL值

时间:2010-11-16 20:05:32

标签: sql sql-server

我有一个返回多个值的查询,所有值都围绕“交易类型”分组(可以是卡/现金/支票)。某些值是从内联表构建的。

所有内联表都返回一个公共列,我可以用它将它们连接到我原来的一个表。

但是,在测试期间可能会发现一些内联表可能什么都没有返回,这会破坏我的查询。

例如,一个内联表按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

1 个答案:

答案 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