ホームページ  >  記事  >  データベース  >  GROUP BY 句と同時に使用される mysql 関数

GROUP BY 句と同時に使用される mysql 関数

伊谢尔伦
伊谢尔伦オリジナル
2016-11-23 10:45:121567ブラウズ

1. GROUP BY (集計) 関数

この章では、一連の数値演算のグループ (集合) 関数について説明します。特に明記されていない限り、グループ関数は NULL 値を無視します。

ROUP BY 句を含まないステートメントでグループ関数を使用する場合、すべての行をグループ化することと同じになります。

AVG([DISTINCT] expr)

expr の平均値を返します。 DISTINCT オプションを使用すると、expr のさまざまな値の平均を返すことができます。

一致する行が見つからない場合、AVG() は NULL を返します。

mysql> SELECT student_name, AVG(test_score)
-> FROM student
-> GROUP BY student_name;

BIT_AND(expr)

expr のすべてのビットのビット単位の AND を返します。計算は 64 ビット (BIGINT) の精度で実行されます。

一致する行が見つからない場合、この関数は 18446744073709551615 を返します。 (これは、すべてのビットが 1 に設定された符号なし BIGINT 値です)。

BIT_OR(expr)

expr のすべてのビットのビットごとの OR を返します。計算は 64 ビット (BIGINT) の精度で実行されます。

一致する行が見つからない場合、関数は 0 を返します。

BIT_XOR(expr)

expr のすべてのビットのビットごとの XOR を返します。計算は 64 ビット (BIGINT) の精度で実行されます。

一致する行が見つからない場合、関数は 0 を返します。

COUNT(expr)

SELECT ステートメントで取得した行内の NULL 以外の値の数を返します。

一致する行が見つからない場合、COUNT() は 0 を返します。

mysql> SELECT student.student_name,COUNT(*)-> FROM student,course-> WHERE student.student_id=course.student_id-> GROUP BY student_name;

COUNT(*) は、NULL 値が含まれているかどうかに関係なく、取得された行の数を返すという点で少し異なります。

SELECT は他の列を取得せずにテーブルから取得され、WHERE 句がなく、COUNT(*) は最速の戻り速度を実現するように最適化されています。例:

mysql> SELECT COUNT(*) FROM student;

この最適化は、MyISAM テーブルにのみ適用されます。これらのテーブル タイプには、関数によって返される正確な数のレコードが格納され、アクセスが非常に簡単であるためです。トランザクション ストレージ エンジン (InnoDB、BDB) の場合、複数のトランザクションが発生する可能性があり、それぞれのトランザクションが行数に影響を与える可能性があるため、正確な行数を保存することはさらに問題になります。

COUNT(DISTINCT expr,[expr...])

個別の非 NULL 値の数を返します。

一致する項目が見つからない場合、COUNT(DISTINCT) は 0 を返します。

mysql> SELECT COUNT(DISTINCT results) FROM student;

MySQL では、式のリストを指定することで、NULL を含まないさまざまな式の組み合わせの数を取得します。標準 SQL では、COUNT(DISTINCT ...) 内のすべての式を連結する必要があります。

GROUP_CONCAT(expr)

この関数は、グループの連結から非 NULL 値を含む文字列結果を返します。完全な構文は次のとおりです:

GROUP_CONCAT([DISTINCT] expr [,expr ...]
[ORDER BY {unsigned_integer | col_name | expr}
[ASC | DESC] [,col_name ...]]
[SEPARATOR str_val])
mysql> SELECT student_name,-> GROUP_CONCAT(test_score)-> FROM student-> GROUP BY student_name;
Or:
mysql> SELECT student_name,-> GROUP_CONCAT(DISTINCT test_score-> ORDER BY test_score DESC SEPARATOR ' ')-> FROM student-> GROUP BY student_name;

