Mysql 分组数据的异常值

Mysql 分组数据的异常值,mysql,sql,greatest-n-per-group,Mysql,Sql,Greatest N Per Group,我想分析分组数据的异常值。假设我有数据: +--------+---------+-------+ | fruit | country | price | +--------+---------+-------+ | apple | UK | 1 | | apple | USA | 3 | | apple | LT | 2 | | apple | LV | 5 | | apple | EE |

我想分析分组数据的异常值。假设我有数据:

+--------+---------+-------+
| fruit  | country | price |
+--------+---------+-------+
| apple  | UK      |  1    | 
| apple  | USA     |  3    | 
| apple  | LT      |  2    | 
| apple  | LV      |  5    | 
| apple  | EE      |  4    | 
| pear   | SW      |  6    | 
| pear   | NO      |  2    | 
| pear   | FI      |  3    | 
| pear   | PL      |  7    | 
+--------+---------+-------+
我们吃梨吧。如果我发现异常值的方法是将梨的最高价格取25%,最低价格取25%,那么梨的异常值将是

+--------+---------+-------+
| pear   | NO      |  2    | 
| pear   | PL      |  7    |
+--------+---------+-------+ 
至于苹果:

+--------+---------+-------+
| apple  | UK      |  1    | 
| apple  | LV      |  5    |
+--------+---------+-------+ 
我想要的是创建一个视图,它将显示所有水果异常值联合的表。若我有这个视图,我可以只分析尾部,也可以将视图与主表相交,以得到并没有异常值的表——这是我的目标。解决办法是:

(SELECT * FROM fruits f WHERE f.fruit = 'pear' ORDER BY f.price ASC
LIMIT (SELECT ROUND(COUNT(*) * 0.25,0)
      FROM fruits f2
      WHERE f2.fruit = 'pear')
)
union all 
(SELECT * FROM fruits f WHERE f.fruit = 'pear' ORDER BY f.price DESC
LIMIT (SELECT ROUND(COUNT(*) * 0.25,0)
      FROM fruits f2
      WHERE f2.fruit = 'pear')
)
union all 
(SELECT * FROM fruits f WHERE f.fruit = 'apple' ORDER BY f.price ASC
LIMIT (SELECT ROUND(COUNT(*) * 0.25,0)
      FROM fruits f2
      WHERE f2.fruit = 'apple')
)
union all 
(SELECT * FROM fruits f WHERE f.fruit = 'apple' ORDER BY f.price DESC
LIMIT (SELECT ROUND(COUNT(*) * 0.25,0)
      FROM fruits f2
      WHERE f2.fruit = 'apple')
)

这将给我一个我想要的表,但是限制后的代码似乎不正确。。。另一个问题是组的数量。在这个例子中,只有两组(梨、苹果),但在我的实际数据中,大约有100组。所以“union all”应该以某种方式自动遍历所有唯一的结果,而无需为每个唯一的结果编写代码,找到每个唯一结果的异常值的数量,只获取该数量的行,并在另一个表(视图)中全部显示。

舍入不需要2/3个参数吗?也就是说,您是否不需要输入您希望四舍五入的小数点位

so
...
LIMIT (SELECT ROUND(COUNT(*) * 0.25)
      FROM #fruits f2
      WHERE f2.fruit = 'apple')

becomes
...
LIMIT (SELECT ROUND(COUNT(*) * 0.25,2)
      FROM #fruits f2
      WHERE f2.fruit = 'apple')

另外,只是快速查看一下午餐,但看起来您只是在期待最小/最大值。你不能只使用这些函数吗?

在我所知道的任何RDBMS中,你都不能用子查询中的值来提供
LIMIT
。有些数据库甚至不允许在其子句版本中使用主机变量/参数(我想到的是iSeries DB2)

这本质上是一个问题。大多数其他RDBMS中的类似查询都是通过所谓的窗口函数来解决的——本质上,您看到的是可移动的数据选择

MySQL没有这个功能,所以我们不得不伪造它。查询的实际机制将取决于您需要的实际数据,因此我只能谈谈您在这里尝试的内容。这些技术通常应具有适应性,但可能需要更多的创造力

首先,您需要一个函数,它将返回一个数字,指示它的位置-我假设重复的价格应该被赋予相同的排名(平局),这样做不会造成数字上的差距。这本质上就是
densite\u RANK()
windowing函数。我们可以通过执行以下操作获得这些结果:

SELECT fruit, country, price,
       @Rnk := IF(@last_fruit <> fruit, 1, 
                 IF(@last_price = price, @Rnk, @Rnk + 1)) AS Rnk,
       @last_fruit := fruit,
       @last_price := price
FROM Fruits
JOIN (SELECT @Rnk := 0) n
ORDER BY fruit, price
fruit  country   price
=======================
apple  UK        1 
apple  LV        5 
pear   NN        2 
pear   NO        2 
pear   PL        7 
现在,您正在尝试获取行的上/下25%。在这种情况下,您需要计算不同的价格:

SELECT fruit, COUNT(DISTINCT price)
FROM Fruits
GROUP BY fruit
。。。现在我们只需要将其加入到前面的语句中,以限制顶部/底部:

SELECT RankedFruit.fruit, RankedFruit.country, RankedFruit.price
FROM (SELECT fruit, COUNT(DISTINCT price) AS priceCount
      FROM Fruits
      GROUP BY fruit) CountedFruit
JOIN (SELECT fruit, country, price,
             @Rnk := IF(@last_fruit <> fruit, 1, 
                        IF(@last_price = price, @Rnk, @Rnk + 1)) AS rnk,
             @last_fruit := fruit,
             @last_price := price
      FROM Fruits
      JOIN (SELECT @Rnk := 0) n
      ORDER BY fruit, price) RankedFruit
  ON RankedFruit.fruit = CountedFruit.fruit
     AND (RankedFruit.rnk > ROUND(CountedFruit.priceCount * .75)
          OR RankedFruit.rnk <= ROUND(CountedFruit.priceCount * .25))

(我复制了一个
pear
行以显示“平分”价格。)

那么这是一个关于百分位数的问题吗?如果不能使用
row_NUMBER()
(MySQL不支持),这会有点麻烦。您似乎在选择最高和最低的值,而不是顶部和底部25%的值!?!至于梨,底部25%是4*0.25=1,苹果-0.25*5=1.25。四舍五入(1.25)=1,所以我觉得这很好。主要问题不在于如何找到异常值。主要的问题是如何过滤每个组(唯一的水果)的数据(通过任何异常值方法:百分位、标准贬值…),并将所有这些异常值添加到另一个表中。为什么小数点后两位?@popovitsj,2只是语法的一个示例。我只是好奇如何将结果限制在1.33行。
fruit  country   price
=======================
apple  UK        1 
apple  LV        5 
pear   NN        2 
pear   NO        2 
pear   PL        7