假设我有一个表(数字)只有一列:
n
---
4
5
67
23
7
89
,我想获取中位数(仅数字列表)。我以为这很容易,所以我写道:
SELECT SUM(ord.n)/2
FROM (
SELECT n
FROM numbers
ORDER BY n ASC
LIMIT 2 OFFSET (SELECT COUNT(n)/2-1 FROM numbers)
) AS ord
但是当然会抛出语法错误。我想我不能将子查询插入offset中,但我想知道要做什么才能得到预期的结果?我知道写查询以获取中位数的方法有很多,但我需要知道是否有可能将“变量”插入偏移量而不是放置一些数字?
答案 0 :(得分:1)
我认为您正在寻找下面的查询,该查询应该适用于MySQL 5.1及更高版本
SELECT
AVG(filter.n)
FROM (
SELECT
*
, (@position := @position + 1) AS init_position
FROM
t
CROSS JOIN (
SELECT
@position := 0
, @max := (SELECT COUNT(t.n) FROM t)
, @median_mode := (CASE WHEN ((@max % 2) = 0) THEN 'even' ELSE 'odd' END)
) AS init_user_param
ORDER BY
t.n ASC
) AS filter
WHERE
CASE
WHEN @median_mode = 'even'
THEN filter.init_position BETWEEN (@max / 2) AND ((@max / 2) + 1)
WHEN @median_mode = 'odd'
THEN filter.init_position = ((@max + 1) / 2)
END
结果
| AVG(filter.n) |
| ------------- |
| 15 |
请参阅demo
当89不在列表中时的结果。
| AVG(filter.n) |
| ------------- |
| 7 |
请参阅demo
答案 1 :(得分:0)
您可以使用ROW_NUMBER()
窗口功能:
try {
const fetched = await message.channel.fetchMessages({ limit: 100 });
const notPinned = fetched.filter(fetchedMsg => !fetchedMsg.pinned);
await message.channel.bulkDelete(notPinned, true);
} catch(err) {
console.error(err);
}
请参见demo。
结果:
WITH cte AS (SELECT COUNT(*) counter FROM numbers)
SELECT AVG(n) median
FROM (
SELECT
row_number() over (order by n) ordinal,
n
FROM numbers
) t
WHERE (SELECT counter FROM cte) IN (2 * ordinal, 2 * (ordinal - 1))
答案 2 :(得分:0)
(可能)与算法最相似的解决方案是使用两个查询。首先获取偏移量。然后将其插入查询中。仅限SQL的方式是使用准备好的语句:
set @offset = (SELECT COUNT(n)/2-1 FROM numbers);
set @sql = "
SELECT SUM(ord.n)/2
FROM (
SELECT n
FROM numbers
ORDER BY n ASC
LIMIT 2 OFFSET ?
) AS ord
";
prepare stmt from @sql;
execute stmt using @offset;