【问题标题】:Find min value and max value from two columns. Generate date from min to max从两列中找到最小值和最大值。生成从 min 到 max 的日期
【发布时间】:2011-12-06 16:14:18
【问题描述】:

我在 SQL Server DB 中有表:

ID    Open_date     Close_date
1     01-01-2010    01-03-2010
2     21-01-2011    12-02-2011
3     01-03-2010    NULL
4     10-01-2010    NULL

我需要做一些将返回的 T-SQL 查询:

Month    Year    Open    Close
01       2010    2       0
02       2010    0       0
03       2010    0       1
04       2010    0       0
05       2010    0       0
06       2010    0       0
07       2010    0       0
08       2010    0       0
09       2010    0       0
10       2010    0       0
11       2010    0       0
12       2010    0       0
01       2011    1       0
02       2011    0       1

结果集中的条目数等于数据库中表的“Open_date”和“Close_date”列的最小值与相同列的最大值之间的月数。问题是如何从两个日期列中找到最小值和最大值,然后生成从最小值到最大值的日期,然后使用这个临时表(或它将是什么)来计算临时表中每个日期的打开和关闭条目数。

【问题讨论】:

  • 您为什么将 ID 计为 2010 年 1 月关闭?
  • 对不起,我的错误。已更正。
  • 我认为 2010 年 3 月的行应该是 1, 1 而不是 0, 1 以反映记录 #3?
  • @Tarwn - 是的,我也看到了记录#3,它应该是 1 Open 和 1 Close

标签: sql sql-server tsql sql-generation


【解决方案1】:

我之前设计了一个示例,但最终没有发布,但回来后还是决定发布它:)

-- Sample Data
CREATE TABLE #SampleVals ( ID int, Open_Date Date, Close_Date Date);
INSERT INTO #SampleVals(ID, Open_Date, Close_Date)
VALUES(1,'20100101','20100301'),
      (2,'20110121','20110212'),
      (3,'20100301', NULL),
      (4,'20100110',NULL);

-- Get Start/End for full date range
DECLARE @Min Date, @Max Date;
SELECT @Min = DateAdd(dd,-1 * Day(MIN(Open_Date)) + 1, MIN(Open_Date)), 
        @Max = MAX(Close_Date)
FROM #SampleVals;

-- Query for values across entire range
WITH DateRange (StartDate,NextDate) AS (
    SELECT DATEADD(MONTH, n-1, @Min),
            DATEADD(MONTH, n, @Min)
    FROM dbo.Number N
    WHERE N.n <= DATEDIFF(MONTH,@Min,@Max) + 1
)
SELECT MONTH(DR.StartDate),
        YEAR(DR.StartDate),
        SUM(CASE WHEN S.Open_Date >= DR.StartDate Then 1 Else 0 END) AS [Open],
        SUM(CASE WHEN S.Close_Date < DR.NextDate Then 1 Else 0 END) AS [Closed]
FROM DateRange DR
    LEFT JOIN #SampleVals S ON S.Open_Date < DR.NextDate 
                            AND (S.Close_Date >= DR.StartDate OR S.Close_Date IS NULL)
GROUP BY DR.StartDate
ORDER BY DR.StartDate;

-- Cleanup sample data
DROP TABLE #SampleVals;

示例数据的日期已更改以反映 yyyymmdd。我还使用了本地数字表:

CREATE TABLE dbo.Number(n INT NOT NULL IDENTITY) ;
GO
SET NOCOUNT ON ;
INSERT dbo.Number DEFAULT VALUES ;
WHILE SCOPE_IDENTITY() < 5000
    INSERT dbo.Number DEFAULT VALUES ;

我几乎没有发布这个,因为 Norla 在我完成这个之前已经完成了它,但我注意到如果开始日期已关闭(以及该开始日期的月份),Norla 的解决方案会填充关闭列,而这个version 填充 close_date 月份的 close month 列,我相信这是您所要求的。

