MySQL:如何在没有聚合函数的列上工作?

时间:2010-11-14 17:57:04

标签: mysql group-by

我对group by命令在mysql中的工作原理感到有些困惑。

假设我有一张桌子:

mysql> select recordID, IPAddress, date, httpMethod from Log_Analysis_Records_dalhousieShort;                   
+----------+-----------------+---------------------+-------------------------------------------------+
| recordID | IPAddress       | date                | httpMethod                                      |
+----------+-----------------+---------------------+-------------------------------------------------+
|        1 | 64.68.88.22     | 2003-07-09 00:00:21 | GET /news/science/cancer.shtml HTTP/1.0         | 
|        2 | 64.68.88.166    | 2003-07-09 00:00:55 | GET /news/internet/xml.shtml HTTP/1.0           | 
|        3 | 129.173.177.214 | 2003-07-09 00:01:23 | GET / HTTP/1.1                                  | 
|        4 | 129.173.177.214 | 2003-07-09 00:01:23 | GET /include/fcs_style.css HTTP/1.1             | 
|        5 | 129.173.177.214 | 2003-07-09 00:01:23 | GET /include/main_page.css HTTP/1.1             | 
|        6 | 129.173.177.214 | 2003-07-09 00:01:23 | GET /images/bigportaltopbanner.gif HTTP/1.1     | 
|        7 | 129.173.177.214 | 2003-07-09 00:01:23 | GET /images/right_1.jpg HTTP/1.1                | 
|        8 | 64.68.88.165    | 2003-07-09 00:02:43 | GET /studentservices/responsible.shtml HTTP/1.0 | 
|        9 | 64.68.88.165    | 2003-07-09 00:02:44 | GET /news/sports/basketball.shtml HTTP/1.0      | 
|       10 | 64.68.88.34     | 2003-07-09 00:02:46 | GET /news/science/space.shtml HTTP/1.0          | 
|       11 | 129.173.159.98  | 2003-07-09 00:03:46 | GET / HTTP/1.1                                  | 
|       12 | 129.173.159.98  | 2003-07-09 00:03:46 | GET /include/fcs_style.css HTTP/1.1             | 
|       13 | 129.173.159.98  | 2003-07-09 00:03:46 | GET /include/main_page.css HTTP/1.1             | 
|       14 | 129.173.159.98  | 2003-07-09 00:03:48 | GET /images/bigportaltopbanner.gif HTTP/1.1     | 
|       15 | 129.173.159.98  | 2003-07-09 00:03:48 | GET /images/left_1g.jpg HTTP/1.1                | 
|       16 | 129.173.159.98  | 2003-07-09 00:03:48 | GET /images/webcam.gif HTTP/1.1                 | 
+----------+-----------------+---------------------+-------------------------------------------------+

当我执行此语句时,它如何选择要包含的recordID,因为有一系列recordID是正确的?它只是选择匹配的第一个吗?

mysql> select recordID, IPAddress, date, httpMethod from Log_Analysis_Records_dalhousieShort GROUP BY IPADDRESS;
+----------+-----------------+---------------------+-------------------------------------------------+
| recordID | IPAddress       | date                | httpMethod                                      |
+----------+-----------------+---------------------+-------------------------------------------------+
|       11 | 129.173.159.98  | 2003-07-09 00:03:46 | GET / HTTP/1.1                                  | 
|        3 | 129.173.177.214 | 2003-07-09 00:01:23 | GET / HTTP/1.1                                  | 
|        8 | 64.68.88.165    | 2003-07-09 00:02:43 | GET /studentservices/responsible.shtml HTTP/1.0 | 
|        2 | 64.68.88.166    | 2003-07-09 00:00:55 | GET /news/internet/xml.shtml HTTP/1.0           | 
|        1 | 64.68.88.22     | 2003-07-09 00:00:21 | GET /news/science/cancer.shtml HTTP/1.0         | 
|       10 | 64.68.88.34     | 2003-07-09 00:02:46 | GET /news/science/space.shtml HTTP/1.0          | 
+----------+-----------------+---------------------+-------------------------------------------------+
6 rows in set (0.00 sec)

对于此表格,max(date)min(date)值对我而言似乎合乎逻辑,但我对如何选择recordIDhttpMethod感到困惑。

在一个命令中使用两个聚合函数是否安全?

