根据 SQL 中的日期计算百分位数

Posted

技术标签:

【中文标题】根据 SQL 中的日期计算百分位数【英文标题】:Calculate percentiles based on dates in SQL 【发布时间】:2016-06-01 04:41:16 【问题描述】:

我有一个包含 50k 行的表,其中包含 A 列(BIGINT,例如客户帐户 ID)和 B 列(日期,例如 - 最后购买日期)。

我想了解在给定日期范围的前 25%、前 50%、前 75% 中进行最后一次购买的客户百分比,因此我可以根据所有这些客户帐户 ID 判断我们最近的大部分购买都偏向于。关于如何在 sql 中实现的任何想法?

表:所有事务

ACCT_ID         |   DATE
----------------|---------------
23748234782947  |   05-15-2016
28178792839838  |   05-01-2016
28178092734538  |   02-12-2016
28347732839867  |   01-15-2016
28170909362959  |   10-10-2015
28171334099090  |   11-11-2015
28109129330023  |   12-25-2014
28172377859289  |   10-31-2014

【问题讨论】:

【参考方案1】:

我不确定我是否正确地使用了这些图块,但如果你的意思是将时间范围划分为四个区域,它会在 2016 年 2 月 1 日到 2016 年 6 月 1 日的时间间隔内像这样工作。权衡:手动计算间隔;也可以通过日期计算来完成此操作

CREATE TABLE tblA ( ACCT_ID INTEGER, PDATE DATE);

INSERT INTO TblA(ACCT_ID, PDATE) VALUES (1000,'2016-05-21');
INSERT INTO TblA(ACCT_ID, PDATE) VALUES (1001,'2016-05-11');
INSERT INTO TblA(ACCT_ID, PDATE) VALUES (1002,'2016-05-24');
INSERT INTO TblA(ACCT_ID, PDATE) VALUES (1003,'2016-04-21');
INSERT INTO TblA(ACCT_ID, PDATE) VALUES (1004,'2016-02-12');
INSERT INTO TblA(ACCT_ID, PDATE) VALUES (1005,'2016-02-21');
INSERT INTO TblA(ACCT_ID, PDATE) VALUES (1001,'2016-03-22');
INSERT INTO TblA(ACCT_ID, PDATE) VALUES (1002,'2016-04-01');
INSERT INTO TblA(ACCT_ID, PDATE) VALUES (1005,'2016-04-01');
INSERT INTO TblA(ACCT_ID, PDATE) VALUES (1006,'2016-04-01');

    SELECT DISTR.DATE_RANGE, COUNT(DISTR.ACCT_ID) / OVRL.TOTALCNT
FROM (SELECT 'TOP25' as DATE_RANGE, A.ACCT_ID
        FROM tblA A
       WHERE A.PDATE BETWEEN STR_TO_DATE('01.05.2016', '%m/%d/%Y')  AND STR_TO_DATE('01.06.2016', '%m/%d/%Y')
      UNION ALL
      SELECT 'TOP50' as DATE_RANGE, B.ACCT_ID
        FROM tblA B
       WHERE B.PDATE BETWEEN STR_TO_DATE('01.04.2016', '%m/%d/%Y')  AND STR_TO_DATE('01.06.2016', '%m/%d/%Y')
      UNION ALL
      SELECT 'TOP75' as DATE_RANGE, C.ACCT_ID
        FROM tblA C
       WHERE C.PDATE BETWEEN STR_TO_DATE('01.03.2016', '%m/%d/%Y')  AND STR_TO_DATE('01.06.2016', '%m/%d/%Y')
      UNION ALL
      SELECT 'ALL' as DATE_RANGE, C.ACCT_ID
      FROM tblA C
      WHERE C.PDATE BETWEEN STR_TO_DATE('01.02.2016', '%m/%d/%Y')  AND STR_TO_DATE('01.06.2016', '%m/%d/%Y') ) DISTR
,    (SELECT COUNT(*) AS TOTALCNT FROM tblA A WHERE A.PDATE BETWEEN STR_TO_DATE('01.03.2016', '%m/%d/%Y')  AND STR_TO_DATE('01.06.2016', '%m/%d/%Y')) OVRL
GROUP BY DISTR.DATE_RANGE, OVRL.TOTALCNT

将交付

ALL 10  10
TOP25   3   10
TOP50   7   10
TOP75   8   10

【讨论】:

【参考方案2】:

此解决方案将根据数据集的完整日期范围动态创建日期四分位数,然后显示四分位数中出现的 ID 百分比:

select unix_timestamp(min(date)) into @start from p;
select unix_timestamp(max(date)) into @end from p;
Set @25 = 0.25 *(@end - @start)+@start;
Set @50 = 0.50 *(@end - @start)+@start;
Set @75 = 0.75 *(@end - @start)+@start;

SELECT 
CASE WHEN unix_timestamp(date)>@75 then 4
WHEN unix_timestamp(date)>@50 then 3
WHEN unix_timestamp(date)>@25 then 2
ELSE 1 END as Quartile, 
round(count(id)/(select count(*) from p)*100,2) as Percentage 
FROM p 
GROUP BY Quartile;

Here is a functional example 提供更多细节和格式。

如果您有一半的日期在您的范围的开头,一半在结尾,您将只能动态地看到 Q1 和 Q4。

先将变量设置为范围,然后对每个Quartile进行拆分,或者其他时间段分区。

CASE 语句从大日期到小日期级联,全部采用UNIX_TIMESTAMP 格式以便于算术,在失败时从四分位数传递到四分位数。

同样的结构可用于按段分割日期范围,n-tiles。

【讨论】:

以上是关于根据 SQL 中的日期计算百分位数的主要内容,如果未能解决你的问题,请参考以下文章

计算百分比准确度:(实际日期 - 计划日期)/计划日期在 ms sql 2010 或 2013 中

sql 计算Postgresql中的百分位数

在 SQL 中分析并形成分位数并计算落在各个分位数中的值的百分比

如何根据 T-SQL (SSMS 2017) 中的下一条记录 [Effective Date]-1 计算到期日期?

SQL语句如何根据出生日期计算年龄

SQL语句如何根据出生日期计算年龄