【问题标题】:Handling non existent values in sql query expression for ssrs chart处理 ssrs 图表的 sql 查询表达式中不存在的值
【发布时间】:2012-03-13 20:44:29
【问题描述】:

我在 ssrs 折线图中使用以下查询。它根据每个订单日期计算每个月记录的订单数量。

我的问题是,当一个月没有订单时,而不是说零或空,它会一起删除该月的行。我希望它把它算为零,但 null 也可以。

基本上,我希望总是有十二行,无论它们是否包含信息。

我该如何解决这个问题?有什么我可以使用的表达方式吗?还是我遗漏了一些非常明显的东西?

SELECT
MONTH(Ord.OrdDate) AS 'MONTH',
COUNT(CASE WHEN @Worker_ID1 IS NULL OR @Worker_ID1 = Worker.ID THEN 1 END) AS 'Worker1',
COUNT(CASE WHEN @Worker_ID2 IS NULL OR @Worker_ID2 = Worker.ID THEN 1 END) AS 'Worker2',
COUNT(CASE WHEN @Worker_ID3 IS NULL OR @Worker_ID3 = Worker.ID THEN 1 END) AS 'Worker3',
COUNT(CASE WHEN @Worker_ID4 IS NULL OR @Worker_ID4 = Worker.ID THEN 1 END) AS 'Worker4',
COUNT(CASE WHEN @Worker_ID5 IS NULL OR @Worker_ID5 = Worker.ID THEN 1 END) AS 'Worker5'

FROM Ord
JOIN Prod ON Ord.Prod_ID = Prod.ID
JOIN ProdType ON Prod.ProdType_ID = ProdType.ID
JOIN Grouping ON Ord.Grouping_ID = Grouping.ID
JOIN Worker ON Grouping.Worker_ID = Worker.ID

WHERE @Year = YEAR(Ord.OrdDate)
AND (@ProdType_ID IS NULL OR @ProdType_ID = ProdType.ID)

GROUP BY MONTH(Ord.OrdDate)

【问题讨论】:

  • 这不是严格的答案,所以我使用评论。您可以考虑按 MONTH(Ord.OrdDate) 和 Worker.ID 进行分组,然后使用 ssrs-2008 提供的数据透视表(如果我没记错的话,这是一个矩阵报告。)您可以将谓词更改为 AND Worker.ID IN (\ @Worker_ID1、\@Worker_ID2、\@Worker_ID3、\@Worker_ID4、\@Worker_ID5)。如果其中任何一个为 NULL,则它们被隐式地排除在 IN 子句之外。

标签: sql sql-server ssrs-2008 bids


【解决方案1】:

正如上面提到的答案,您将需要一个外部联接和某种日历表。这是未经测试的,但我认为对你有用:

with dateCTE as
(
     select cast('2012-01-01' as datetime) dateValue -- start date
     union all
     select DateAdd(mm, 1, dateValue)
     from    dateCTE   
     where   dateValue < '2012-12-30' -- end date
 )
SELECT
MONTH(dateCTE.dateValue) AS 'MONTH',
COUNT(CASE WHEN @Worker_ID1 IS NULL OR @Worker_ID1 = Worker.ID THEN 1 END) AS 'Worker1',
COUNT(CASE WHEN @Worker_ID2 IS NULL OR @Worker_ID2 = Worker.ID THEN 1 END) AS 'Worker2',
COUNT(CASE WHEN @Worker_ID3 IS NULL OR @Worker_ID3 = Worker.ID THEN 1 END) AS 'Worker3',
COUNT(CASE WHEN @Worker_ID4 IS NULL OR @Worker_ID4 = Worker.ID THEN 1 END) AS 'Worker4',
COUNT(CASE WHEN @Worker_ID5 IS NULL OR @Worker_ID5 = Worker.ID THEN 1 END) AS 'Worker5'

FROM dateCTE
LEFT JOIN Ord on MONTH(dateCTE.datevalue) = MONTH(Ord.OrdDate)
JOIN Prod ON Ord.Prod_ID = Prod.ID
JOIN ProdType ON Prod.ProdType_ID = ProdType.ID
JOIN Groupord ON Ord.Groupord_ID = Groupord.ID
JOIN Worker ON Groupord.Worker_ID = Worker.ID

