2014-02-14 3 views
1

Я использую сервер SQL Server Compact Edition, и я хочу подсчитать количество комментариев в месяц, которые соответствуют определенному учебнику в диапазоне дат, и включают месяцы, которые имеют счет от нуля. Я знаю, что мне нужно присоединиться к таблице «Календарь» к моей таблице, чтобы учесть недостающие месяцы, но мне нужна помощь в правильной реализации этого.Подсчет записей по годам и месяцам, включая нулевые подсчеты

У меня есть таблица всех комментариев из разных учебников. Эта таблица называется Комментарии и требуемые столбцы: [Tutorial] (nvarchar) и [DateAdded] (DateTime).

Tutorial | DateAdded 
---------+------------- 
sample | 2013-09-02 
sample | 2013-09-04 
sample | 2013-09-12 
sample | 2013-09-12 
example | 2013-09-15 
sample | 2013-09-16 
sample | 2013-09-21 
sample | 2013-09-30 
sample | 2013-10-01 
sample | 2013-11-11 
sample | 2013-11-11 
example | 2013-11-14 
sample | 2013-11-15 
sample | 2013-11-19 
sample | 2013-11-21 
sample | 2013-11-25 
sample | 2014-02-04 
sample | 2014-02-06 

И у меня есть Calendar таблицу, которая имеет год и месяц колонки, как так:

Year | Month 
-----+------ 
2000 | 01 
2000 | 02 
. | . 
. | . 
. | . 
2099 | 12 

Если бы я искал для ежемесячного подсчету «образец» комментарии от прошлого года (в с 14 февраля 2014 года), то идеальный результат будет:

Tutorial | Year | Month | Count 
---------+------+-------+------ 
sample | 2013 | 09 | 7 
sample | 2013 | 10 | 1 
sample | 2013 | 11 | 6 
sample | 2013 | 12 | 0 
sample | 2014 | 01 | 0 
sample | 2014 | 02 | 2 

Я был в состоянии понять, как сделать следующий запрос, но мне нужны месяцы, которые не имеют замечаний возвращать 0, как ш флигель.

SELECT 
    Tutorial, 
    datepart(year, DateAdded) AS Year, 
    datepart(month, DateAdded) AS Month, 
    COUNT(*) AS Count From Comments 
WHERE 
    DateAdded > DATEADD(year,-1,GETDATE()) 
     AND 
    Tutorial='sample' 
GROUP BY 
    Tutorial, 
    datepart(year, DateAdded), 
    datepart(month, DateAdded) 

Выход с использованием данных образца сверху.

Tutorial | Year | Month | Count 
---------+------+-------+------ 
sample | 2013 | 09 | 7 
sample | 2013 | 10 | 1 
sample | 2013 | 11 | 6 
sample | 2014 | 02 | 2 

Я знаю, что нужно соединить таблицы, но я не могу показаться, чтобы выяснить, какие присоединиться использовать или как правильно реализовать. Имейте в виду, что это для SQL Server CE, поэтому не все команды SQL Server могут использоваться.

Большое спасибо!

ответ

1

Если у вас есть Calendar стол с Month и Year вы должны попробовать что-то вроде

SELECT t2.Tutorial, t1.[Month], t1.[Year], COALESCE(t2.Number, 0) AS Result 
    FROM Calendar AS t1 LEFT JOIN (
    SELECT 
     Tutorial, 
     CONVERT(NCHAR(6), DateAdded, 112) AS tutDate, 
     COUNT(*) AS Count From Comments 
    WHERE 
     DateAdded > DATEADD(year,-1,GETDATE()) 
     AND 
     Tutorial='sample' 
    GROUP BY 
     Tutorial, 
     CONVERT(NCHAR(6), [Order Date], 112) 
) AS t2 
    ON (t1.[Year] + t1.[Month]) = t2.tutDate 
    ORDER BY t1.[Year] + t1.[Month] 
0

Далее следует отдельный сценарий, который вы можете использовать, чтобы попробовать и не касаться каких-либо ваших реальных объектов базы данных в процессе производства. В нижней трети кода содержится помощь с объединениями, которые вы ищете.

SQL Server CE позволит вам написать хранимую процедуру, которая, в свою очередь, может использоваться как источник отчета. Сохраненные procs хороши, потому что они могут принимать входные параметры, что идеально подходит для ведения отчетов.

-- create dummy Comments table for prototyping 
create table #Comments (
    ID int identity(1,1) not null, 
    Tutorial nvarchar(50) not null, 
    DateAdded datetime not null, 
    primary key clustered(DateAdded,ID,Tutorial) 
); 