MySQL では、式を組み合わせた連結値を取得できます。 DISTINCT を使用すると、重複した値を削除できます。複数の結果値を並べ替える場合は、ORDER BY 句を使用する必要があります。逆順に並べ替えるには、ORDER BY 句を使用して並べ替える列名に DESC (降順) キーワードを追加します。デフォルトの順序は昇順ですが、ASC を使用して明示的に指定できます。 SEPARATOR の後には、結果の値に挿入する文字列値が続きます。デフォルトはカンマ (「,」) です。 SEPARATOR '' を指定すると、すべての区切り文字を削除できます。

group_concat_max_len システム変数を使用して、許可される最大長を設定できます。プログラムでのこの操作の構文は次のとおりです。val は符号なし整数です。

SET [SESSION | GLOBAL] group_concat_max_len = val;

最大長が設定されている場合、結果はこの最大長に切り取られます。

MIN([DISTINCT] expr), MAX([DISTINCT] expr)

expr の最小値と最大値を返します。 MIN() および MAX() の値は文字列引数にすることができ、その場合は最小または最大の文字列値が返されます。 DISTINCT キーワードを使用すると、expr のさまざまな値の最小値または最大値を見つけることができますが、これは DISTINCT を省略した場合と同じ結果になります。

一致する行が見つからない場合、MIN() と MAX() は NULL を返します。

mysql> SELECT student_name, MIN(test_score), MAX(test_score)-> FROM student-> GROUP BY student_name;

MIN()、MAX()、およびその他の集計関数の場合、MySQL は現在、コレクション内の文字列の相対位置ではなく、文字列値に基づいて ENUM および SET カラムを比較します。これは、ORDER BY が 2 つを比較する方法とは異なります。これは、MySQL の将来のバージョンでは改善されるはずです。

STD(expr) STDDEV(expr)

expr の母標準偏差を返します。これは標準 SQL の拡張です。この関数の STDDEV() 形式は、Oracle との互換性を提供するために使用されます。代わりに、標準 SQL 関数 STDDEV_POP() を使用できます。

一致する行が見つからない場合、これらの関数は NULL を返します。

STDDEV_POP(expr)

expr (VAR_POP() の平方根) の母標準偏差を返します。 STD() または STDDEV() も使用できます。これらは同じ意味ですが、標準 SQL ではありません。

若找不到匹配的行,则STDDEV_POP()返回 NULL。

STDDEV_SAMP(expr)

返回expr 的样本标准差 ( VAR_SAMP()的平方根)。

若找不到匹配的行,则STDDEV_SAMP() 返回 NULL 。

SUM([DISTINCT] expr)

返回expr 的总数。 若返回集合中无任何行,则 SUM() 返回NULL。DISTINCT 关键词可用于 MySQL 5.1 中,求得expr不同值的总和。

若找不到匹配的行,则SUM()返回 NULL。

VAR_POP(expr)

返回expr 总体标准方差。它将行视为总体,而不是一个样本, 所以它将行数作为分母。你也可以使用 VARIANCE(),它具有相同的意义然而不是 标准的 SQL。

若找不到匹配的项,则VAR_POP()返回NULL。

VAR_SAMP(expr)

返回expr 的样本方差。更确切的说,分母的数字是行数减去1。

若找不到匹配的行,则VAR_SAMP()返回NULL。

VARIANCE(expr)

返回expr 的总体标准方差。这是标准SQL 的延伸。可使用标准SQL 函数 VAR_POP() 进行代替。

若找不到匹配的项,则VARIANCE()返回NULL。

2. GROUP BY修改程序

GROUP BY子句允许一个将额外行添加到简略输出端 WITH ROLLUP 修饰符。这些行代表高层(或高聚集)简略操作。ROLLUP 因而允许你在多层分析的角度回答有关问询的问题。例如,它可以用来向OLAP (联机分析处理) 操作提供支持。

设想一个名为sales 的表具有年份、国家、产品及记录销售利润的利润列:

CREATE TABLE sales
(
    year    INT NOT NULL,
    country VARCHAR(20) NOT NULL,
    product VARCHAR(32) NOT NULL,
    profit  INT
);

