2009-08-05 58 views
0

我有一個稱爲註冊記憶具有以下字段表:擺脫不需要的sql子查詢的最佳方法?

  • 標識
  • DateStarted(不爲空)
  • DateCompleted(可爲空的)

我有一個條形圖,其顯示了編號的註冊按日期開始和完成。 我的查詢是這樣的:

; 
WITH Initial(DateStarted, StartCount) 
as (
    select Datestarted, COUNT(*) 
    FROM Registrations 
    GROUP BY DateStarted  
) 
select I.DateStarted, I.StartCount, COUNT(DISTINCT R.RegistrationId) as CompleteCount 
    from Initial I 
     inner join Registrations R 
      ON (I.DateStarted = R.DateCompleted) 
    GROUP BY I.DateStarted, I.StartCount 

它返回一個表,看起來像:

DateStarted StartCount CompleteCount 
2009-08-01 1033  903 
2009-08-02 540   498 

查詢只是有這些代碼味道的問題之一。什麼是更好的方式來做到這一點?

+0

是否有可能DateCompleted是註冊時不存在記錄的日期?例如在沒有07/31的記錄作爲開始日期的情況下是否可以有記錄,但該日期的註冊是否完成? – shahkalpesh 2009-08-05 02:59:20

+0

如果我理解正確,那麼「CompleteCount」列不應該是過去有多少註冊可能已開始並已完成數據,而是有多少個註冊在某個日期開始(「StartCount」列)也於當天完成。如果這不正確,請澄清。 --thnx – RBarryYoung 2009-08-05 17:28:42

+0

(即在同一天開始和完成的人數) – RBarryYoung 2009-08-05 17:29:25

回答

1

編輯:那麼爲什麼不會在下面的工作?如果您希望將計數設置爲零而不是空值,則可以在最後一個選擇語句中的計數週圍引發coalesce()語句。它還包括已完成(或在下面的示例中結束)註冊日期,即使該日期尚未開始註冊。


我假設下面的表結構(大致)。

create table temp 
(
    id int, 
    start_date datetime, 
    end_date datetime 
) 

insert into temp values (1, '8/1/2009', '8/1/2009') 
insert into temp values (2, '8/1/2009', '8/2/2009') 
insert into temp values (3, '8/1/2009', null) 
insert into temp values (4, '8/2/2009', '8/2/2009') 
insert into temp values (5, '8/2/2009', '8/3/2009') 
insert into temp values (6, '8/2/2009', '8/4/2009') 
insert into temp values (7, '8/4/2009', null) 

然後你可以做下面的事情來得到你想要的。

with start_helper as 
(
    select start_date, count(*) as count from temp group by start_date 
), 

end_helper as 
(
    select end_date, count(*) as count from temp group by end_date 
) 

select coalesce(a.start_date, b.end_date) as date, a.count as start_count, b.count as end_count 
from start_helper a full outer join end_helper b on a.start_date = b.end_date 
where coalesce(a.start_date, b.end_date) is not null 

我認爲完全外部聯接是必要的,因爲創紀錄的今天可以完成的,昨天開始,但我們可能還沒有開始今天的新紀錄,所以你會從結果失去了一天。

0

我沒有看到問題。我看到使用了一個通用表格表達式。


你沒有提供表的DDL,所以我不打算重現這一點。不過,我認爲你可以直接用SELECT代替Initial。

1

副手,我覺得這個做的:

SELECT 
    DateStarted 
    , COUNT(*) as StartCount 
    , SUM(CASE 
     WHEN DateCompleted = DateStated THEN 1 
     ELSE 0 END 
     ) as CompleteCount 

FROM Registration 

GROUP BY DateStarted 

OK,顯然我錯了之前所擁有的要求。鑑於CompleteCounts獨立於起始日期的,那麼這是我會怎麼做:

;WITH StartDays AS 
(
    SELECT DateStarted 
    , Count(*) AS CompleteCount 
    FROM Registration 
    GROUP BY DateStarted 
) 
, CompleteDays AS 
(
    SELECT DateCompleted 
    , Count(*) AS StartCount 
    FROM Registration 
    GROUP BY DateCompleted 
) 
SELECT 
    DateStarted 
    , COALESCE(StartCount, 0) AS StartCount 
    , COALESCE(CompleteCount, 0) AS CompleteCount 

FROM StartDays 
FULL OUTER JOIN CompleteDays ON DateStarted = DateCompleted 

這實際上是非常接近你有什麼。

0

我相信下面是在功能上是否有什麼相同:

select DS.DateStarted 
    , count(distinct DS.RegistrationId) as StartCount 
    , count(distinct DC.RegistrationId) as CompleteCount 
from Registrations DS 
inner join Registrations DC on DS.DateStarted = DC.DateCompleted 
group by Ds.DateStarted 

我有點在結果的列DateStarted的名稱混淆。它看起來只是一些事情的開始和一些事情的結束。計數是當天開始和完成的數量或註冊。

內部連接將丟棄任何有0個開始或0個完成的日期。要獲得所有:

select coalesce(DS.DateStarted, DC.DateCompleted) as "Date" 
    , count(distinct DS.RegistrationId) as StartCount 
    , count(distinct DC.RegistrationId) as CompleteCount 
from Registrations DS 
full outer join Registrations DC on DS.DateStarted = DC.DateCompleted 
group by Ds.DateStarted, DC.DateCompleted 

如果你想包括日期既不是DateStarted也不DateCompleted,用0和0計數,則需要日期的來源,我認爲這將是更清晰的使用兩個相關select子句中的子查詢,而不是連接和計數不同:

select DateSource."Date" 
    , (select count(*) 
     from Registrations 
     where DateStarted = DateSource."Date") as StartCount 
    , (select count (*) 
     from Registrations 
     where DateCompleted = DateSource."Datge") as CompleteCount 
from DateSource -- implementation of date source left as exercise 
where DateSource.Date between @LowDate and @HighDate