选择具有已知行数的报表查询

时间:2014-04-18 12:41:22

标签: sql sql-server select

我为报告编写了一个选择查询,该查询可以获取一年中数月的计数。结果表看起来像..

rep_name    month    year    count
----------------------------------
 repo1       1       2013     5
 repo1       4       2013     6
 repo1       12      2013     18
 repo1       2      2014     20   
   .
   .

等等。在我的案例中,所需的输出是一个表格,显示所有月份的记录。即使没有可用的数据,也需要显示计数为0的记录,如

rep_name    month    year    count
----------------------------------
 repo1       1       2013     5
 repo1       2       2013     0
 repo1       3       2013     0
 repo1       4       2013     6
 repo1       5       2013     0
 repo1       6       2013     0
 repo1       7       2013     0
 repo1       8       2013     0
 repo1       9       2013     0
 repo1       10      2013     0
 repo1       11      2013     0
 repo1       12      2013     18
   . 
   .
   .

之前有过类似的查询,但数据集限制为3。 select statement to always return 3 rows on execution

在这种情况下,我无法确定会显示多少个月。这取决于可用的数据。

2 个答案:

答案 0 :(得分:4)

好吧你想要做的就是自己Calendar Table这些非常有用,每个数据库都应该有一个。关于该链接断开的可能性是包含的脚本。

/** Create Date Dimension Table **/
/* Create First numbers table for key generation */
CREATE TABLE Numbers_Small (Number INT);

INSERT INTO Numbers_Small
VALUES (0)
    ,(1)
    ,(2)
    ,(3)
    ,(4)
    ,(5)
    ,(6)
    ,(7)
    ,(8)
    ,(9);
GO

/* Create Second numbers table for key generation */
CREATE TABLE Numbers_Big (Number_Big BIGINT);

INSERT INTO Numbers_Big (Number_Big)
SELECT (tenthousands.number * 10000 + thousands.number * 1000 + hundreds.number * 100 + tens.number * 10 + ones.number) AS number_big
FROM numbers_small tenthousands
    ,numbers_small thousands
    ,numbers_small hundreds
    ,numbers_small tens
    ,numbers_small ones;
GO

/* Create Date Dimension Table */
CREATE TABLE [dbo].[DimDate] (
    [DateKey] [int] NOT NULL
    ,[Date] [datetime] NOT NULL
    ,[Day] [char](10) NULL
    ,[DayOfWeek] [smallint] NULL
    ,[DayOfMonth] [smallint] NULL
    ,[DayOfYear] [smallint] NULL
    ,[PreviousDay] [datetime] NULL
    ,[NextDay] [datetime] NULL
    ,[WeekOfYear] [smallint] NULL
    ,[Month] [char](10) NULL
    ,[MonthOfYear] [smallint] NULL
    ,[QuarterOfYear] [smallint] NULL
    ,[Year] [int] NULL
    );
GO

/* Create Date Key and Date Fields */
INSERT INTO [DimDate] (
    DateKey
    ,DATE
    )
SELECT number_big
    ,DATEADD(day, number_big, '1900-01-01') AS DATE
FROM numbers_big
WHERE DATEADD(day, number_big, '1900-01-01') BETWEEN '1900-01-01'
        AND '2030-12-31'
ORDER BY number_big;
GO

/* Update all other fields with appropriate data. */
UPDATE [DimDate]
SET Day = DATENAME(DW, DATE)
    ,DayOfWeek = DATEPART(WEEKDAY, DATE)
    ,DayOfMonth = DAY(DATE)
    ,DayOfYear = DATEPART(DY, DATE)
    ,PreviousDay = DATEADD(DAY, - 1, DATE)
    ,NextDay = DATEADD(DAY, 1, DATE)
    ,WeekOfYear = DATEPART(WK, DATE)
    ,Month = DATENAME(MONTH, DATE)
    ,MonthOfYear = MONTH(DATE)
    ,QuarterOfYear = DATEPART(Q, DATE)
    ,Year = YEAR(DATE);
GO

/* Drop Temp Tables */
DROP TABLE Numbers_Small;

DROP TABLE Numbers_Big;

所以,现在添加了该表后,只需在月份上为您的DimDate表格执行LEFT JOIN,然后就可以了。

答案 1 :(得分:1)

此代码从源表中动态提取 min max 日期,然后递归生成日期介于 min max之间的表格日期,最后使用生成的日期加入源表。没有更新,插入,DDL等 - 一个CTE:)

/*
-- generating fake #your_table
select * into #your_table
from (values 
    ('repo1', 1, 2013, 5),
    ('repo1', 4, 2013, 6),
    ('repo1', 12, 2013, 18),
    ('repo1', 2, 2014, 20)) as your_table(rep_name, [month], [year], [count]);
*/


with min_max_days as (
    select min(dateadd(day, -1, dateadd(year, [year]-1900, dateadd(month, [month], '1900-01-01')))) [min_day]
    , max(dateadd(day, -1, dateadd(year, [year]-1900, dateadd(month, [month], '1900-01-01')))) [max_day] from #your_table),

[base] as (
select (select year([min_day]) from min_max_days) [year], (select month([min_day]) from min_max_days) [month], (select [min_day] from min_max_days) [date]
union all
select year(dateadd(month, 1, [date])) [year], month(dateadd(month, 1, [date])) [month], dateadd(month, 1, [date])
from [base]
where [date] < (select [max_day] from min_max_days))

select isnull(t.rep_name, 'repo1') [rep_name]
, b.[month]
, b.[year]
, isnull(t.[count], 0) [count]
from [base] b
left join #your_table t on b.[year] = t.[year]
    and b.[month] = t.[month];

<强>输出

rep_name    month   year    count
--------------------------------
repo1       1       2013    5
repo1       2       2013    0
repo1       3       2013    0
repo1       4       2013    6
repo1       5       2013    0
repo1       6       2013    0
repo1       7       2013    0
repo1       8       2013    0
repo1       9       2013    0
repo1       10      2013    0
repo1       11      2013    0
repo1       12      2013    18
repo1       1       2014    0
repo1       2       2014    20

请查看SQL Fiddle