可以使用这样的简单GROUP BY,每年对表的内容做一次总结:

mysql> SELECT year, SUM(profit) FROM sales GROUP BY year;+------+-------------+
| year | SUM(profit) |
+------+-------------+
| 2000 |        4525 |
| 2001 |        3010 |
+------+-------------+

这个输出结果显示了每年的总利润, 但如果你也想确定所有年份的总利润,你必须自己累加每年的单个值或运行一个加法询问。

或者你可以使用 ROLLUP, 它能用一个问询提供双层分析。将一个 WITH ROLLUP修饰符添加到GROUP BY 语句,使询问产生另一行结果,该行显示了所有年份的总价值:

mysql> SELECT year, SUM(profit) FROM sales GROUP BY year WITH ROLLUP;+------+-------------+
| year | SUM(profit) |
+------+-------------+
| 2000 |        4525 |
| 2001 |        3010 |
| NULL |        7535 |
+------+-------------+

总计高聚集行被年份列中的NULL值标出。

当有多重 GROUP BY 列时,ROLLUP产生的效果更加复杂。这时,每次在除了最后一个分类列之外的任何列出现一个 “break” (值的改变) ,则问讯会产生一个高聚集累计行。

例如,在没有 ROLLUP的情况下,一个以年、国家和产品为基础的关于 sales 表的一览表可能如下所示:

mysql> SELECT year, country, product, SUM(profit)-> FROM sales-> GROUP BY year, country, product;+------+---------+------------+-------------+
| year | country | product    | SUM(profit) |
+------+---------+------------+-------------+
| 2000 | Finland | Computer   |        1500 |
| 2000 | Finland | Phone      |         100 |
| 2000 | India   | Calculator |         150 |
| 2000 | India   | Computer   |        1200 |
| 2000 | USA     | Calculator |          75 |
| 2000 | USA     | Computer   |        1500 |
| 2001 | Finland | Phone      |          10 |
| 2001 | USA     | Calculator |          50 |
| 2001 | USA     | Computer   |        2700 |
| 2001 | USA     | TV         |         250 |
+------+---------+------------+-------------+

表示总值的输出结果仅位于年/国家/产品的分析级别。当添加了 ROLLUP后, 问询会产生一些额外的行:

mysql> SELECT year, country, product, SUM(profit)
    -> FROM sales
    -> GROUP BY year, country, product WITH ROLLUP;+------+---------+------------+-------------+
| year | country | product    | SUM(profit) |
+------+---------+------------+-------------+
| 2000 | Finland | Computer   |        1500 |
| 2000 | Finland | Phone      |         100 |
| 2000 | Finland | NULL       |        1600 |
| 2000 | India   | Calculator |         150 |
| 2000 | India   | Computer   |        1200 |
| 2000 | India   | NULL       |        1350 |
| 2000 | USA     | Calculator |          75 |
| 2000 | USA     | Computer   |        1500 |
| 2000 | USA     | NULL       |        1575 |
| 2000 | NULL    | NULL       |        4525 |
| 2001 | Finland | Phone      |          10 |
| 2001 | Finland | NULL       |          10 |
| 2001 | USA     | Calculator |          50 |
| 2001 | USA     | Computer   |        2700 |
| 2001 | USA     | TV         |         250 |
| 2001 | USA     | NULL       |        3000 |
| 2001 | NULL    | NULL       |        3010 |
| NULL | NULL    | NULL       |        7535 |
+------+---------+------------+-------------+

对于这个问询, 添加ROLLUP 子句使村输出结果包含了四层分析的简略信息,而不只是一个下面是怎样解释  ROLLUP输出:

一组给定的年份和国家的每组产品行后面, 会产生一个额外的总计行, 显示所有产品的总值。这些行将产品列设置为 NULL。

一组给定年份的行后面,会产生一个额外的总计行,显示所有国家和产品的总值。这些行将国家和产品列设置为  NULL。

