MySQL: включить COUNT SELECT Query Results в виде столбца (без группировки) - PullRequest
4 голосов
/ 30 сентября 2010

У меня есть простая структура отправки отчетов, которая в основном делает следующие вещи: Он выполняет запрос SELECT, создает на основе результатов несколько текстовых таблиц, отправляет электронное письмо и выполняет запрос UPDATE.

Эта система является обобщением более старой, в которой все операции были жестко запрограммированы. Однако, выдвигая всю логику того, что я хотел бы сделать, в запрос SELECT, я столкнулся с проблемой.

Раньше я мог получить большую часть информации для своих текстовых таблиц, говоря:

SELECT Name, Address FROM Databas.Tabl WHERE Status='URGENT';

Затем, когда мне понадобится дополнительный номер для электронной почты, также выполните:

SELECT COUNT(*) FROM Databas.Tabl WHERE Status='URGENT' AND TimeLogged='Noon';

Теперь у меня больше нет роскоши множественных запросов SELECT. То, что я хотел бы сделать, это что-то вроде:

SELECT Tabl.Name, Tabl.Address, COUNT(Results.UID) AS Totals
FROM Databas.Tabl
LEFT JOIN Databas.Tabl Results
    ON Tabl.UID = Results.UID
    AND Results.TimeLogged='Noon'
WHERE Status='URGENT';

Это, по крайней мере, в моей голове, говорит, чтобы получить общее количество всех строк, которые были выбраны, а также имеют некоторые условные.

В действительности, однако, это дает мне ошибку «1140 - Смешивание столбцов GROUP без столбцов GROUP, недопустимых, если нет GROUP BY». Проблема в том, что я не хочу GROUP BY. Я хочу, чтобы этот COUNT излишне повторял количество найденных SELECT результатов, у которых TimeLogged = 'Noon'. Или я хочу удалить предложение AND и включить в качестве столбца в результат оператора SELECT количество результатов, найденных этим оператором SELECT.

GROUP BY не является ответом, потому что это заставляет его получать COUNT только тех строк, которые имеют одинаковое значение в некотором столбце. И COUNT, возможно, даже не способ обойти это, хотя это то, что приходит на ум. FOUND_ROWS () не сработает, так как он должен быть частью вторичного запроса, и я получаю только один (плюс в нем нет LIMIT), а ROW_COUNT (), похоже, не работает, так как это оператор SELECT.

Возможно, я подхожу к этому с неправильного угла. Но я хочу получить информацию типа COUNT о результатах запроса SELECT, а также всю другую информацию, возвращенную запросом SELECT, в одном запросе.

=== Вот что у меня так далеко ===

SELECT Tabl.Name, Tabl.Address, Results.Totals
FROM Databas.Tabl
LEFT JOIN (SELECT COUNT(*) AS Totals, 0 AS Bonus
           FROM Databas.Tabl
           WHERE TimeLogged='Noon'
           GROUP BY NULL) Results
     ON 0 = Results.Bonus
WHERE Status='URGENT';

При этом используются подвыборы, которых я изначально надеялся избежать, но теперь понимаю, что надежда могла быть глупой. Кроме того, кажется, что подзапросы COUNTing SELECT будут дешевле, чем основной запрос, поскольку все условные выражения COUNT находятся в одной таблице, но настоящий SELECT, с которым я работаю, должен объединять несколько разных таблиц для получения производной информации.

Ключевым моментом является то, что я могу использовать GROUP BY NULL, который будет возвращать один результат, так что COUNT (*) будет фактически перехватывать все, и что я могу принудительно установить корреляцию с этим столбцом, просто подставив столбец Bonus с 0 на обе таблицы.

Похоже, что это решение, которое я буду использовать, но я не могу принять его как ответ до завтра. Спасибо за помощь.

Ответы [ 5 ]

11 голосов
/ 30 сентября 2010
SELECT Tabl.Name, Tabl.Address, Results.Totals
FROM Databas.Tabl
LEFT JOIN (SELECT COUNT(*) AS Totals, 0 AS Bonus
           FROM Databas.Tabl
           WHERE TimeLogged='Noon'
           GROUP BY NULL) Results
     ON 0 = Results.Bonus
WHERE Status='URGENT';

Я понял это благодаря идеям, созданным несколькими ответами, хотя на самом деле это не прямой результат любого.Почему это делает то, что мне нужно, было объяснено в редактировании исходного поста, но я хотел иметь возможность решить вопрос с правильным ответом на тот случай, если кто-то еще захочет выполнить эту глупую операцию.Спасибо всем, кто помог.

2 голосов
/ 30 сентября 2010

Вы могли бы вместо этого сделать союз. Вам нужно будет добавить столбец к исходному запросу и выбрать в нем 0, а затем UNION с вашим вторым запросом, который возвращает один столбец. Для этого во втором запросе также необходимо выбрать пустые поля, соответствующие первому.

SELECT Cnt = 0, Name, Address FROM Databas.Tabl WHERE Status='URGENT'
UNION ALL
SELECT COUNT(*) as Cnt, Name='', Address='' FROM Databas.Tabl WHERE Status='URGENT' AND TimeLogged='Noon';

Это что-то вроде хака, но то, что ты пытаешься сделать, не идеально ...

1 голос
/ 30 сентября 2010

Делает ли это то, что вам нужно?

SELECT   Tabl.Name                   ,
         Tabl.Address                ,
         COUNT(Results.UID) AS GrandTotal,
         COUNT(CASE WHEN Results.TimeLogged='Noon' THEN 1 END) AS NoonTotal
FROM     Databas.Tabl
         LEFT JOIN Databas.Tabl Results
         ON       Tabl.UID = Results.UID
WHERE    Status            ='URGENT'
GROUP BY Tabl.Name,
         Tabl.Address
WITH ROLLUP;
0 голосов
/ 30 сентября 2010

Группировка по Tabl.id Я не верю, что испортит результаты. Попробуйте и посмотрите, хотите ли вы этого.

0 голосов
/ 30 сентября 2010

API, который вы используете для доступа к базе данных, должен иметь возможность сообщать вам, сколько строк было возвращено - скажем, если вы используете Perl, вы можете сделать что-то вроде этого:

my $sth  = $dbh->prepare("SELECT Name, Address FROM Databas.Tabl WHERE Status='URGENT'");
my $rv   = $sth->execute();
my $rows = $sth->rows;
...