我有一个数据库表,基本上有date Date, int UserId, double Value
列。
我希望能够进行查询,为每个日期的所有用户提供10%和90%的百分位值,例如SELECT Date, Pct10(Value), Pct90(Value) from Table group by Date
。
我知道使用Count(*)
和LIMIT
计算百分位数并计算行数的不同方法,但是,我没有看到如何在一个语句中对每个日期值进行迭代应用。
示例数据:
Date | UserId | Value
2013-01-01 | 0 | 1
2013-01-01 | 1 | 1
2013-01-01 | 2 | 1
2013-01-01 | 3 | 1
2013-01-01 | 4 | 2
2013-01-01 | 5 | 2
2013-01-01 | 6 | 2
2013-01-01 | 7 | 2
2013-01-01 | 8 | 2
2013-01-01 | 9 | 2
2013-01-01 | 10 | 9
2013-01-02 | 1 | 1
2013-01-02 | 9 | 1
预期结果将是
Date | Pct10 | Pct90
2013-01-01 | 1 | 2
2013-01-02 | 1 | 1
答案 0 :(得分:0)
我不确定获得百分位数。我正在使用基于select nth percentile from mysql下面的子查询,但我不确定我是否已正确修改它。我的答案是在子查询的组合中。
随着表格大小的增加,以下查询会很慢并且会以指数方式变慢,但它应该能够满足您的需求:
SELECT p10.Date, Pct10, Pct90
FROM (
SELECT Date, count(Value) AS Pct10
FROM mydata
GROUP BY Date, Value
ORDER BY ABS(0.1-(count(Value)/(select count(*) from mydata)))
LIMIT 1) AS p10
INNER JOIN (
SELECT Date, count(Value) AS Pct9
FROM mydata
GROUP BY Date, Value
ORDER BY ABS(0.9-(count(Value)/(select count(*) from mydata)))
LIMIT 1) AS p90 ON p10.Date = p90.Date
GROUP BY p1.Date
这是我的第二个想法。如果它工作,它将比我列出的第一个更快更有效,但对于较大的表仍然相当慢。
SELECT p10.Date, count(Value) AS Pct10, Pct90
FROM mydata p10
INNER JOIN (
SELECT Date, count(Value) AS Pct90
FROM mydata
GROUP BY Date, Value
ORDER BY ABS(0.9-(count(Value)/(select count(*) from mydata)))
LIMIT 1) AS p90 ON p10.Date = p90.Date
GROUP BY Date, Value
ORDER BY ABS(0.1-(count(Value)/(select count(*) from mydata)))
LIMIT 1
修改强>
好的,头脑风暴时间。鉴于这是一个日期百分位数的子查询(我甚至不确定它是如何工作的): SELECT Date, count(Value) AS Pct90
FROM mydata
WHERE Date = ?
GROUP BY Value
ORDER BY ABS(0.9-(count(Value)/(select count(*) from mydata WHERE Date = ?)))
LIMIT 1
然后让我们尝试修复ORDER BY:
SELECT Date, count(Value) as Pct90
FROM mydata
INNER JOIN (SELECT Date, COUNT(*) AS DateTotal FROM mydata GROUP BY Date) AS d
ON d.Date = mydata.Date
GROUP BY Date, Value
ORDER BY (ABS(0.9-(COUNT(Value)/d.DateTotal)))
LIMIT 1
如果你在我之前的例子中使用这种模式,也许它会起作用。
编辑2
所以,我们再来一次,因为我们不能使用LIMIT 1(之前我应该已经实现过)。我实际上在我自己的数据库上测试了以下内容(希望我将所有字段和表名改回原来的样子!)它似乎有用。你必须再次为p10做这个并将两者结合起来。
--- removed due to typos ---
编辑3
我在编辑2中发现了一些错误,所以我删除了它。这是整个百分比查询。据我所知,此查询适用于我的数据库(使用不同的字段和表)。
SELECT n.Date, n.Pct AS Pct10, n.Value AS Pct10Value, q.Pct AS Pct90, q.Value AS Pct90Value FROM (
SELECT p.Date, p.Pct, p.Value, m.Selector FROM (
SELECT mydata.Date, Value, COUNT(Value) as Pct, (ABS(0.1-(COUNT(Value)/d.DateTotal))) AS Abs10
FROM mydata
INNER JOIN (SELECT Date, COUNT(*) AS DateTotal FROM mydata GROUP BY Date) AS d
ON d.Date = mydata.Date
GROUP BY Date, Value
) p
INNER JOIN (
SELECT Date, MIN(Abs10) AS Selector FROM (
SELECT mydata.Date, Value, COUNT(Value) as Pct, (ABS(0.1-(COUNT(Value)/d.DateTotal))) AS Abs10
FROM mydata
INNER JOIN (SELECT Date, COUNT(*) AS DateTotal FROM mydata GROUP BY Date) AS d
ON d.Date = mydata.Date
GROUP BY Date, Value
) x GROUP BY Date
) AS m ON m.Selector = p.Abs10
GROUP BY p.Date) n
INNER JOIN (
SELECT p.Date, p.Pct, p.Value, m.Selector FROM (
SELECT mydata.Date, Value, COUNT(Value) as Pct, (ABS(0.9-(COUNT(Value)/d.DateTotal))) AS Abs90
FROM mydata
INNER JOIN (SELECT Date, COUNT(*) AS DateTotal FROM mydata GROUP BY Date) AS d
ON d.Date = mydata.Date
GROUP BY Date, Value
) p
INNER JOIN (
SELECT Date, MIN(Abs90) AS Selector FROM (
SELECT mydata.Date, Value, COUNT(Value) as Pct, (ABS(0.9-(COUNT(Value)/d.DateTotal))) AS Abs90
FROM mydata
INNER JOIN (SELECT Date, COUNT(*) AS DateTotal FROM mydata GROUP BY Date) AS d
ON d.Date = mydata.Date
GROUP BY Date, Value
) x GROUP BY Date
) AS m ON m.Selector = p.Abs90
GROUP BY p.Date) q ON q.Date = n.Date