#php #mysql #sql
#php #mysql #sql
Вопрос:
У меня есть этот запрос, который будет подключаться к моей базе данных. Я столкнулся с тем, что загрузка данных, которые я хочу, происходит слишком медленно.
SELECT
IFNULL((SELECT SUM(c.due_to_office) AS dt_amount FROM sales_entry_summary a, sales_products b, sales_entry c WHERE a.ses_id = c.ses_id AND a.sales_date = '2019-01-01' AND a.`status` = 'AUDITED' AND a.product_id = b.product_id AND b.so_category = 'DT'),0) AS dt_amounts,
IFNULL((SELECT SUM(c.due_to_office) AS rt_amount FROM sales_entry_summary a, sales_products b, sales_entry c WHERE a.ses_id = c.ses_id AND a.sales_date = '2019-01-01' AND a.`status` = 'AUDITED' AND a.product_id = b.product_id AND b.so_category = 'RT'),0) AS rt_amounts,
IFNULL((SELECT SUM(c.due_to_office) AS it_amount FROM sales_entry_summary a, sales_products b, sales_entry c WHERE a.ses_id = c.ses_id AND a.sales_date = '2019-01-01' AND a.`status` = 'AUDITED' AND a.product_id = b.product_id AND b.so_category = 'IT'),0) AS it_amounts,
IFNULL((SELECT SUM(c.due_to_office) AS lr_amount FROM sales_entry_summary a, sales_products b, sales_entry c WHERE a.ses_id = c.ses_id AND a.sales_date = '2019-01-01' AND a.`status` = 'AUDITED' AND a.product_id = b.product_id AND b.so_category = 'LR'),0) AS lr_amounts,
IFNULL((SELECT SUM(c.due_to_office) AS ir_amount FROM sales_entry_summary a, sales_products b, sales_entry c WHERE a.ses_id = c.ses_id AND a.sales_date = '2019-01-01' AND a.`status` = 'AUDITED' AND a.product_id = b.product_id AND b.so_category = 'IR'),0) AS ir_amounts,
IFNULL((SELECT SUM(c.due_to_office) AS v_amount FROM sales_entry_summary a, sales_products b, sales_entry c WHERE a.ses_id = c.ses_id AND a.sales_date = '2019-01-01' AND a.`status` = 'AUDITED' AND a.product_id = b.product_id AND b.so_category = 'V'),0) AS v_amounts;
Комментарии:
1. Пропустите подзапросы, используйте вместо них выражения прецедентов.
Ответ №1:
Никогда не используйте запятые в FROM
предложении. Всегда используйте правильный, явный, стандартный JOIN
синтаксис. JOIN
является частью SQL уже более двух десятилетий. Пришло время правильно выучить язык.
Я подозреваю, что условная агрегация поможет решить вашу проблему:
SELECT SUM(CASE WHEN p.so_category = 'DT' THEN c.due_to_office ELSE 0 END) AS dt_amount,
SUM(CASE WHEN p.so_category = 'RT' THEN c.due_to_office ELSE 0 END) AS rt_amount,
SUM(CASE WHEN p.so_category = 'IT' THEN c.due_to_office ELSE 0 END) AS it_amount,
SUM(CASE WHEN p.so_category = 'LR' THEN c.due_to_office ELSE 0 END) AS ir_amount,
SUM(CASE WHEN p.so_category = 'IR' THEN c.due_to_office ELSE 0 END) AS ir_amount,
SUM(CASE WHEN p.so_category = 'V' THEN c.due_to_office ELSE 0 END) AS v_amount
FROM sales_entry_summary ses JOIN
sales_entry se
ON ses.ses_id = se.ses_id JOIN
sales_products sp
ON ses.product_id = p.product_id
WHERE ses.sales_date = '2019-01-01' AND
ses.status = 'AUDITED';
Для дополнительной производительности вам нужен индекс sales_entry_summary(sales_date, status)
.
Ответ №2:
SELECT b.so_category, SUM(c.due_to_office) AS dt_amount
FROM sales_entry_summary a, sales_products b, sales_entry c
WHERE a.ses_id = c.ses_id AND a.sales_date = '2019-01-01' AND a.`status` = 'AUDITED' AND a.product_id = b.product_id
GROUP BY b.so_category
HAVING b.so_category in ('DT', 'RT', 'IT', 'LR', 'IR', 'V')
выдаст вам строки с so_category и суммой. Если вы хотите иметь одну строку, затем оберните select вокруг select выше и используйте case when .
Редактировать
Конечно, вы можете объединить таблицы, что было бы улучшением.
Комментарии:
1. как я могу отобразить so_category, который имеет нулевое значение или 0;
2. @ArnieMallari В том, что вам нужно разрешить null для so_category, но поскольку null не равно null (это странно, я знаю, но так оно и есть), вам нужно разрешить это отдельно, например, ИМЕТЬ b.so_category в (‘DT’, ‘RT’, ‘IT’, ‘LR’, ‘IR’, ‘V’) или (b.so_category равно null). При выборе, если вы хотите использовать некоторые значения по умолчанию, вы можете использовать функцию IFNULL для этой цели, у вас есть примеры для этого в коде, который вы указали в вопросе.
3. @ArnieMallari если у вас возникла ситуация, когда в b есть некоторые категории, которые не связаны ни с какими записями в a или c, то приведенный выше запрос отфильтровывает их. В этом случае вам нужно будет преобразовать приведенный выше запрос из Decartes mutiplications в выделение из b и слева, присоединив к нему a и c. Это приведет к получению даже тех записей в b, которые не имеют связанных записей в a или c, и для улучшения способа сбора значений вы можете использовать функцию IFNULL .