2016-09-19 6 views
0

У меня есть запрос MySQL с четырьмя операторами IF, которые должны установить псевдоним «1» или «0» в соответствии с условиями внутри. Хотя у меня нет никаких ошибок, единственный IF, возвращающий правильные значения, совпадает с псевдонимом is_paid.Запрос MySQL с несколькими операторами IF, не возвращающими ожидаемые результаты

Я дважды проверял условия для других трех псевдонимов, и даже если они в порядке, я все равно получаю фиктивные результаты.

Я что-то не так? Есть ли способ написать запрос, чтобы я мог получить ожидаемые результаты?

Вот запрос:

SELECT r.doc_number, 
     r.doc_date, 
     r.due_date, 
     r.currency, 
     r.amount, 
     r.vat, 
     r.vatammount, 
     (r.amount + r.vatammount) final_amount, 
     r.currency, 
     b.boq_id, 
     b.boq_comp_id, 
     b.boq_client_id, 
     b.boq_agency, 
     b.boq_date, 
     b.boq_orders, 
     b.receivable_id, 
     c.comp_name, 
     crm.`cn-name-first`, 
     crm.`cn-name-last`, 
     bi.inv_path, 
     (SELECT SUM(amount_recieved) FROM receivables_payments WHERE r_id = b.receivable_id) total_amount_received, 
     IF (r.amount + r.vatammount = (SELECT SUM(amount_recieved) FROM receivables_payments WHERE r_id = b.receivable_id), '1', '0') AS is_paid, 
     IF (CURRENT_DATE >= r.due_date AND r.amount + r.vatammount != (SELECT SUM(amount_recieved) FROM receivables_payments WHERE r_id = b.receivable_id), '1', '0') AS is_overdue, 
     IF (r.due_date < CURRENT_DATE AND r.amount + r.vatammount != (SELECT SUM(amount_recieved) FROM receivables_payments WHERE r_id = b.receivable_id), '1', '0') AS is_outstanding, 
     IF (r.due_date = CURRENT_DATE AND r.amount + r.vatammount != (SELECT SUM(amount_recieved) FROM receivables_payments WHERE r_id = b.receivable_id), '1', '0') AS is_due_today 
FROM receivables r 
LEFT JOIN boq b ON b.receivable_id = r.id 
LEFT JOIN boq_invoices bi ON bi.inv_boq_id = b.boq_id 
LEFT JOIN comp_companies c ON c.comp_id = b.boq_comp_id 
LEFT JOIN crm_contacts crm ON crm.contact_id = b.boq_client_id 
WHERE r.status = 'active' 
    AND r.doc_type = 'inv' 
    AND b.boq_status = 'active' 
GROUP BY r.id 
HAVING is_due_today = '1' 
ORDER BY r.doc_date DESC 
LIMIT 10 
+1

ваше 'if' overlap .. 'current_date> = r.due_date' и' r.due_date = current_date' будет инициировать BOTH, если значения равны. поэтому вы в основном говорите, что что-то из-за «сегодняшнего дня» как просрочено, так и сегодня. –

+0

Булево значение по определению '1' и' 0'. Нет необходимости переводить 'IF'. – shmosel

+1

Вместо того, чтобы помещать 'SELECT' в каждый' IF', я предлагаю вам присоединиться к подзапросу, который вычисляет 'SUM (amount_received) GROUP BY r_id'. – Barmar

ответ

0

У вас есть проблемы с null -comparisons. 20 != 0 - true, но 20 != null - null (что имеет такой же эффект, как false в IF).

IF (... r.amount + r.vatammount != 
     (SELECT SUM(amount_recieved) 
     FROM receivables_payments WHERE r_id = b.receivable_id) 
    , '1', '0') AS is_overdue, 

null/false будет в тех случаях, когда у вас нет каких-либо подгоночных строки в receivables_payments (так, вероятно, в тех случаях, без оплаты), потому что SUM(amount_recieved) будет null. Таким образом, вы не получите правильный флаг.

Вы можете использовать coalesce(value,0), чтобы получить 0 когда значение null, так что вы можете сравнить, как вы привыкли:

IF (... r.amount + r.vatammount != 
     COALESCE(SELECT SUM(amount_recieved) 
     FROM receivables_payments WHERE r_id = b.receivable_id),0) 
    , '1', '0') AS is_overdue, 

Вы должны фактически сделать это для всех 5 колонок, которые используют сумму (флаги и total_amount_received), поскольку, например, в случае, если у вас есть счет на сумму 0, флаг is_paid также будет недействительным.

+0

Я действительно добрался до этой версии: http://pastebin.com/aNSxM2Hk Прекрасно работает для всех псевдонимов, но не для 'is_outstanding', и я не знаю почему. – Cosmin

+0

@Cosmin' is_outstanding' точно так же, как 'is_overdue' (вы только что переключили' CURRENT_DATE> r.due_date' на ' r.due_date Solarflare

0

Ваш запрос имеет общие вопросы:

  • Прежде всего может быть много Boq в дебиторской задолженности. Вы группируетесь по дебиторской задолженности, но не указываете, какие данные boq должны отображаться (например, максимальный boq_id всех boqs, принадлежащих дебиторской задолженности, с max(b.boq_id)). Таким образом, вы просто показываете один из подходящих boq_id, один из подходящих boq_comp_id и т. Д., Все произвольно выбранные. Они даже не должны принадлежать к одной записи, поэтому вы можете получить boq_id из одной записи, boq_comp_id из другого и т. Д.
  • Тогда вы нарушите соединение boq. Таким образом, вы хотите показать дебиторскую задолженность, даже если у них нет каких-либо связанных с этим проблем. Но в вашем предложении WHERE вы требуете b.boq_status = 'active'. Столбцы с объединенными данными - NULL. Таким образом, никакие внешние объединенные записи не совпадают, и вы сразу же их увольняете. Либо вы хотите для внешнего соединения, а затем установите условие в предложение ON, или вы этого не сделаете, затем используйте INNER JOIN (или короткий JOIN, если на то пошло).

Теперь ваши оценки:

  • is_overdue когда уплаченная сумма не соответствует сумме к оплате и due_date сегодня или в прошлом.
  • is_outstanding - это когда выплаченная сумма не соответствует сумме, подлежащей оплате, а due_date прошло.
  • is_due_today - это когда уплаченная сумма не соответствует сумме, подлежащей оплате, а due_date - сегодня.

У меня все в порядке. Ну, вы считаете переплату как неоплачиваемую, но, возможно, они невозможны в вашей базе данных. Если сумма не удовлетворена, а due_date - сегодня, устанавливаются оба is_overdue и is_due_today. Если сумма не выполнена, а due_date - на прошлой неделе, устанавливаются оба параметра is_overdue и is_outstanding.

Не так ли? Какова ваша фактическая проблема с ними?

+0

Существует только одна дебиторская/boq Выдающиеся средства не оплачиваются, но срок платежа не был выполнен все же. – Cosmin

+0

Я знаю, что это одна дебиторская задолженность за boq, но это несколько boq за дебиторскую задолженность. Вот почему вы не можете показать * * boq для дебиторской задолженности. Итак, какой boq вы хотите показать для дебиторской задолженности? Последний? Старейший? Пока вы не сказали СУБД. Если вы хотите, чтобы 'due_date' для' is_outstanding' находился в * будущем *, тогда сделайте его 'IF (r.due_date> CURRENT_DATE AND ...' –

+0

Нет, выдающийся означает, что 'r.due_date Cosmin

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