mysql> select recordID, IPAddress, min(date), max(date), httpMethod from Log_Analysis_Records_dalhousieShort GROUP BY IPADDRESS;
+----------+-----------------+---------------------+---------------------+-------------------------------------------------+
| recordID | IPAddress       | min(date)           | max(date)           | httpMethod                                      |
+----------+-----------------+---------------------+---------------------+-------------------------------------------------+
|       11 | 129.173.159.98  | 2003-07-09 00:03:46 | 2003-07-09 00:03:48 | GET / HTTP/1.1                                  | 
|        3 | 129.173.177.214 | 2003-07-09 00:01:23 | 2003-07-09 00:01:23 | GET / HTTP/1.1                                  | 
|        8 | 64.68.88.165    | 2003-07-09 00:02:43 | 2003-07-09 00:02:44 | GET /studentservices/responsible.shtml HTTP/1.0 | 
|        2 | 64.68.88.166    | 2003-07-09 00:00:55 | 2003-07-09 00:00:55 | GET /news/internet/xml.shtml HTTP/1.0           | 
|        1 | 64.68.88.22     | 2003-07-09 00:00:21 | 2003-07-09 00:00:21 | GET /news/science/cancer.shtml HTTP/1.0         | 
|       10 | 64.68.88.34     | 2003-07-09 00:02:46 | 2003-07-09 00:02:46 | GET /news/science/space.shtml HTTP/1.0          | 
+----------+-----------------+---------------------+---------------------+-------------------------------------------------+
6 rows in set (0.00 sec)

4 个答案:

答案 0 :(得分:12)

在没有聚合函数的select表达式中列出字段时,通常使用GROUP BY是无效的SQL,应该抛出错误。

但是,MySQL允许这样做,只需随机选择一个值。尽量避免它,因为它令人困惑。

要禁止这一点,您可以在运行时说:

SET sql_mode := CONCAT('ONLY_FULL_GROUP_BY,',@@sql_mode);

或使用配置值和/或命令行选项sql-mode

是的,列出两个聚合函数是完全有效的。

答案 1 :(得分:4)

因为我很新,显然我无法发布有用的图片,所以我会尝试用文字来做...

我刚刚对此进行了测试,看起来不在GROUP BY中的字段值将使用与条件匹配的FIRST行的值。这也将解释其他人在选择不在group by子句中的列时所感知的“随机性”。

示例:

创建一个名为“test”的表,其中有两列名为“col1”和“col2”,其数据如下所示:

Col1 Col2
1 2
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3

然后运行以下查询:

选择col1,col2
从测试中按col2 desc

你会得到这个结果:

1 3
2 3
3 3
1 2
1 2
2 2
3 2
2 1
3 1

现在考虑以下查询:

选择groupTable.col1,groupTable.col2
来自(
选择col1,col2
从测试中 按col2排序 desc
)groupTable
group by groupTable.col1
按groupTable.col1 desc排序

你会得到这个结果:

3 3
2 3
1 3

将子查询更改为asc:

选择col1,col2
从测试中按col2 asc

结果:

2 1
3 1
1 2
1 2
2 2
3 2
1 3
2 3
3 3

再次使用它作为子查询的基础:

选择groupTable.col1,groupTable.col2
来自(
选择col1,col2
从测试中 按col2排序 asc
)groupTable
group by groupTable.col1
按groupTable.col1 desc排序

结果:
3 1
2 1
1 2

现在,您应该能够看到子查询的顺序如何影响为所选字段选择但未在group by子句中选择的值。这可以解释其他人提到的感知“随机性”,因为如果子查询(或缺少子查询)没有与ORDER BY子句组合,那么mysql会在进入时抓取行,但是通过在子查询中定义排序顺序能够控制此行为并获得可预测的结果。

答案 2 :(得分:0)

我认为根据PRIMARY KEY或任何INDEX需要第一行,因为它看起来像是这样工作,但我在各种表上尝试了GROUP BY查询并且没有识别任何模式。

因此,我将避免使用任何非分组列的值。

答案 3 :(得分:0)

Group By根据索引选取第一条记录。让我们说Log_Analysis_Records_dalhousieShort表有recoedID作为索引。因此,在记录ID 11到16中,分组为IPAddress 129.173.159.98选择11 recordID。但是min和max是按操作预先分组的,因此逻辑上为您计算值。

mysql> select recordID, IPAddress, date, httpMethod from Log_Analysis_Records_dalhousieShort GROUP BY IPADDRESS;
+----------+-----------------+---------------------+-------------------------------------------------+
| recordID | IPAddress       | date                | httpMethod                                      |
+----------+-----------------+---------------------+-------------------------------------------------+
|       11 | 129.173.159.98  | 2003-07-09 00:03:46 | GET / HTTP/1.1                                  | 
|        3 | 129.173.177.214 | 2003-07-09 00:01:23 | GET / HTTP/1.1                                  | 
|        8 | 64.68.88.165    | 2003-07-09 00:02:43 | GET /studentservices/responsible.shtml HTTP/1.0 | 
|        2 | 64.68.88.166    | 2003-07-09 00:00:55 | GET /news/internet/xml.shtml HTTP/1.0           | 
|        1 | 64.68.88.22     | 2003-07-09 00:00:21 | GET /news/science/cancer.shtml HTTP/1.0         | 
|       10 | 64.68.88.34     | 2003-07-09 00:02:46 | GET /news/science/space.shtml HTTP/1.0          | 
+----------+-----------------+---------------------+-------------------------------------------------+
6 rows in set (0.00 sec)