最后, 在所有其它行后面,会产生一个额外的总计列,显示所有年份、国家及产品的总值。 这一行将年份、国家和产品列设置为 NULL。

使用ROLLUP 时的其它注意事项

以下各项列出了一些MySQL执行ROLLUP的特殊状态:

当你使用 ROLLUP时, 你不能同时使用 ORDER BY子句进行结果排序。换言之, ROLLUP 和ORDER BY 是互相排斥的。然而,你仍可以对排序进行一些控制。在 MySQL中, GROUP BY 可以对结果进行排序,而且你可以在GROUP BY列表指定的列中使用明确的 ASC和DESC关键词,从而对个别列进行排序。 (不论如何排序被ROLLUP添加的较高级别的总计行仍出现在它们被计算出的行后面)。

LIMIT可用来限制返回客户端的行数。LIMIT 用在 ROLLUP后面, 因此这个限制 会取消被ROLLUP添加的行。例如:

mysql> SELECT year, country, product, SUM(profit)
    -> FROM sales
    -> GROUP BY year, country, product WITH ROLLUP
    -> LIMIT 5;+------+---------+------------+-------------+
| year | country | product    | SUM(profit) |
+------+---------+------------+-------------+
| 2000 | Finland | Computer   |        1500 |
| 2000 | Finland | Phone      |         100 |
| 2000 | Finland | NULL       |        1600 |
| 2000 | India   | Calculator |         150 |
| 2000 | India   | Computer   |        1200 |
+------+---------+------------+-------------+

将ROLLUP同 LIMIT一起使用可能会产生更加难以解释的结果,原因是对于理解高聚集行,你所掌握的上下文较少。

在每个高聚集行中的NULL 指示符会在该行被送至客户端时产生。服务器会查看最左边的改变值后面的GROUP BY子句指定的列。对于任何结果集合中的,有一个词匹配这些名字的列, 其值被设为 NULL。(若你使用列数字指定了分组列,则服务器会通过数字确定将哪个列设置为 NULL)。

由于在高聚集行中的 NULL值在问询处理阶段被放入结果集合中,你无法将它们在问询本身中作为NULL值检验。例如,你无法将 HAVING product IS NULL 添加到问询中,从而在输出结果中删去除了高聚集行以外的部分。

另一方面, NULL值在客户端不以 NULL 的形式出现, 因而可以使用任何MySQL客户端编程接口进行检验。

3. 具有隐含字段的GROUP BY

MySQL 扩展了 GROUP BY的用途,因此你可以使用SELECT 列表中不出现在GROUP BY语句中的列或运算。这代表 “对该组的任何可能值 ”。你可以通过避免排序和对不必要项分组的办法得到它更好的性能。例如,在下列问询中,你无须对customer.name 进行分组:

mysql> SELECT order.custid, customer.name, MAX(payments)
    -> FROM order,customer
    -> WHERE order.custid = customer.custid
    -> GROUP BY order.custid;

在标准SQL中, 你必须将 customer.name添加到 GROUP BY子句中。在MySQL中, 假如你不在ANSI模式中运行,则这个名字就是多余的。

假如你从 GROUP BY 部分省略的列在该组中不是唯一的,那么不要使用这个功能! 你会得到非预测性结果。

在有些情况下,你可以使用MIN()和MAX() 获取一个特殊的列值,即使他不是唯一的。下面给出了来自包含排序列中最小值的列中的值:

SUBSTR(MIN(CONCAT(RPAD(sort,6,' '),column)),7)

注意,假如你正在尝试遵循标准 SQL, 你不能使用GROUP BY或 ORDER BY子句中的表达式。你可以通过使用表达式的别名绕过这一限制:

mysql> SELECT id,FLOOR(value/100) AS val
    -> FROM tbl_name
    -> GROUP BY id, val ORDER BY val;

然而, MySQL允许你使用GROUP BY 及 ORDER BY 子句中的表达式。例如:

mysql> SELECT id, FLOOR(value/100) FROM tbl_name ORDER BY RAND();


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。