2013-07-30 124 views
5

我試圖做此表的查詢:分組在T-SQL的日期範圍

Id  startdate  enddate  amount 
1  2013-01-01 2013-01-31  0.00 
2  2013-02-01 2013-02-28  0.00 
3  2013-03-01 2013-03-31  245 
4  2013-04-01 2013-04-30  529 
5  2013-05-01 2013-05-31  0.00 
6  2013-06-01 2013-06-30  383 
7  2013-07-01 2013-07-31  0.00 
8  2013-08-01 2013-08-31  0.00 

我想要得到的輸出:

2013-01-01   2013-02-28   0 
2013-03-01   2013-06-30   1157 
2013-07-01   2013-08-31   0 

我希望得到這一結果所以我會知道什麼時候貨幣開始進入,何時停止。我也對開始進入貨幣前幾個月(這解釋了第一行)以及貨幣停止的月數感興趣(這也解釋了爲什麼我也對2013年7月至2013年8月的第三排感興趣)。

我知道我可以使用的日期最小值和最大值,並在量總結,但我無法弄清楚如何獲得記錄劃分的方式。
謝謝!

+1

感謝編輯馬哈茂德·賈邁勒。我試圖從我的android手機問這個問題。 –

+2

根據你想要做什麼分組? –

+2

它看起來像你想分組連續的行零和非零,但爲什麼你不分出五月行? –

回答

2

這裏有一個想法(和a fiddle用它去):

;WITH MoneyComingIn AS 
(
    SELECT MIN(startdate) AS startdate, MAX(enddate) AS enddate, 
     SUM(amount) AS amount 
    FROM myTable 
    WHERE amount > 0 
) 
SELECT MIN(startdate) AS startdate, MAX(enddate) AS enddate, 
    SUM(amount) AS amount 
FROM myTable 
WHERE enddate < (SELECT startdate FROM MoneyComingIn) 
UNION ALL 
SELECT startdate, enddate, amount 
FROM MoneyComingIn 
UNION ALL 
SELECT MIN(startdate) AS startdate, MAX(enddate) AS enddate, 
    SUM(amount) AS amount 
FROM myTable 
WHERE startdate > (SELECT enddate FROM MoneyComingIn) 

和第二不使用UNIONfiddle):

SELECT MIN(startdate), MAX(enddate), SUM(amount) 
FROM 
(
    SELECT startdate, enddate, amount, 
    CASE 
     WHEN EXISTS(SELECT 1 
        FROM myTable b 
        WHERE b.id>=a.id AND b.amount > 0) THEN 
      CASE WHEN EXISTS(SELECT 1 
          FROM myTable b 
          WHERE b.id<=a.id AND b.amount > 0) 
       THEN 2 
       ELSE 1 
      END 
     ELSE 3 
    END AS partition_no 
    FROM myTable a 
) x 
GROUP BY partition_no 

雖然我想爲寫它假設Id是爲了。你可以用ROW_NUMBER() OVER(ORDER BY startdate)替代它。

+0

+1這些解決方案都不需要使用'UNION'或變量。 – Yuck

+0

沒有UNION的好解決方案。 –

0

如果你想要做的就是看當錢開始在未來,當它停了下來,這可能會爲你工作:

select 
    min(startdate), 
    max(enddate), 
    sum(amount) 
where 
    amount > 0 

這不包括地方沒有錢進來,雖然週期。

+0

這只是給你第一個開始日期,最後結束日期和總金額:[鏈接](http://www.sqlfiddle.com/#!3/c0d17/4) – Sam

+0

是的,但正如OP所說:「我想要爲了得到這個結果,我會知道什麼時候貨幣開始進入和何時停止「,這是。減去之前和之後的空閒時間,即:) –

1

類似的東西應該這樣做:

select min(startdate), max(enddate), sum(amount) from paiements 
    where enddate < (select min(startdate) from paiements where amount >0) 
union 
select min(startdate), max(enddate), sum(amount) from paiements 
    where startdate >= (select min(startdate) from paiements where amount >0) 
    and enddate <= (select max(enddate) from paiements where amount >0) 
union 
select min(startdate), max(enddate), sum(amount) from paiements 
    where startdate > (select max(enddate) from paiements where amount >0) 

但這種報告,它使用多個查詢可能是更加明確。

1

這你想要做什麼:

-- determine the three periods 
DECLARE @StartMoneyIn INT 
DECLARE @EndMoneyIn INT 

SELECT @StartMoneyIn = MIN(Id) 
FROM [Amounts] 
WHERE amount > 0 

SELECT @EndMoneyIn = MAX(Id) 
FROM [Amounts] 
WHERE amount > 0 

-- retrieve the amounts 
SELECT MIN(startdate) AS startdate, MAX(enddate) AS enddate, SUM(amount) AS amount 
FROM [Amounts] 
WHERE Id < @StartMoneyIn 
UNION 
SELECT MIN(startdate), MAX(enddate), SUM(amount) 
FROM [Amounts] 
WHERE Id >= @StartMoneyIn AND Id <= @EndMoneyIn 
UNION 
SELECT MIN(startdate), MAX(enddate), SUM(amount) 
FROM [Amounts] 
WHERE Id > @EndMoneyIn 
4
with CT as 
(
    select t1.*, 
      (select max(endDate) 
      from t 
      where startDate<t1.StartDate and SIGN(amount)<>SIGN(t1.Amount) 
      ) as GroupDate 
    from t as t1 
) 
select min(StartDate) as StartDate, 
     max(EndDate) as EndDate, 
     sum(Amount) as Amount 
from CT 
group by GroupDate 
order by StartDate 

SQLFiddle demo

+0

很有用的查詢。雖然這個返回了零之間的記錄。 –

0

如果你不關心期間總,但只希望你去哪裏從0到的東西記錄你可以做一些像這樣瘋狂的事情:

select * 
from MoneyTable mt 
where exists (select * 
       from MoneyTable mtTemp 
       where mtTemp.enddate = dateadd(day, -1, mt.startDate) 
       and mtTemp.amount <> mt.amount 
       and mtTemp.amount * mt.amount = 0) 

或者如果你必須包括第一個記錄:

select * 
from MoneyTable mt 
where exists (select * 
       from MoneyTable mtTemp 
       where mtTemp.enddate = dateadd(day, -1, mt.startDate) 
       and mtTemp.amount <> mt.amount 
       and mtTemp.amount * mt.amount = 0) 
or not exists (select * 
       from MoneyTable mtTemp 
       where mtTemp.enddate = dateadd(day, -1, mt.startDate)) 

Sql Fiddle