2016-08-23 3 views
1

Я хочу сделать запрос, который добавит очки для команды. Точки складываются путем выполнения SUM в столбце + SUM из другой таблицы с тем же идентификатором команды. Я стараюсь писать так:MySQL SUM (столбец) + (SUBQUERY WITH SUM)

SELECT 
    k.id, 
    s.fylke, 
    s.Kommune, 
    s.Skolenavn, 
    k.schoolid, 
    k.number, 
    k.letter, 
    SUM(e.amount) + (SELECT SUM(poeng) FROM oppdrag WHERE klasseid=k.id) AS poeng 
FROM skoler AS s, klasser AS k, etappe AS e 
WHERE s.id=k.schoolid AND k.id=e.klasseid AND e.year='2016' 
GROUP BY k.id 
ORDER BY poeng 

Проблема заключается в том, что, когда я пишу это таким образом, это дает правильное количество очков, если команда имеет запись в таблице «oppdrag» Otherways он просто возвращает NULL как точки (poeng).

ответ

2

Если ваш подзапрос возвращает NULL, это приведет к попытке суммировать число с NULL, что дает NULL назад.

Чтобы исправить это, вы можете попробовать использовать функцию IFNULL, которая заменит его с 0, если запрос не возвращает значения:

SELECT 
    k.id, 
    s.fylke, 
    s.Kommune, 
    s.Skolenavn, 
    k.schoolid, 
    k.number, 
    k.letter, 
    SUM(e.amount) + IFNULL((SELECT SUM(poeng) FROM oppdrag WHERE klasseid=k.id), 0) AS poeng 
FROM skoler AS s, klasser AS k, etappe AS e 
WHERE s.id=k.schoolid AND k.id=e.klasseid AND e.year='2016' 
GROUP BY k.id 
ORDER BY poeng 
+0

Спасибо, решает проблему простым способом :) – johnohod

1

Во-первых, научиться использовать явное JOIN синтаксис. Простое правило: Никогда запятые запятые в разделе FROM. Всегда использовать явно JOIN с ON.

Затем вы можете решить вашу проблему, в том числе подзапроса в предложении FROM:

SELECT ske.*, ske.amount + COALESCE(od.amount, 0) as poenb 
FROM (SELECT k.id, s.fylke, s.Kommune, s.Skolenavn, k.schoolid, 
      k.number, k.letter, SUM(e.amount) as amount 
     FROM skoler s JOIN 
      klasser k 
      ON s.id = k.schoolid JOIN 
      etappe e 
      ON k.id = e.klasseid AND e.year = '2016' 
     GROUP BY k.id 
    ) ske LEFT JOIN 
    (SELECT od.klasseid, SUM(od.poeng) as amount 
     FROM oppdrag od 
     GROUP BY od.klasseid 
    ) od 
    ON od.klasseid = k.id 
ORDER BY poeng; 
2

Я бы избежать этого подзапроса от вашего оператора выбора, он собирается убить производительность. Кроме того, вы действительно должны использовать правильный синтаксис соединения (стиль, который вы используете, является древним). Попробуй что-нибудь вроде этого;

SELECT 
    k.id, 
    s.fylke, 
    s.Kommune, 
    s.Skolenavn, 
    k.schoolid, 
    k.number, 
    k.letter, 
    SUM(e.amount) + ISNULL(SUM(od.poeng),0) AS poeng 
FROM skoler AS s 
INNER JOIN klasser AS k 
    ON s.id = k.schoolid 
INNER JOIN etappe AS e 
    ON k.id = e.klasseid 
LEFT JOIN oppdrag od 
    ON od.klasseid = k.id 
WHERE e.year='2016' 
GROUP BY k.id 
ORDER BY poeng 
+0

Возможно, вы правы. Похоже, что лучше писать с помощью JOINS. Но похоже, что два стиля запросов используют одно и то же время для запуска, поэтому я не уверен, что он убивает производительность. – johnohod

+0

все зависит от того, сколько данных вы обрабатываете. Подзапрос с выбором будет вызываться один раз для каждой строки результирующего набора. Если вы присоединитесь к нему, это будет просто вызвано один раз в общей сложности. –

+0

У меня такое ощущение, что подзапрос не запускается один раз в строке. Я использовал такие подзапросы много раз с хорошей производительностью. Я думаю, что запрос оптимизирован до его выполнения. Но я согласен, ваш синтаксис лучше и имеет больший контроль над тем, что происходит, мой неряшливый :) – johnohod

1

Использовать явный синтаксис JOIN. Кроме того, включите все столбцы, которые не агрегированы в разделе GROUP BY. Просто потому, что MySQL не дает ошибку, это не значит, что это целесообразно сделать так, как вы это сделали. Не включая все столбцы, которые не объединены в группу, путем выбора случайных значений.

SELECT 
    k.id, 
    s.fylke, 
    s.Kommune, 
    s.Skolenavn, 
    k.schoolid, 
    k.number, 
    k.letter, 
    COALESCE(SUM(e.amount), 0) + COALESCE(SUM(o.poeng), 0) AS poeng 
FROM skoles AS s 
INNER JOIN klasser AS k ON s.id = k.schoolid 
INNER JOIN etappe AS e ON k.id = e.klasseid 
LEFT JOIN (SELECT klasseid, SUM(poeng) AS poeng FROM oppdrag) AS o ON o.klasseid = k.id 
WHERE e.year = '2016' 
GROUP BY k.id, s.fylke, s.Kommune, s.Skolenavn, k.schoolid, k.number, k.letter 
ORDER BY poeng