2013-09-13 4 views
1

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

Способ, которым он работает, состоит в том, что существует одна таблица под названием forecastwaste и таблица с именем wastestream. wastestream содержит все данные о типах отходов, которые фактически были переработаны, а forecastwaste содержит типы отходов, которые были предсказаны. Таблица wastetypes содержит имя доступных типов wastetypes, которые пользователь может выбрать.

У меня есть этот SQL Statement ($contractid содержит идентификатор контракта):

SELECT ws.wastetype, SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent, wt.id, wt.category, wt.defrecycling, fw.tonnes 
FROM wastestream ws, wastetypes wt, forecastwaste fw 
WHERE ws.contractid = ".$contractid." 
AND fw.contractid = ".$contractid." 
AND ws.wastetype = wt.id 
AND fw.wastetype = wt.id 
GROUP BY ws.wastetype 

Однако проблема у меня есть, что если есть тип отходов в forecastewate таблице, не в wastestream таблица запроса ничего не отображает. Я хочу получить его так, чтобы, если в таблице wastestream результатов не было найдено, запрос будет по-прежнему отображать запись прогноза и возвращать 0, если он ничего не может найти. Текущий запрос не позволяет этого.

Как я могу заставить запрос работать так, чтобы он выполнял то, что мне нужно?

EDIT
Благодаря Bandydan я переписал запрос так теперь выглядит следующим образом:

SELECT ws.wastetype, SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent, wt.id, wt.category, wt.defrecycling, fw.tonnes 
FROM c1skips.wastestream ws 
LEFT JOIN c1skips.wastetypes wt ON (wt.id = ws.wastetype) 
INNER JOIN c1skips.forecastwaste fw ON (wt.id = fw.wastetype) 
WHERE fw.contractid = '602' 
AND ws.contractid = '602' 
GROUP BY ws.wastetype; 

Я объясню, что я пытаюсь сделать немного лучше тоже.

У меня есть таблица под названием forecastwaste и в этой таблице у меня есть следующие данные:

|---------------------------------| 
| wastetype | tonnes | contractid | 
|-----------|--------|------------| 
|  1  | 10 | 602  | 
|  2  | 20 | 602  | 
|  3  | 50 | 602  | 
|-----------|--------|------------| 

Эта таблица затем используется, чтобы посмотреть на wastestream стол, чтобы увидеть, как большая часть материала перерабатывается. Таблица wastestream выглядит следующим образом:

|-----------------------------------------| 
| wastetype | recordedweight | contractid | 
|-----------|----------------|------------| 
|  1  |  2  |  602 | 
|  1  |  4  |  602 | 
|  2  |  20  |  602 | 
|-----------|----------------|------------| 

Обе таблицы ссылаются на wastetype таблицу, которая идентифицирует номер с типом отходов.

С текущим запросом он возвращает результаты только в том случае, если они отображаются в таблице wastestream. Тем не менее, я хочу это так, что даже если нет записи в таблице wastestream вернет 0.

EDIT 2
Я добавил COALESCE на мой запрос, как это:

SELECT ws.wastetype, SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent, wt.id, wt.category, wt.defrecycling, 
COALESCE(ws.recordedweight, 0) tonnes 
FROM c1skips.wastestream ws 
LEFT JOIN c1skips.wastetypes wt ON (wt.id = ws.wastetype) 
INNER JOIN c1skips.forecastwaste fw ON (wt.id = fw.wastetype) 
WHERE fw.contractid = '602' 
AND ws.contractid = '602' 
GROUP BY ws.wastetype; 

Но результаты все те же. Это будет либо SUM(ws.recordedweight) totalWeight, либо SUM(ws.percent) totalPercent, которые возвращают значения NULL в таблице wastestream, но в таблице forecaste будет указано значение, пытающееся ссылаться на них, но COALESCE не будет работать с этим.

+2

Рассмотрите возможность первой замены этого оператора на тот, который использует INNER JOINs для упрощения чтения. Тогда это вопрос использования LEFT JOIN. –

ответ

1

Вам необходимо внутреннее соединение между forecastwaste и wastetypes плюс Left Join к wastestream:

SELECT ws.wastetype, SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent, wt.id, wt.category, wt.defrecycling, fw.tonnes 
FROM c1skips.forecastwaste fw 
JOIN c1skips.wastetypes wt ON (wt.id = fw.wastetype) 
LEFT JOIN c1skips.wastestream ws 
ON (ws.contractid = fw.contractid) AND (ws.wastetype = fw.wastetype) 
WHERE fw.contractid = '602' 
GROUP BY ws.wastetype; 

Я заменил fw.contractid = '602' с (ws.contractid = fw.contractid) как условие присоединения. Теперь нет необходимости писать контракт в двух местах, и вы можете запустить запрос без WHERE, чтобы вернуть все строки.

Edit: Изменен внешний таблицу из wastestream в forecastwaste

+0

Этот запрос возвращает неверные данные. Если я изменил 'ws.contractid' на' fw.contractid', отобразятся правильные данные. Однако запись значения «0» по-прежнему не отображается. – mickburkejnr

+0

Хорошо, ваша внешняя таблица (т. Е. Таблица, в которой вы хотите все строки, даже если нет совпадения) является прогнозируемой. Я изменил ответ, надеюсь, теперь все правильно. – dnoeth

+0

FANTASTIC! Спасибо, сэр, что сделал трюк! – mickburkejnr

0

Я думаю, вам нужно переписать тот, который использует соединения, тогда вы сможете использовать LEFT JOIN. Он работает так, как вам нужно.

То, что я могу сделать в нескольких минутах выглядит следующим образом:

SELECT ws.wastetype, SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent, wt.id, wt.category, wt.defrecycling, fw.tonnes 
    FROM wastetypes wt 
    LEFT JOIN wastestream ws ON (wt.id = ws.wastetype) 
    INNER JOIN forecastwaste fw USING(wt.id = fw.wastetype) 
    WHERE wt.contractid = ".$contractid." 
    GROUP BY ws.wastetype 

Здесь я предполагаю, что вам нужна информация от масс, информация о том же типе, что ВОЗМОЖНО существует в WS и информации о том, что type from fw (это определенно существует). Я не уверен, что это правильно, потому что у меня нет таблиц для проверки, но я хотел показать вам всю идею.

Посмотрите ответы на вопросы that question, и вы найдете способ решить вашу проблему.

0

Try:

SELECT 
    wt.wastetype, wt.id, wt.category, wt.defrecycling, 
    SUM(ws.recordedweight) totalWeight, SUM(ws.percent) totalPercent, 
    COALESCE(fw.tonnes, 0) tonnes 
FROM c1skips.wastetypes wt 
LEFT JOIN c1skips.wastestream ws ON (wt.id = ws.wastetype) 
LEFT JOIN c1skips.forecastwaste fw ON (wt.id = fw.wastetype) 
WHERE fw.contractid = '602' 
AND ws.contractid = '602' 
GROUP BY ws.wastetype; 

Обратите внимание, что FROM было изменено на wastetypes, wastestream перемещается в LEFT JOIN и есть функция COALESCE.

+0

Обновлен мой ответ. – mickburkejnr

+0

Но как насчет других частей запроса? У вас все еще есть 'FROM c1skips.wastestream', в то время как он должен быть добавлен с помощью' LEFT JOIN'. Вы не можете иметь строки в результате, которые отсутствуют в таблице, которая определена в 'FROM'. Каков результат, если вы выполняете весь запрос, который я предложил? – Alex

+0

'wt.wastetype' был некорректным, поэтому я изменил его на' ws.wastetype', но запрос показал те же результаты, что и запрос, который у меня был раньше. – mickburkejnr

0

Основываясь на втором редактирования я бы рекомендовал:

SELECT ws.wastetype, SUM(COALESCE(ws.recordedweight, 0)) totalWeight, SUM(COALESCE(ws.percent, 0)) totalPercent, wt.id, wt.category, wt.defrecycling, 
COALESCE(ws.recordedweight, 0) tonnes 
FROM c1skips.forecastwaste fw 
LEFT JOIN c1skips.wastetypes wt ON (wt.id = fw.wastetype) 
LEFT JOIN c1skips.wastestream ws ON (wt.id = ws.wastetype) 
WHERE fw.contractid = '602' 
AND ws.contractid = '602' 
GROUP BY ws.wastetype; 

Это должно работать, используя COALESCE внутри суммы предотвращения аннулирует, и оставил присоединение к forecastwaste.

Смежные вопросы