1

SQL 服务器 2005

我有一个 SQL 函数 (ftn_GetExampleTable),它返回一个包含多个结果行的表

EXAMPLE

ID    MemberID MemberGroupID   Result1    Result2 Result3 Year Week
1     1        1               High Risk  2       xx      2011 22
2     11       4               Low Risk   1       yy      2011 21 
3     12       5               Med Risk   3       zz      2011 25
etc.

现在我在上面的表格上为结果 2 进行计数和分组,所以我得到

SELECT MemberGroupID, Result2, Count(*) AS ExampleCount, Year, Week 
FROM ftn_GetExampleTable 
GROUP BY MemberGroupID, Result2, Year, Week

MemberGroupID  Result2  ExampleCount Year Week
1              2        4            2011 22
4              1        2            2011 21
5              3        1            2011 25

现在想象一下,当我在 2011 年第 20 周和第 23 周之间绘制这个新表时,您会看到它不会在这个示例中绘制 20 或 23 或某些组甚至某些结果,因为它们不在包含的数据中,所以我需要将“错误数据”插入此表中,该表具有所有可能性,因此即使计数为 0,它们至少会显示在图表上,这有意义吗?

我想知道最简单和最动态的方式,因为它可能是我想要绘制的 Result1 或 Result3(不同的列类型)。

提前致谢

4

2 回答 2

2

看起来您的维度是:MemberGroupIDResult2和周(YearWeek)。

解决此问题的一种方法是生成所有维度所需的所有值的列表,并生成它们的笛卡尔积。举个例子,

SELECT m.MemberGroupID, n.Result2, w.Year, w.Week
  FROM (SELECT MemberGroupID FROM ftn_GetExampleTable GROUP BY MemberGroupID) m
 CROSS
  JOIN (SELECT Result2       FROM ftn_GetExampleTable GROUP BY Result2      ) n
 CROSS
  JOIN (SELECT Year, Week FROM myCalendar WHERE ... ) w

您不一定需要名为 myCalendar 的表。(这种方法似乎很流行。)您只需要一个行源,您可以从中派生一个 (Year, Week) 元组列表。(在 Stackoverflow 的其他地方有问题的答案,如何生成日期列表。)

MemberGroupID 和 Result2 值的列表不必来自 ftn_GetExampleTable 行源,您可以替换另一个查询。

有了这些维度的笛卡尔积,你就有了一个完整的“网格”。现在您可以 LEFT JOIN 您的原始结果集。

在“gappy”结果查询中没有匹配行的任何地方,都会返回 NULL。您可以保留 NULL,或将其替换为 0,如果它是您要返回的“计数”,这可能是您想要的。

SELECT d.MemberGroupID
     , d.Result2
     , d.Year
     , d.Week
     , IFNULL(r.ExampleCount,0) as ExampleCount
  FROM ( <dimension query from above> ) d
  LEFT
  JOIN ( <original ExampleCount query> ) r
    ON r.MemberGroupID  = d.MemberGroupID
    AND r.Result2       = d.Result2
    AND r.Year          = d.Year
    AND r.Week          = d.Week

可以重构该查询以使用公用表表达式,这使查询更易于阅读,尤其是在您包含多个度量时。

; WITH d AS ( /* <dimension query with no gaps (example above)> */ 
       )
     , r AS ( /* <original query with gaps> */
              SELECT MemberGroupID, Result2, Count(*) AS ExampleCount, Year, Week
              FROM ftn_GetExampleTable
              GROUP BY MemberGroupID, Result2, Year, Week
       )
SELECT d.*
     , IFNULL(r.ExampleCount,0)
  FROM d
  LEFT 
  JOIN r 
    ON r.Year=d.Year AND r.Week=d.Week AND r.MemberGroupID = d.MemberGroupID
       AND r.Result2 = d.Result2

这不是您问题的完整有效解决方案,但它概述了您可以使用的方法。

于 2012-06-22T14:02:29.617 回答
0

每当我需要在 SQL-Server 中生成序列时,我都会使用该sys.all_objects表和ROW_NUMBER函数,然后根据需要对其进行操作:

SELECT  ROW_NUMBER() OVER(ORDER BY Object_ID) AS Sequence
FROM    Sys.All_Objects

因此,对于年份和周数列表,我将使用:

DECLARE @StartDate  DATETIME,
        @EndDate    DATETIME
SET @StartDate = '20110101'
SET @EndDate = '20120601'

SELECT  DATEPART(YEAR, Date) AS YEAR,
        DATEPART(WEEK, Date) AS WeekNum
FROM    (   SELECT  DATEADD(WEEK, ROW_NUMBER() OVER(ORDER BY Object_ID) - 1, @StartDate) AS Date
            FROM    Sys.All_Objects
        ) Dates
WHERE   Date < @endDate

日期子查询在开始日期和结束日期之间以一周的间隔提供日期列表。

因此,在您的示例中,最终结果将类似于:

DECLARE @StartDate  DATETIME,
        @EndDate    DATETIME
SET @StartDate = '20110101'
SET @EndDate = '20120601'

;WITH Data AS
(   SELECT  MemberGroupID, 
            Result2, 
            Count(*) AS ExampleCount, 
            Year, 
            Week 
    FROM    ftn_GetExampleTable 
    GROUP BY MemberGroupID, Result2, Year, Week
), Dates AS
(   SELECT  DATEPART(YEAR, Date) AS YEAR,
            DATEPART(WEEK, Date) AS WeekNum
    FROM    (   SELECT  DATEADD(WEEK, ROW_NUMBER() OVER(ORDER BY Object_ID) - 1, @StartDate) AS Date
                FROM    Sys.All_Objects
            ) Dates
    WHERE   Date < @endDate
)
SELECT  YearNum, 
        WeeNum, 
        MemberID, 
        Result2, 
        COALESCE(ExampleCount, 0) AS ExampleCount
FROM    Dates
        LEFT JOIN Data
            ON YearNum = Data.Year
            AND WeekNum = Data.Week
于 2012-06-22T08:24:09.170 回答