【问题标题】:Finding Median of Dates in SQL Server 2008在 SQL Server 2008 中查找日期的中位数
【发布时间】:2015-02-11 11:15:18
【问题描述】:

我正在寻找一种方法来获取一堆开始日期和结束日期(很多和很多日期)的中位数。但是,它将特定于各种“发票编号”。请参阅下面的示例数据。

 invoice_no   invoice start date      invoice end date
 4006            11/14/2001               12/15/2004
 20071  11/29/2001               02/01/2003
 19893  11/30/2001               12/02/2001
 19894  11/30/2001               12/04/2001
 004             10/22/2002               10/31/2002

求开始日期和结束日期之间的中位数。

中位数将是该特定 invoice_no 的开始日期和结束日期之间的任何值。但是,为了尽可能多地过滤数据。我意识到我也可以做 WHERE STATUS 'REJECTED' 并且它也应该有助于避免很多不必要的日期。另外,我只想在几个月之间过滤,所以我也添加了 BETWEEN DATETIME。

到目前为止的代码:

 与
    时间间隔
    (
        选择发票编号,
                invoice_start_date、invoice_end_date、check_date、status_code、
                cast(count(*) OVER (PARTITION BY invoice_no) as float) 总计,
                row_number() OVER (PARTITION BY invoice_no ORDER BY invoice_start_date, invoice_end_date, check_date) AS rn
        FROM INVOICE_HEADER INNER JOIN
                      INVOICE_HEADER_CUSTOM ON INVOICE_HEADER.invoice_id = INVOICE_HEADER_CUSTOM.invoice_id

                  WHERE status_code <> 'REJECTED' AND 

Check_Date BETWEEN CONVERT(DATETIME, '2014-12-01 00:00:00', 102) AND CONVERT(DATETIME, '2014-12-31 00:00:00', 102) )

SELECT * FROM tmp WHERE (total / 2.0 - 1) < rn and rn < (total / 2.0 + 1)

【问题讨论】:

    标签: sql sql-server-2008 date median


    【解决方案1】:

    您很接近,只是在您的 count 语句中错过了 PARTITION BY 子句。

    WITH
        tmp AS
        (
            SELECT invoice_no,
                    dates,
                    cast(count(*) OVER (PARTITION BY invoice_no) as float) AS total,
                    row_number() OVER (PARTITION BY invoice_no ORDER BY dates) AS rn
            FROM    INVOICE_HEADER
        )
    
    
    SELECT *
    FROM tmp
    WHERE (total / 2.0 - 1) < rn
        and rn < (total / 2.0 + 1)
    

    【讨论】:

    • 嗨,谢谢。所以我在自己的工作中犯了一个错误——实际上有一个“invoice_start_date”和“invoice_end_date”——实际上我正在寻找这两个日期之间的中位数。 invoice_no 的相同概念仍然适用。我也更新了我原来的帖子。
    • 对不起 - 我意识到这种变化对原始问题来说是一个很大的变化。因此,我为它创建了一个新问题:stackoverflow.com/questions/27489691/…
    【解决方案2】:

    我会将中位数表示为:

    SELECT invoice_no,
           (MIN(date) +
            (DATEDIFF(hour, MIN(DATE), MAX(DATE)) / 2.0)
           )
    FROM (SELECT ih.invoice_no
                 COUNT(*) OVER (PARTITION BY invoice_no) as cnt,
                 ROW_NUMBER() OVER (PARTITION BY invoice_no ORDER BY dates) as seqnum
          FROM INVOICE_HEADER ih
         ) ih
    WHERE 2*seqnum in (cnt, cnt + 1, cnt + 2)
    GROUP BY invoice_no
    

    其中大部分可能是不言自明的。您需要 partition by 来计算每个发票编号。您需要 order by dates 将值按正确的顺序排列。 where 子句是我处理中位数奇数/偶数问题的首选方法。

    最后一步有点棘手。当有偶数个值时,中位数是日期时间的平均值。这可能有点难以计算。相反,取最小日期并添加最大值和最小值之间的差异。当有偶数个元素时,这会产生平均值。当有奇数个元素时,这也会产生平均值,因为最小值和最大值是相同的值。

    【讨论】:

    • 如果存在“invoice_start_date”和“invoice_end_date”,我将如何处理这种概念这将是相同的概念,而是取两个日期之间的中位数。我试图将两个日期字段合并到我的 SQL 中,但无济于事。你可以在上面看到我更新的帖子。感谢您的帮助。
    • @user1985793 。 . .将问题从一列的中位数更改为两列的中位数是对问题的重大更改,应作为另一个问题提出。
    • 啊,好吧-抱歉。不想重复一个问题,但我认为这是一个非常重要的变化。我会提出一个新问题。谢谢。
    猜你喜欢
    • 2015-02-13
    • 2014-07-04
    • 1970-01-01
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    相关资源
    最近更新 更多