Мне кажется, что эти два запроса одинаковы, с той лишь разницей, что они определяют, есть ли соответствующий штрих-код, и возвращают 'B' или 'R' в зависимости.
Я бы избегал лишнихRigmarole о UNION и просто сделать один запрос с условным тестом, чтобы определить, возвращается ли 'B' или 'R'.
Если намерение оператора UNION
(вместо более обычногоUNION ALL
) - для удаления дубликатов из каждого набора, для этого можно использовать предложение GROUP BY
или ключевое слово DISTINCT
.(В исходном запросе мы гарантируем, что между этими двумя наборами не будет дубликатов, так как на множестве всегда указано «R», в другом наборе всегда есть буква «B».
Я неиметь представление о спецификации для запроса, но основываясь на том, что я могу выделить из существующего запроса, я бы вместо этого попытался сделать что-то вроде этого:
SELECT user.first_name AS prenom
, user.last_name AS nom
, fvll.created_on AS created_on
, fvll.bar_code
, CASE WHEN ni.bar_code IS NULL THEN 'R' ELSE 'B' END AS r
FROM stk_fuel_voucher_line fvll
JOIN stk_fuel_voucher fv
ON fv.id = fvll.id_fuel_voucher
JOIN adm_user user
ON user.id = fv.id_user
LEFT
JOIN ( SELECT fvl.bar_code
FROM stk_fuel_voucher_line fvl
JOIN stk_fuel_voucher_book fvb
ON fvb.first_bar_code <= fvl.bar_code
AND fvb.last_bar_code >= fvl.bar_code
WHERE YEAR(fvl.created_on) = ?
AND MONTH(fvl.created_on) = ?
GROUP BY fvl.bar_code
) ni
ON ni.bar_code = fvll.bar_code
WHERE YEAR(fvll.created_on) = ?
AND MONTH(fvll.created_on) = ?
GROUP
BY user.first_name AS prenom
, user.last_name AS nom
, fvll.created_on
, fvll.bar_code
, CASE WHEN ni.bar_code IS NULL THEN 'R' ELSE 'B' END
ORDER
BY fv11.created_on
Опять же, если мы нечто касается удаления дубликатов, то мы могли бы удалить предложение GROUP BY
.
Для сравнения дат я бы выбрал сравнение необработанных дат, чтобы в запросе можно было эффективно использовать операцию сканирования диапазона индекса.
Вместо этого:
WHERE YEAR(fvll.created_on) = ?
AND MONTH(fvll.created_on) = ?
Я бы написал что-то вроде
WHERE fvll.created_on >= month_begin_dt + INTERVAL 0 MONTH
AND fvll.created_on >= month_begin_dt + INTERVAL 1 MONTH
с month_begin_dt
, представляющим выражение, которое возвращает первый день месяца, однакоэто должно быть передано, если нам нужно построить ДАТУ из года и месяца, мы могли бы сделать это. Конечная цель будет иметь эквивалент:
WHERE fvll.created_on >= '2018-05-01' + INTERVAL 0 MONTH
AND fvll.created_on >= '2018-05-01' + INTERVAL 1 MONTH