WHERE (@Year = YEAR(Ord.OrdDate) or ORD.prod_id is null)
AND (@DrugType_ID IS NULL OR @ProdType_ID = ProdType.ID)

GROUP BY MONTH(dateCTE.dateValue)
OPTION  (MAXRECURSION 0)

【讨论】:

  • +1 CTE 非常适合即时生成日期或数字表。
  • @JamieF 太糟糕了,这是硬编码到特定年份的,这有点偏离它。还有一些其他问题 - 例如,如果 SET LANGUAGE FRENCH 和 CTE 返回一个额外的月份(单独运行 CTE,它有 13 个月),则日期格式失败。
  • 这真的只是为了给出想法。 OP 似乎也只过滤了一年的结果,而且由于分组是按月计算的,只要 CTE 中的 1-12 个月,您仍然会得到相同的分组。
  • 这正是我的问题。该表不包含每个月的信息。我需要一些可以按 12 个月分组的东西,即使它们都是空的。
【解决方案2】:

您需要一个包含月份的表才能完成这项工作(或者您可以使用存储过程或可能的公用表表达式)。

SELECT Months.Month, COUNT(Orders.OrderID)
FROM
 Months
LEFT OUTER JOIN
 Orders
ON
 MONTH(Orders.OrderDate) = Months.Month

确保您得到:

Month, Count
1, 1
2, 1
3, 2
4, NULL
etc

【讨论】:

  • 我知道这行得通。但是,我们无权创建新表或存储过程。一切都必须在查询范围内。
  • 那么JOIN (SELECT Month = 1 UNION ALL SELECT 2 UNION ALL SELECT 3...) AS Months?
  • 正确。但这需要是您的“MASTER”表......所以从那个开始,然后加入您的其他表
  • 我已经尝试在这个查询中使用联合,但是当我添加所有需要的功能时,查询是大量的。管理人员讨厌大量查询。我知道,我没有太多选择吗?
【解决方案3】:
;WITH m(m) AS ( SELECT TOP 12 ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.objects )
SELECT [MONTH] = m.m,
  Worker1 = COUNT(CASE WHEN COALESCE(@Worker_ID1, w.ID) = w.ID THEN 1 END),
  Worker2 = COUNT(CASE WHEN COALESCE(@Worker_ID2, w.ID) = w.ID THEN 1 END),
  Worker3 = COUNT(CASE WHEN COALESCE(@Worker_ID3, w.ID) = w.ID THEN 1 END),
  Worker4 = COUNT(CASE WHEN COALESCE(@Worker_ID4, w.ID) = w.ID THEN 1 END),
  Worker5 = COUNT(CASE WHEN COALESCE(@Worker_ID5, w.ID) = w.ID THEN 1 END)
