我有一个表,要在其中计算每个域的记录
我有这样的查询。 Here is sqlfiddle表模式和查询
SELECT
COUNT(*),
SUBSTRING_INDEX( TRIM( LEADING 'www.' FROM TRIM( LEADING 'http://' FROM TRIM( LEADING 'https://' FROM link ) ) ), '/', 1 ) AS domain
FROM
links
WHERE
source = 'web'
AND DATE( last_seen ) = DATE( NOW( ) )
HAVING
domain = 'testingwebsite.com'
使用SELECT COUNT(*)
时返回0个结果,但使用SELECT *
时返回多个结果
我做错了什么?
答案 0 :(得分:3)
您未按域分组
SELECT
COUNT(*),
SUBSTRING_INDEX( TRIM( LEADING 'www.' FROM TRIM( LEADING 'http://' FROM TRIM( LEADING 'https://' FROM link ) ) ), '/', 1 ) AS domain
FROM
links
WHERE
source = 'web'
AND DATE( last_seen ) = DATE( NOW( ) )
group by domain
HAVING
domain = 'testingwebsite.com'
如果您不添加group的列名,那么您将获得count(*)不可替代的值(在您的情况下,第一个由db engine ..遇到的值)
这种情况在mysql版本<5.7上发生(从mysql 5.7开始,不允许使用没有group by的聚合函数,也是为了避免这种情况=
答案 1 :(得分:2)
一种解决方案是添加GROUP BY
。首先,您应该了解原因。
您有一个没有GROUP BY
的聚合查询。 总是会产生一行。但是,未聚合的列(domain
)将具有任意值。它可能与您比较中的域匹配,也可能不匹配。
您可以通过多种方式解决此问题。最有效的方法是省去domain
中的SELECT
,而只在WHERE
中引用它:
SELECT COUNT(*)
FROM links l
WHERE source = 'web' AND
last_seen >= CURDATE() AND -- probably no last_seen values in the future
'testingwebsite.com' = SUBSTRING_INDEX( TRIM( LEADING 'www.' FROM TRIM( LEADING 'http://' FROM TRIM( LEADING 'https://' FROM link ) ) ), '/', 1 )
这保证返回一行,无论是否有任何行与WHERE
子句匹配。如果没有行匹配,则计数将为0
。我怀疑那是您想要的。
请注意,我也更改了日期比较。这样,查询就可以使用links(source, last_seen)
上的索引。
最后,如果您确实希望在SELECT
中使用该域,但又不想重复该域,则建议使用子查询:
SELECT domain, COUNT(*)
FROM (SELECT l.*,
SUBSTRING_INDEX( TRIM( LEADING 'www.' FROM TRIM( LEADING 'http://' FROM TRIM( LEADING 'https://' FROM link ) ) ), '/', 1 ) as domain
FROM links l
) l
WHERE source = 'web' AND
last_seen >= CURDATE() AND -- probably no last_seen values in the future
domain = 'testingwebsite.com'
GROUP BY domain;
请注意,如果数据中不存在域,则不会返回任何行。
关于效果的评论。此版本确实实现了子查询,这会产生开销(这是MySQL的缺点,但不是其他数据库的缺点)。但是,您的版本不仅实现了子查询,而且还聚合了所有数据,因此它应该比使用HAVING
更快。通常,最好在聚合前 而不是事后进行过滤。
答案 2 :(得分:0)
您必须按域分组:
SELECT
COUNT(*),
SUBSTRING_INDEX( TRIM( LEADING 'www.' FROM TRIM( LEADING 'http://' FROM TRIM( LEADING 'https://' FROM link ) ) ), '/', 1 ) AS domain
FROM
links
WHERE
source = 'web'
AND DATE( last_seen ) = DATE( NOW( ) )
GROUP BY domain
如果您想要特定域的结果,可以添加:
HAVING
domain = 'testingwebsite.com'
HAVING
仅适用于SQL语句中的GROUP BY
:
HAVING子句必须在任何GROUP BY子句之后且在任何 ORDER BY子句