Сделайте этот запрос более простым

#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 .