Вопрос

Мне нужно запросить эту базу данных, чтобы получить каждую строку, а также СУММУ значений одного из столбцов результатов.Я мог бы использовать php для получения общего значения, но тогда мне нужно было бы запустить два цикла, один для получения общего значения (которое находится вверху над результатами).Поэтому я бы предпочел, чтобы запрос перехватил его и просто создал строку "total", но единственный способ заставить его работать - это использовать подзапрос, который по сути является повторением исходного запроса.Есть ли лучший способ?

SELECT 
CONCAT(u.firstname, ' ', u.lastname ) name, u.id, s.description, s.shiftstart, s.shiftend, 
    (SELECT 
    SUM( TIME_TO_SEC( TIMEDIFF( shiftend, shiftstart ) ) ) /3600
    FROM shifts
    WHERE id =  '$user'
    AND DATE( shiftstart )
    BETWEEN '$start'
    AND '$end') total
FROM shifts s
INNER JOIN users u ON ( s.id = u.id )
WHERE s.id = '$user'
AND DATE( shiftstart )
BETWEEN '$start'
AND '$end'
ORDER BY shiftstart

Вышеуказанные работы и результаты:

name        id     description  shiftstart             shiftend               total
Joe User    joeuser    Stuff    2009-01-05 07:45:00    2009-01-05 12:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-05 13:00:00    2009-01-05 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 07:45:00    2009-01-06 10:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 10:45:00    2009-01-06 12:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 13:30:00    2009-01-06 14:30:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 14:30:00    2009-01-06 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-07 09:45:00    2009-01-07 14:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-07 15:00:00    2009-01-07 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-08 08:00:00    2009-01-08 12:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-08 13:15:00    2009-01-08 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 07:45:00    2009-01-09 10:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 11:45:00    2009-01-09 15:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 15:15:00    2009-01-09 17:00:00    39.5000

Это то, что мне нужно, но, вероятно, не лучший способ это получить.

Это было полезно?

Решение

MySQL поддерживает специальный модификатор group-by, называемый СВЕРТКА.

SELECT CONCAT(u.firstname, ' ', u.lastname ) name, u.id, 
  s.description, s.shiftstart, s.shiftend, 
  SUM( TIME_TO_SEC( TIMEDIFF( shiftend, shiftstart ) ) ) /3600 total
FROM shifts s INNER JOIN users u ON ( s.id = u.id )
WHERE s.id = ? AND DATE( shiftstart ) BETWEEN ? AND ?
GROUP BY u.id, s.shiftstart WITH ROLLUP
ORDER BY shiftstart;

Другие советы

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

Запустите два запроса из вашего кода.Сначала выведите больший набор, а затем общую строку в любом желаемом формате.Ваши запросы станут меньше и проще, ваша производительность повысится, и вы получите желаемый результат.

Еще один совет - дисковое пространство стоит дешево, и большинство таблиц базы данных читаются гораздо чаще, чем записываются.Настройте триггер вставки / обновления (если это возможно в MySQL) для заполнения отдельного столбца вычисляемыми полями типа "CONCAT(u.firstname,' ',u.lastname)" и используйте это для запросов.Функции для каждой строки не масштабируются и будут снижать производительность вашей СУБД по мере ее увеличения.

По сравнению с этим все может быть лучше;вопрос в сравнении с чем, не так ли?

Ключевая проблема, на которую вы указали, заключается в том, что вы хотели, чтобы итоговая сумма была в верхней части результатов;Crystal Reports и другие приложения управляют такого рода магией, являясь двухпроходным движком.При первом проходе подсчитываются итоги.

При любом решении есть компромиссы.Если вы получите отдельную строку "итого", то принимающему приложению нужно будет либо вычеркнуть ее из результатов, либо использовать какой-нибудь другой трюк, чтобы скрыть ее.

Одна из возможностей, которая может быть приемлемой, если вы не пишете для сайта с посещаемостью в 1 миллион просмотров в час, - это просто сделать 2 звонка: один для получения дополнительной информации, такой как имя, общее время и т.д., А затем для уточнения деталей ...Это появляется из запроса, который вы выбираете по результатам одного человека.

Мы все за экономию накладных расходов и пропускной способности, но иногда проще, чем лучше...

Редактировать:Пакс опередила меня , нажав на кнопку "Сохранить" ...лол...

Используйте расширение mysql, предоставленное именно для этой цели, как описано в ответе Билла Карвина (за который я сам проголосовал).

Если бы это было недоступно, вариантом 2 был бы другой оператор SQL:ВЫБЕРИТЕ СУММУ ...) SQL действительно оптимизирован, чтобы быть чрезвычайно эффективным для такого рода задач, по сравнению с любым циклом процедурного кода, который вы, вероятно, напишете.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top