0 результатов при использовании COUNT с HAVING, но строки существуют на самом деле - MySQL - PullRequest
0 голосов
/ 10 марта 2019

У меня есть таблица, в которой я хочу посчитать записи для каждого домена

У меня есть такой запрос. Вот 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' 

Возвращает 0 результатов при использовании SELECT COUNT(*), но при использовании SELECT *

возвращает больше, чем результатЯ делаю не так?

Ответы [ 3 ]

3 голосов
/ 10 марта 2019

Вы пропустили группу по домену

    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' 

если вы не добавите имя столбца для группы, вы получите непредсказуемое значение для count (*) (первое значение, добавленное механизмом БД .. в вашем случае 0)

это происходит для версии mysql <5.7 (начиная с формы mysql 5.7, использование функции агрегации без группировки не допускается также во избежание этой ситуации = </p>

2 голосов
/ 10 марта 2019

Одним из решений является добавление 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.В общем случае лучше фильтровать до агрегации , чем после.

0 голосов
/ 10 марта 2019

Вы должны сгруппировать по домену:

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 подходит только с GROUP BY в операторе SQL:

предложение HAVING должно идти после любого предложения GROUP BY и перед любым ЗАКАЗАТЬ по пункту

из https://dev.mysql.com/doc/refman/8.0/en/select.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...