MySQL查询:选择不同的列1,按列2分组

20

现在我有以下查询:

SELECT name, COUNT(name), time, price, ip, SUM(price) 
  FROM tablename 
 WHERE time >= $yesterday 
   AND time <$today GROUP BY name

我想要做的是按列“ip”添加DISTINCT,即

SELECT DISTINCT ip FROM tablename 
所以我的最终输出应该是所有今天时间的行中的所有列,按名称分组(每个重复名称带有名称计数),并且没有重复的IP地址。
我的查询应该是什么样子?(或者,如何使用php添加缺失的过滤器到输出中?)
提前致谢。
[更新]
为了减少混乱,请考虑这个(简化后的)数据库表:
|   name   |   ip   |
---------------------
|  mark    |  123   |
|  mark    |  123   |
|  mark    |  456   |
|  dave    |  789   |
|  dave    |  087   |

我要寻找的结果是一个类似这样的HTML表格:

|  name    |  name count   |
----------------------------
|  mark    |      2        |
|  dave    |      2        |

我目前得到的是:

|  name    |  name count   |
----------------------------
|  mark    |      3        |
|  dave    |      2        |

即使两次使用相同的IP地址,该计数器也会将其算作3次。


我也尝试了SELECT DISTINCT ip FROM (SELECT name, COUNT(name), time, price, ip, SUM(price) FROM tablename WHERE time >= $yesterday AND time <$today GROUP BY name) as TABLE,但是我得到了一个语法错误... - Adam Tal
尝试:SELECT DISTINCT TABLE.ip FROM (SELECT T.name, COUNT(T.name), T.time, T.price, T.ip, SUM(T.price) FROM tablename T WHERE time >= $yesterday AND time <$today GROUP BY name) as TABLE - lexu
"提供的参数不是有效的MySQL结果资源" :( - Adam Tal
好的,我快要抓狂了,解决不了这个问题!!! :) 尝试了一种新方法,新问题在这里:http://u.nu/4kau7 - Adam Tal
5个回答

62
您可以使用COUNT(DISTINCT ip),这将仅计算不同的值,例如:
SELECT name, COUNT(name), time, price, COUNT(DISTINCT ip), SUM(price) 
  FROM tablename 
 WHERE time >= :yesterday 
   AND time < :today GROUP BY name

4
等一下,稍等一下。尝试重现查询来回答马克的问题后发现:这个确实有效!!!我简直不敢相信。我想我可能会哭泣。 - Adam Tal
2
当您没有提供完整的SELECT语句时,我们如何理解您的意思? - micro
@AdamTal 我也是,我也是!!! - Ryan Arief

13

FROM tablename替换为FROM (SELECT DISTINCT * FROM tablename)应该可以给出你想要的结果(忽略重复行),例如:

SELECT name, COUNT(*)
FROM (SELECT DISTINCT * FROM Table1) AS T1
GROUP BY name

您的测试数据的结果:

dave 2
mark 2

好的,请问如何提取数据呢?(我以前从未使用过SELECT在SELECT之内) Table1是我的表吗?T1指什么?提前感谢。 - Adam Tal
1
@Adam:是的,Table1 是你的表名,而 T1 则是该子查询的别名,因此你也可以写成 SELECT T1.name, ...。MySQL 要求所有子查询都有别名(对这个答案点赞)。 - Peter Lang
谢谢Peter和Mark。我该如何在我的PHP中使用数据?我使用了 $data = mysql_query("SELECT..."),然后用 while($row = mysql_fetch_array($data)) { echo $row['name']; echo $row['COUNT(name)']; }。但现在它返回为空。 - Adam Tal
好的,更新: 现在的问题是,如果我有一个使用与马克相同IP地址的戴夫,然后另一个不使用相同IP地址的戴夫,这个查询就不会显示任何戴夫(尽管仍然应该计算不共享相同IP的戴夫)。尝试将DISTINCT *更改为DISTINCT ip,但是然后我会收到错误。 - Adam Tal

4
您可以只添加DISTINCT(ip),但它必须出现在查询的开头。请确保转义进入SQL字符串的PHP变量。
SELECT DISTINCT(ip), name, COUNT(name) nameCnt, 
time, price, SUM(price) priceSum
FROM tablename 
WHERE time >= $yesterday AND time <$today 
GROUP BY ip, name

尝试在开头添加DISTINCT(ip),但没有起作用,它只是忽略了它。'nameCnt'从哪里来的?我是不是写错了查询语句?(在没有'nameCnt'和'priceSum'之前,它对我起作用,除了DISTINCT的事情)... - Adam Tal
最好给列起别名,这样在 PHP 中您可以通过别名引用它们,而不必使用 $result['COUNT(name)'] - 而是使用别名 $result['nameCnt']。我认为您需要对 ip 和 name 进行 GROUP BY,回答已更新。 - Andy
1
你实际上不能这样做 - distinct不是一个函数,它是一个应用于整行的关键字,或者是聚合函数的修饰符。在你的情况下,它是SELECT的一个关键字,因此必须在列名之前使用。你放在'ip'周围的括号只是装饰性的。 - Ian Clelland

2

您的需求有些矛盾。

按名称分组(基本上是按名称加准备聚合的去重),然后按IP去重。

如果在指定的时间段内有两个人(名称)从同一个IP地址工作,您认为应该发生什么?


您试过这个吗?

SELECT name, COUNT(name), time, price, ip, SUM(price) 
  FROM tablename 
 WHERE time >= $yesterday AND time <$today 
GROUP BY name,ip

我尝试过了,但没有得到正确的结果。我想使用DISTINCT来筛选IP,是因为我不想要重复的IP地址。而我想要在名称上使用GROUP BY是为了统计名称数量(例如显示一行表格告诉我有多少人叫“马克”)。在我的数据库中,我不会有两个不同的名称使用相同的IP地址。 - Adam Tal
关于 GROUP BY name,ip ... 它没有解决问题,我认为它只按第一列分组并忽略第二列。 - Adam Tal
@Adam:它按名称和IP分组..您可以通过将IP移动到选择列表的第二个位置来更轻松地查看此内容。 - lexu
@Adam:如果您没有两个具有相同IP的名称,那么为什么您在问题中的第一个SELECT语句包含重复的IP?每个ID应该只出现一次。 - Larry Lustig
@lexu 不确定那边具体发生了什么,但它并没有消除重复项 - 无论是名称还是IP地址。 - Adam Tal
@Larry Lustig - 我的意思不是每个IP只出现一次。我的意思是,如果有两个重复的IP,它们将始终具有相同的名称。我想做的是为该IP仅计算一次该名称(即删除重复的IP)。 - Adam Tal

2
尝试以下方法:
SELECT DISTINCT(ip), name, COUNT(name) nameCnt, 
time, price, SUM(price) priceSum
FROM tablename 
WHERE time >= $yesterday AND time <$today 
GROUP BY ip, name

聚合函数可以与DISTINCT函数一起使用吗? - Ravinder Payal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接