-- populate dummy Comments table 
declare @startDate datetime = '2000-01-01'; 
declare @endDate datetime = '2014-02-14'; 
declare @numTxns int = 5000; 

set nocount on; 

declare @numDays int = cast(@endDate as int) - cast(@startDate as int) + 1; 
declare @i int = 1; 
declare @j int = @i + @numTxns; 
declare @rnd float; 
while @i <= @j 
begin 
    set @rnd = RAND(); 
    insert into #Comments (Tutorial,DateAdded) 
    select 
    -- random tutorial titles 
     coalesce (
      case when @rnd < .25 then 'foo' else null end, 
      case when @rnd between .5 and .75 then 'baz' else null end, 
      case when @rnd > .75 then 'qux' else null end, 
      'bar' 
     ) as Tutorial, 
    -- random dates between @startDate and @endDate 
     cast(cast(rand() * @numDays + @startDate as int) as datetime) as DateAdded 
    set @i = @i + 1 
end; 

-- try deleting some months to see what happens 
delete from #Comments 
where DateAdded between '2013-11-01' and '2013-11-30' 
    or DateAdded between '2014-01-01' and '2014-01-31'; 

set nocount off; 
go 

-- ### following could easily be rewritten as a stored procedure 

-- stored procedure parameters 
declare @startDate datetime = '2000-01-01'; 
declare @endDate datetime = '2014-03-31'; 
-- pick only one option below 
--declare @Tutorial nvarchar(50) = 'foo'; -- this only gets data for Tutorials called 'foo' 
declare @Tutorial nvarchar(50) = 'all'; -- this gets data for all tutorials 

-- begin stored procedure code 
set nocount on; 

-- this temp table is an alternative to 
-- creating ***and maintaining*** a table full of dates, 
-- months, etc., and cluttering up your database 
-- in production, it will automatically delete itself 
-- once the user has completed running the report. 
create table #dates (
    DateAdded datetime not null, 
    YearAdded int null, 
    MonthAdded int null, 
    primary key clustered (DateAdded) 
); 

-- now we put dates into #dates table 
-- based on the parameters supplied by 
-- the user running the report 
declare @date datetime = @startDate; 
while @date <= @endDate 
begin 
    insert into #dates 
    select @date, YEAR(@date), MONTH(@date); 

    set @date = @date + 1; 
end; 

-- ## Why put every day of the month in this table? 
-- ## I asked for a monthy report, not daily! 
-- Yes, but looping through dates is easier, simply add 1 for the next date. 
-- You can always build a monthly summary table later if you'd like. 
-- This *is* kind of a brute-force solution, but easy to write. 
-- More answers to this question in the code below, where they'll make more sense. 

set nocount off; 

-- now we return the data to the user 
-- any month with no Tutorials will still show up in the report 
-- but the counts will show as zero 
select YearAdded, MonthAdded, SUM(Count_From_Comments) as Count_From_Comments, 
    SUM(foo) as Count_Foo, SUM(bar) as Count_Bar, 
    SUM(baz) as Count_Baz, SUM(qux) as Count_Qux 
from (
-- ## you can reuse the following code for a detail report by day 
-- ## another answer to 'Why not by month?' from above 
-- start daily report code 
    select t1.DateAdded, t1.YearAdded, t1.MonthAdded, t2.Tutorial, 
      coalesce(Count_From_Comments,0) as Count_From_Comments, 
      case when t2.Tutorial = 'foo' then 1 else 0 end as foo, 
      case when t2.Tutorial = 'bar' then 1 else 0 end as bar, 
      case when t2.Tutorial = 'baz' then 1 else 0 end as baz, 
      case when t2.Tutorial = 'qux' then 1 else 0 end as qux 
    from #dates as t1 -- no where clause needed because #dates only contains the ones we want 
    left join (-- left join here so that we get all dates, not just ones in #Comments 
     select *, 1 AS Count_From_Comments 
     from #Comments 
     where @Tutorial in (Tutorial,'all') 
    ) as t2 
     on t1.DateAdded = t2.DateAdded -- ## join on one field instead of two, another answer to 'Why not by month?' from above 
-- end daily report code 
) as qDetail 
group by YearAdded, MonthAdded 
order by YearAdded, MonthAdded 

-- end stored procedure code 
go 

-- ## Not required in production code, 
-- ## but handy when testing this script. 
drop table #dates; 

-- #### Since this will be a real table in production 
-- #### we definitely only want this for testing! 
drop table #Comments; 

go 

Счастливое кодирование.

+0

Ни одно из этого будет работать с SQL CE – ErikEJ

+0

Так я вижу, спасибо за исправление. –

Смежные вопросы