【问题标题】:grouping by date range in t-sql在 t-sql 中按日期范围分组
【发布时间】:2013-07-30 21:54:21
【问题描述】:

我正在尝试对此表进行查询:

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 月的第三行感兴趣)。

我知道我可以在日期上使用最小值和最大值并在金额上使用总和,但我不知道如何以这种方式划分记录。
谢谢!

【问题讨论】:

  • 感谢 Mahmoud Gamal 的编辑。我试图用我的安卓手机问这个问题。
  • 你想根据什么来分组?
  • 看起来你想对连续的零和非零行进行分组,但你为什么不分离出 May 行呢?
  • 他试图为数据创建三个切片 - (1) 没有钱进来 (2) 钱进来 (3) 没有钱再进来。这两个干旱时期将结束资金到账的时间。
  • 基于金额为零和非零的包含日期。

标签: sql sql-server tsql


【解决方案1】:
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

【讨论】:

  • 非常有用的查询。虽然这个返回记录之间的零。
【解决方案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)

还有一秒钟,不使用UNION (fiddle):

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)

【讨论】:

    【解决方案3】:

    应该这样做:

    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)
    

    但是对于这种报告,使用多个查询可能更明确。

    【讨论】:

      【解决方案4】:

      这就是你想要的:

      -- 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
      

      【讨论】:

        【解决方案5】:

        如果您只想查看资金何时开始流入以及何时停止,这可能对您有用:

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

        这不包括没有钱进来的时期。

        【讨论】:

        • 这只是给你第一个开始日期,最后一个结束日期和总金额:link
        • 是的,但正如 OP 所说:“我想得到那个结果,所以我会知道钱什么时候开始进来,什么时候停止”,确实如此。减去前后的空白句点,即:)
        【解决方案6】:

        如果您不关心期间的总数,而只想要从 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

        【讨论】:

          猜你喜欢
          • 2014-10-11
          • 2013-01-07
          • 2013-12-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-04
          • 2021-11-16
          相关资源
          最近更新 更多