FROM m
LEFT OUTER JOIN dbo.Ord AS o
ON o.OrdDate >= DATEADD(MONTH, m.m-1, RTRIM(@Year)+'0101')
AND o.OrdDate < DATEADD(MONTH, m.m, RTRIM(@Year+'0101')
INNER JOIN dbo.Prod     AS p  ON o.Prod_ID     = p.ID
INNER JOIN dbo.ProdType AS pt ON p.ProdType_ID = pt.ID
INNER JOIN dbo.Grouping AS g  ON o.Grouping_ID = g.ID
INNER JOIN dbo.Worker   AS w  ON g.Worker_ID   = w.ID
WHERE (@DrugType_ID IS NULL OR pt.ID = @ProdType_ID)
GROUP BY m.m
ORDER BY m.m;

【讨论】:

    【解决方案4】:

    通过删除 where 子句并在计数聚合中进行过滤来使其工作。

    SELECT
    MONTH(Ord.OrdDate) AS 'MONTH',
    COUNT(CASE WHEN @Year = YEAR(Ord.OrdDate) AND Worker.ID = @Worker_ID1 AND @ProdType_ID = ProdType.ID THEN 1 END) AS 'Worker1',
    COUNT(CASE WHEN @Year = YEAR(Ord.OrdDate) AND Worker.ID = @Worker_ID2 AND @ProdType_ID = ProdType.ID THEN 1 END) AS 'Worker2',
    COUNT(CASE WHEN @Year = YEAR(Ord.OrdDate) AND Worker.ID = @Worker_ID3 AND @ProdType_ID = ProdType.ID THEN 1 END) AS 'Worker3',
    COUNT(CASE WHEN @Year = YEAR(Ord.OrdDate) AND Worker.ID = @Worker_ID4 AND @ProdType_ID = ProdType.ID THEN 1 END) AS 'Worker4',
    COUNT(CASE WHEN @Year = YEAR(Ord.OrdDate) AND Worker.ID = @Worker_ID5 AND @ProdType_ID = ProdType.ID THEN 1 END) AS 'Worker5'
    
    FROM Ord
    JOIN Grouping ON Ord.Grouping_ID = Grouping.ID
    JOIN Worker ON Grouping.Worker_ID = Worker.ID
    JOIN Prod ON Ord.Prod_ID = Prod.ID
    JOIN ProdType ON Prod.ProdType_ID = ProdType.ID 
    
    GROUP BY MONTH(Ord.OrdDate)
    

    【讨论】:

      【解决方案5】:
      select a.mon,b.* from
      (
      select 1 as mon union select 2 as mon union select 3 as mon union select 4 as mon union 
      select 5 as mon union select 6 as mon union select 7 as mon union select 8 as mon union 
      select 9 as mon union select 10 as mon union select 11 as mon union  select 12 as mon 
      ) a
      left outer join
      (
         your existing query here
      ) b
      on a.mon=b.MONTH(OrdDate)
      go
      

      只需将您的查询复制并粘贴到占位符中即可。 您将始终只获得 12 行。而且也不需要创建任何表格。

      【讨论】:

        【解决方案6】:

        SQL 构造“内连接”很好地定义了该行为。 当连接条件不满足时,使用左连接(或右连接,取决于哪个是正确的一侧)检索空值,如下所示(未测试)

        SELECT
        MONTH(Ord.OrdDate) AS 'MONTH',
        COUNT(CASE WHEN @Worker_ID1 IS NULL OR @Worker_ID1 = Worker.ID THEN 1 END) AS 'Worker1',
        COUNT(CASE WHEN @Worker_ID2 IS NULL OR @Worker_ID2 = Worker.ID THEN 1 END) AS 'Worker2',
        COUNT(CASE WHEN @Worker_ID3 IS NULL OR @Worker_ID3 = Worker.ID THEN 1 END) AS 'Worker3',
        COUNT(CASE WHEN @Worker_ID4 IS NULL OR @Worker_ID4 = Worker.ID THEN 1 END) AS 'Worker4',
        COUNT(CASE WHEN @Worker_ID5 IS NULL OR @Worker_ID5 = Worker.ID THEN 1 END) AS 'Worker5'
        
        FROM Prod 
        LEFT JOIN ORD ON Ord.Prod_ID = Prod.ID
        JOIN ProdType ON Prod.ProdType_ID = ProdType.ID
        JOIN Grouping ON Ord.Grouping_ID = Groupord.ID
        JOIN Worker ON Grouping.Worker_ID = Worker.ID
        
        WHERE ((Ord.OrdDate is not null and @Year = YEAR(Ord.OrdDate)) or ORD.prod_id is null)
        AND (@ProdType_ID IS NULL OR @ProdType_ID = ProdType.ID)
        
        GROUP BY MONTH(Ord.OrdDate)
        

        注意 - 我添加了额外的 where 子句条件来检查 orddate 上的 year 函数,因为这可以为 null

        google for joins SQL,相信您会找到比这更多的优质信息

        希望对你有帮助

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-11-17
          • 1970-01-01
          • 1970-01-01
          • 2015-08-21
          • 1970-01-01
          • 1970-01-01
          • 2020-08-06
          • 1970-01-01
          相关资源
          最近更新 更多