Sql server 通过TSQL确定一个月内的任意最后一天?

Sql server 通过TSQL确定一个月内的任意最后一天?,sql-server,tsql,sql-server-2000,Sql Server,Tsql,Sql Server 2000,在我处理的每一行数据中,我都有一个日期和一个值: f1 f2 2012-01-01 00:00:00.000 10 2012-01-10 00:00:00.000 9 2012-02-01 00:00:00.000 19 2012-02-15 00:00:00.000 31 使用TSQL,我需要返回包含特定年-月组合的最晚日期的每一行-例如,在上面的数据中,我需要返回第二行和第四行,因为20

在我处理的每一行数据中,我都有一个日期和一个值:

f1                            f2 
2012-01-01 00:00:00.000       10
2012-01-10 00:00:00.000       9
2012-02-01 00:00:00.000       19
2012-02-15 00:00:00.000       31
使用TSQL,我需要返回包含特定年-月组合的最晚日期的每一行-例如,在上面的数据中,我需要返回第二行和第四行,因为2012年10月1日是为2012年1月存储的最晚日期,2012年2月15日是2012年2月记录的最晚日期。预期结果:

f1                            f2 
2012-01-10 00:00:00.000       9
2012-02-15 00:00:00.000       31
请注意,这并不像简单地确定一个月的最后一天或一个月的最后一个工作日那么简单


我怀疑我需要使用某种GROUP BY组合,其中包括datepartday上的最大值f1,但我不知道如何前进。有人能把我推向正确的方向吗?

假设SQL Server 2005或更高版本:

DECLARE @t TABLE (f1 DATETIME, f2 INT);

INSERT @t SELECT '2012-01-01',10
UNION ALL SELECT '2012-01-10',9
UNION ALL SELECT '2012-02-01',19
UNION ALL SELECT '2012-02-15',31;

;WITH x AS 
(
  SELECT f1, f2, ROW_NUMBER() OVER (
   PARTITION BY DATEADD(MONTH, DATEDIFF(MONTH, 0, f1), 0) 
   ORDER BY f1 DESC) AS rn
  FROM @t
)
SELECT f1, f2 FROM x
WHERE rn = 1;

假设SQL Server 2005或更高版本:

DECLARE @t TABLE (f1 DATETIME, f2 INT);

INSERT @t SELECT '2012-01-01',10
UNION ALL SELECT '2012-01-10',9
UNION ALL SELECT '2012-02-01',19
UNION ALL SELECT '2012-02-15',31;

;WITH x AS 
(
  SELECT f1, f2, ROW_NUMBER() OVER (
   PARTITION BY DATEADD(MONTH, DATEDIFF(MONTH, 0, f1), 0) 
   ORDER BY f1 DESC) AS rn
  FROM @t
)
SELECT f1, f2 FROM x
WHERE rn = 1;

正如其他人指出的那样,这假设f1的值在集合中是不同的

SELECT
    MaxValues.f1,
    Detail.f2
FROM
    (
    SELECT
        DATEPART(year, f1),
        DATEPART(month, f1),
        MAX(f1) AS f1
    FROM
        MyTable
    GROUP BY
        DATEPART(year, f1),
        DATEPART(month, f1)
    ) AS MaxValues
    INNER JOIN MyTable AS Detail ON
        Detail.f1 = MaxValues.f1

正如其他人指出的那样,这假设f1的值在集合中是不同的

SELECT
    MaxValues.f1,
    Detail.f2
FROM
    (
    SELECT
        DATEPART(year, f1),
        DATEPART(month, f1),
        MAX(f1) AS f1
    FROM
        MyTable
    GROUP BY
        DATEPART(year, f1),
        DATEPART(month, f1)
    ) AS MaxValues
    INNER JOIN MyTable AS Detail ON
        Detail.f1 = MaxValues.f1
或更少

SELECT f1, f2 
FROM (SELECT f1, f2, MAX(f1) OVER(PARTITION BY YEAR(f1), MONTH(f1)) AS f3 FROM @t) t
WHERE f1 = f3
或更少

SELECT f1, f2 
FROM (SELECT f1, f2, MAX(f1) OVER(PARTITION BY YEAR(f1), MONTH(f1)) AS f3 FROM @t) t
WHERE f1 = f3


请指定您正在使用哪个版本的SQL Server。在给定日期,您的源代码中是否有多行?@JohnDewey提出了一个很好的观点-如果第3行和第4行的日期相同,您希望如何打破僵局?您需要告诉SQL Server您想要哪一行,即使您不在乎,否则每次运行查询时可能会得到不同的结果。先生们,我已经为您提供了架构的简化版本-在现实世界中,还有另一个字段,我们称之为客户ID,它将唯一地显示日期。因此,对于每个CustomerID,我们只会看到一个日期出现一次。只要我们在CustomerID上分组,就不用担心领带了。Aaron-gulp…SQL 2000。别笑……好吧,笑一笑,但要友善:请指定您使用的SQL Server版本。在给定日期,您的源代码中是否有多行?@JohnDewey提出了一个很好的观点-如果第3行和第4行都有相同的日期,您希望如何打破这种局面?您需要告诉SQL Server您想要哪一行,即使您不在乎,否则每次运行查询时可能会得到不同的结果。先生们,我已经为您提供了架构的简化版本-在现实世界中,还有另一个字段,我们称之为客户ID,它将唯一地显示日期。因此,对于每个CustomerID,我们只会看到一个日期出现一次。只要我们在CustomerID上分组,就不用担心领带了。Aaron-gulp…SQL 2000。不要笑…好吧,笑一点,但要友善:按DATEADDMONTH、DATEDIFFMONTH、0、f1、0划分。。。可以通过DATEDIFFMONTH、0、f1…减少到分区,但这仍然是正确的想法+1@t-clausen.dk这是一个很好的观点,我习惯于将两者都包括在内,因为太多次我不得不回答为什么我只在一个整数上分组-按DATEADDMONTH、DATEDIFFMONTH、0、f1、0划分的分区。。。可以通过DATEDIFFMONTH、0、f1…减少到分区,但这仍然是正确的想法+1@t-clausen.dk这是一个很好的观点,我习惯于将两者都包括在内,因为太多次我不得不回答为什么我只在一个整数上分组-我认为这会很好地工作,因为我的同事仍然在2K上运行……我记得,2000确实支持这样的嵌套子查询。@RussellChristopher-我相信在以后的版本中,这可能会得到优化,以删除联接。@RussellChristopher感谢您的接受。顺便说一句,我接受了你关于will的评论,作为一个家伙…仍然在2K上运行,这意味着这可能是某种不推荐的功能。这是一个普通的派生表,大多数RDBMS都支持它。弱者才不会。这个语法在MSSQL服务器中工作,因为我记得,这是一个很长的时间。它不仅在2000年起作用,而且在2005年、2008年和2008年也起作用。它也不是嵌套的。我认为这会很好地工作,因为我的同事仍然在2K上运行……我记得,2000确实支持这样的嵌套子查询。@RussellChristopher-我相信在以后的版本中,这可能会得到优化,以删除联接。@RussellChristopher感谢您的接受。顺便说一句,我接受了你关于will的评论,作为一个家伙…仍然在2K上运行,这意味着这可能是某种不推荐的功能。这是一个普通的派生表,大多数RDBMS都支持它。弱者才不会。这个语法在MSSQL服务器中工作,因为我记得,这是一个很长的时间。它不仅在2000年起作用,而且在2005年、2008年和2008年也起作用。它也不是嵌套的。