Изменить запрос sql

У меня есть следующий запрос, чтобы получить среднее значение данных за 52 недели года следующим образом:

$dates = array(); $firstDate = date("Ymd", strtotime('first day of January 2016')); $lastDate = date("Ymd", strtotime('last day of December 2016')); for($i=strtotime($firstDate); $i<=strtotime($lastDate); $i+=86400 *7){ array_push($dates, date("Ymd", strtotime('monday this week', $i))); } for($i = 0; $i < count($dates); $i++){ $sql = "SELECT pr_products.product, CONCAT(YEAR('".$dates[$i]."'),'-',LPAD(WEEK('".$dates[$i]."'),2,'0')) AS Week, SUM(IF(sw_sowing.type = 'SW', sw_sowing.quantity,0)) AS PlantSowing, SUM(IF(ROUND(DATEDIFF(TIMESTAMPADD(DAY,(6 WEEKDAY('".$dates[$i]."')),'".$dates[$i]."'), sw_sowing.date)/7) >= pr_products.week_production AND sw_sowing.type = 'SW',sw_sowing.quantity,0)) AS production FROM ( SELECT max(sw_sowing.id) AS id FROM sw_sowing WHERE sw_sowing.status != 0 AND sw_sowing.id_tenant = :id_tenant AND sw_sowing.status = 100 AND sw_sowing.date <= TIMESTAMPADD(DAY,(6-WEEKDAY('".$dates[$i]."')),'".$dates[$i]."') GROUP BY sw_sowing.id_production_unit_detail ) AS sw INNER JOIN sw_sowing ON sw_sowing.id = sw.id INNER JOIN pr_products ON pr_products.id = sw_sowing.id_product INNER JOIN pr_varieties ON sw_sowing.id_variety = pr_varieties.id INNER JOIN pr_lands ON pr_lands.id = sw_sowing.id_land WHERE pr_varieties.code != 1 AND sw_sowing.id_product = 1 AND sw_sowing.status = 100 GROUP BY pr_products.product HAVING plantSowing > 0 ORDER BY pr_products.product"; } 

Сначала я объявляю две переменные: $firstdate – дата начала и $lastDate которая является датой окончания.

Затем я заставляю пройти две даты и держать в массиве даты понедельника каждую неделю.

Затем я просматриваю этот новый массив, чтобы получать нужные мне данные из недели в неделю.

Примечание. В запросе переменные $dates[$i] являются датами понедельника каждой недели.

В любом случае, запрос работает отлично, потому что он приносит мне данные, которые мне нужны с 52 недель в году. Проблема в том, что требуется некоторое время.

Я уже индексировал таблицы в mysql, я немного улучшаю, но недостаточно, запрос на самом деле не тяжелый, он занимает в среднем 0.60 секунды за цикл.

Я хотел бы знать, есть ли возможность удалить то, что я делаю, и в запросе добавить, что я не знаю, WHERE которое сравнивает две даты и приносит мне данные, или если есть какой-либо способ улучшить запрос.

Я уже обновил запрос с предложениями ответа:

 $data = array(); $start = new DateTime('first monday of January 2016'); $end = new DateTime('last day of December 2016'); $datePeriod = new DatePeriod($start , new DateInterval('P7D') , $end); $sql = "SELECT product AS product, Week AS label, ROUND(SUM(harvest)/SUM(production),2) AS value FROM ( ( SELECT pr_products.product, CONCAT(YEAR(:dates),'-', LPAD(WEEK(:dates1),2,'0')) AS Week, SUM(IF(sw_sowing.type = 'SW', sw_sowing.quantity,0)) AS PlantSowing, SUM(IF(ROUND(DATEDIFF(TIMESTAMPADD(DAY,(6-WEEKDAY(:dates2)),:dates3), sw_sowing.date)/7) >= pr_products.week_production AND sw_sowing.type = 'SW',sw_sowing.quantity,0)) AS production, 0 AS Harvest FROM ( SELECT max(sw_sowing.id) AS id FROM sw_sowing WHERE sw_sowing.status != 0 AND sw_sowing.date <= TIMESTAMPADD(DAY,(6-WEEKDAY(:dates4)),:dates5) GROUP BY sw_sowing.id_production_unit_detail ) AS sw INNER JOIN sw_sowing ON sw_sowing.id = sw.id INNER JOIN pr_products ON pr_products.id = sw_sowing.id_product INNER JOIN pr_varieties ON sw_sowing.id_variety = pr_varieties.id WHERE pr_varieties.code != 1 AND sw_sowing.id_product = 1 AND sw_sowing.status = 100 AND sw_sowing.id_tenant = :id_tenant GROUP BY pr_products.product HAVING plantSowing > 0 ORDER BY pr_products.product ) UNION ALL ( SELECT pr_products.product, CONCAT(YEAR(:dates6),'-', LPAD(WEEK(:dates7),2,'0')) AS Week, 0 AS plantSowing, 0 AS Production, SUM(pf_harvest.quantity) AS Harvest FROM pf_harvest INNER JOIN pr_products ON pr_products.id = pf_harvest.id_product INNER JOIN pr_varieties ON pr_varieties.id = pf_harvest.id_variety INNER JOIN pf_performance ON pf_performance.id = pf_harvest.id_performance WHERE pf_harvest.date BETWEEN TIMESTAMPADD(DAY,(0-WEEKDAY(:dates8)),:dates9) AND TIMESTAMPADD(DAY,(6-WEEKDAY(:dates10)),:dates11) AND pr_varieties.code != 1 AND pf_harvest.id_product = 1 AND pf_performance.status = 100 AND pf_harvest.id_tenant = :id_tenant1 GROUP BY pr_products.product ORDER BY pr_products.product ) ) AS sc GROUP BY product, label ORDER BY label"; $statement = $this->db->prepare($sql); $id_tenant = $this->getIdTenant(); foreach($datePeriod AS $dates){ $values = [ ':dates' => $dates->format('Ym-d'), ':dates1' => $dates->format('Ym-d'), ':dates2' => $dates->format('Ym-d'), ':dates3' => $dates->format('Ym-d'), ':dates4' => $dates->format('Ym-d'), ':dates5' => $dates->format('Ym-d'), ':dates6' => $dates->format('Ym-d'), ':dates7' => $dates->format('Ym-d'), ':dates8' => $dates->format('Ym-d'), ':dates9' => $dates->format('Ym-d'), ':dates10' => $dates->format('Ym-d'), ':dates11' => $dates->format('Ym-d'), ':id_tenant' => $id_tenant, ':id_tenant1' => $id_tenant ]; $result = $this->db->executePrepared($statement , $values); $data[] = $result->fetchAll(); } $this -> jsonReturnSuccess($data);