【讨论】:

    【解决方案2】:

    我稍微更改了日期,因为我使用的是不同的日期系统,但这应该可以。如果是,请接受!

    DECLARE @TABLE1 TABLE
    (
        ID INT
        , Open_date DATETIME
        , Close_date DATETIME
    )
    
    INSERT INTO @TABLE1 (ID, Open_date, Close_date)
          SELECT 1, '01-01-2010', '03-01-2010'
    UNION SELECT 2, '01-21-2011', '02-12-2011'
    UNION SELECT 3, '03-01-2010', NULL
    UNION SELECT 4, '01-10-2010', NULL
    
    
    DECLARE @MIN_DATE DATETIME
    DECLARE @MAX_DATE DATETIME
    
    SELECT @MIN_DATE = MIN(d)
        , @MAX_DATE = MAX(d)
    FROM
    (
        SELECT Open_date AS d
        FROM @TABLE1
    
            UNION
    
        SELECT Close_date AS d
        FROM @TABLE1
    )a
    
    --SELECT @MIN_DATE, @MAX_DATE
    
    
    
    DECLARE @DATES TABLE
    (
        ID INT IDENTITY(1,1)
        , [date] DATETIME
    )
    
    DECLARE @DATE DATETIME
    SET @DATE = @MIN_DATE
    
    WHILE (@DATE <= @MAX_DATE)
    BEGIN
    
        INSERT INTO @DATES ([date])
        VALUES (@DATE)
    
        SET @DATE = @DATE + 1
    
    END
    
    --SELECT *
    --FROM @DATES
    
    SELECT MONTH(a.[date]) AS [Month]
        , YEAR(a.[date]) AS [Year]
        , SUM(CASE WHEN b.Open_date IS NOT NULL THEN 1 ELSE 0 END) AS [Open]
        , SUM(CASE WHEN b.Close_date IS NOT NULL THEN 1 ELSE 0 END) AS [Close]
    FROM @DATES a
    LEFT JOIN @TABLE1 b
        ON a.[date] = b.Open_date
    GROUP BY YEAR(a.[date]), MONTH(a.[date])
    ORDER BY YEAR(a.[date]), MONTH(a.[date])
    

    【讨论】:

      【解决方案3】:

      对于 SQL Server 2005+,您可以尝试一个

      somewhat simpler approach. Try this:
      
      WITH CTE AS
      (
          SELECT  MIN(CONVERT(VARCHAR(6),Dates,112)) YearMonth, 
                  MAX(CONVERT(VARCHAR(6),Dates,112)) MaxDate
          FROM (  SELECT Open_Date Dates FROM YourTable
                  UNION 
                  SELECT Close_Date FROM YourTable) A
          UNION ALL
          SELECT CONVERT(VARCHAR(6),DATEADD(MONTH,1,YearMonth+'01'),112), MaxDate
          FROM CTE
          WHERE CONVERT(VARCHAR(6),DATEADD(MONTH,1,YearMonth+'01'),112)<=MaxDate
      )
      SELECT  RIGHT(A.YearMonth,2) [Month], LEFT(A.YearMonth,4) [Year], 
              COUNT(B.Id) [Open], COUNT(C.Id) [Close]
      FROM CTE A
      LEFT JOIN YourTable B
      ON A.YearMonth = CONVERT(VARCHAR(6),B.Open_Date,112) 
      LEFT JOIN YourTable C
      ON A.YearMonth = CONVERT(VARCHAR(6),C.Close_Date,112) 
      GROUP BY RIGHT(A.YearMonth,2), LEFT(A.YearMonth,4)
      ORDER BY LEFT(A.YearMonth,4), RIGHT(A.YearMonth,2)
      

      【讨论】:

        【解决方案4】:

        另一个版本

        ;with T(monthstart, monthend, _tempmax) as (
            select 
                min(Open_date), dateadd(day, -1, dateadd(month, 1, min(Open_date))), dateadd(month, 1, max(Open_date)) as _tempmax from THETABLE
            union all
            select 
                dateadd(month, 1, monthstart), dateadd(day, -1, dateadd(month, 2, monthstart)), _tempmax
            from T
            where dateadd(month, 1, monthstart) <= _tempmax
        )
        select
            month(monthstart) as [month],
            year(monthstart) as [year],
            sum(case when Open_date between monthstart and monthend then 1 else 0 end),
            sum(case when Close_date between monthstart and monthend then 1 else 0 end)
        from T
        left join 
            THETABLE on (Open_date between monthstart and monthend) or (Close_date between monthstart and monthend)
        group by
            month(monthstart),
            year(monthstart)
        

        【讨论】:

          猜你喜欢
          • 2021-02-12
          • 2013-02-15
          • 2021-10-10
          • 2020-12-02
          • 2023-03-25
          • 1970-01-01
          • 2020-06-20
          • 2021-08-05
          • 2023-03-08
          相关资源
          最近更新 更多