表示不存在的行或空行

时间:2012-02-22 16:01:11

标签: sql-server-2008 ssrs-2008

我需要能够使用TSQL在SSRS 2008中提取数据集的行。我使用了三个表productstockcallsproduct的综合密钥为mfgpart_number,其他两个表中的字段为foreign keyscalls表创建一行,该行对特定月份的呼叫数进行求和,并以yyyymm格式表示月份。我想要做的是提取每个部分的最后一个电话,但我想忽略当前月份,所以我有这个:

select product.mfg, product.part_number, max(calls.yyyymm) last_call
from product inner join stock on product.mfg = stock.mfg 
and product.part_number = stock.part_number
left join calls on product.mfg = calls.mfg 
and product.part_number = calls.part_number
where stock.onhand > 0 and calls.yyyymm < '201202'

这项工作正常,但大约有65条记录,其中唯一的通话是'201202'

我尝试过nullif(max(calls.yyyymm), null)而不是max(calls.yyyymm)。我认为左calls表的连接将完成它,但它似乎没有。我还在select中尝试了一些case语句的变体,即:

case when max(calls.yyyymm) is not null then max(calls.yyyymm) else null end

我最终想要做的是创建两个数据集,一个用于库存零件,一个用于库存零件中的调用,然后使用SSRS 2008中的查找功能创建报告,但我希望两个集合都生成相同的行数,因为这是一个移动目标。这不是我喜欢的方式,但是我们的零件经理要求我在每个月末尝试冻结数据,这就是为什么我决定尝试忽略当前月份的所有通话。对于当前月份的每个调用,我想使用下一个调用(如果存在),如果不存在,则插入null。

这是一个非常小的数据示例,我认为涵盖了所有变体。

use tempdb;
GO
CREATE TABLE dbo.product(mfg VARCHAR(32), part_number CHAR(5))

INSERT dbo.product SELECT 'mfg1','12345';
INSERT dbo.product SELECT 'mfg2','98765';
INSERT dbo.product SELECT 'mfg3','A1234';
INSERT dbo.product SELECT 'mfg4','5678A';

CREATE TABLE dbo.stock(mfg VARCHAR(32), part_number CHAR(5), onhand INT);

INSERT dbo.stock SELECT 'mfg1','12345',30;
INSERT dbo.stock SELECT 'mfg2','98765', 1;
INSERT dbo.stock SELECT 'mfg3','A1234', 9;
INSERT dbo.stock SELECT 'mfg4','5678A', 0;

CREATE TABLE dbo.calls(mfg VARCHAR(32), part_number CHAR(5), yyyymm CHAR(6));

INSERT dbo.calls SELECT 'mfg1','12345','201101';
INSERT dbo.calls SELECT 'mfg1','12345','201202';
INSERT dbo.calls SELECT 'mfg2','98765','201202';

当前结果集:

mfg       part_number          last_call
mfg1      12345                 201101
mfg3      A1234                 NULL

我想要的是什么:

mfg        part_number         last_call
mfg1       12345               201101
mfg2       98765               NULL
mfg3       A1234               NULL

2 个答案:

答案 0 :(得分:1)

认为它只需要:

SELECT p.mfg, p.part_number, last_call = max(c.yyyymm)
  FROM dbo.product AS p
  INNER JOIN dbo.stock AS s
    ON p.mfg = s.mfg AND p.part_number = s.part_number
  LEFT OUTER JOIN dbo.calls AS c
    ON p.mfg = c.mfg AND p.part_number = c.part_number
    AND c.yyyymm < '201202' -- only change
WHERE s.onhand > 0;

为什么呢?因为将外连接条件移动到where子句会将外连接转换为内连接。

答案 1 :(得分:1)

您使用的WHERE子句要求calls.yyyymm不是NULL:

select product.mfg, product.part_number, max(calls.yyyymm) last_call 
  from product inner join
    stock on product.mfg = stock.mfg and product.part_number = stock.part_number left join
    calls on product.mfg = calls.mfg and product.part_number = calls.part_number 
    where stock.onhand > 0 and calls.yyyymm < '201202'

如果将WHERE子句中的那部分移动到JOIN条件,它应该理顺:

select product.mfg, product.part_number, max(calls.yyyymm) last_call 
  from product inner join
    stock on product.mfg = stock.mfg and product.part_number = stock.part_number left join
    calls on product.mfg = calls.mfg and product.part_number = calls.part_number and calls.yyyymm < '201202'
    where stock.onhand > 0