#php #mysql #codeigniter
Вопрос:
У меня есть запрос, который я использую в своей модели CodeIgniter для получения количества списков товаров между определенными днями. Что делает этот запрос, так это берет status_from из журналов, где дата находится во время и после выбранного диапазона дат, и берет added_date из списков, где дата выпадает перед диапазоном дат, выбранным пользователем, и вычисляет его. Как только он извлек эти записи, он проверяет таблицу на предмет того, какую переменную содержит этот статус, и выполняет a sum(case when else 0)
, чтобы получить общее количество.
function get_report(){
$sql = with Y as (
with recursive D (n, day) as (
select 1 as n, '2021-09-25' my_date
union
select n 1, day interval 1 day from D
where day interval 1 day < '2021-10-15'
) select * from D
), X as (
select Y.day,
l.*,
(select status_from from logs
where logs.refno = l.refno
and logs.logtime >= Y.day
order by logs.logtime
limit 1) logstat
from listings l, Y
where l.added_date <= Y.day
), Z as (
select X.day, ifnull(X.logstat,X.status) stat_day, count(*) cnt
from X
group by X.day, stat_day
)
select Z.day,
sum(case when Z.stat_day = 'D' then Z.cnt else 0 end ) Draft,
sum(case when Z.stat_day = 'A' then Z.cnt else 0 end ) Action,
sum(case when Z.stat_day = 'Y' then Z.cnt else 0 end ) Publish,
sum(case when Z.stat_day = 'S' then Z.cnt else 0 end ) Sold,
sum(case when Z.stat_day = 'L' then Z.cnt else 0 end ) Let
from Z
group by Z.day
order by Z.day;
$query = $this->db->query($sql);
return $query;
}
Dbfiddle: https://dbfiddle.uk/?rdbms=mysql_8.0amp;fiddle=6789f0517b194b09d235860dc794ea14
Теперь здесь, как вы можете видеть, я обрабатываю свои вычисления в самой инструкции sql, но я хочу выполнить эти вычисления на своей стороне php, в основном повторяя каждый раз, когда он встречается Z.stat_day = 'D'
, затем добавляя 1 в столбец черновика и то же самое для других статусов.
Текущий Класс Представления:
<?php
foreach($data_total as $row ){
$draft = $row->draft ? $row->draft : 0;
$publish = $row->publish ? $row->publish : 0;
$action = $row->action ? $row->action : 0;
$sold = $row->sold ? $row->sold : 0;
$let = $row->let ? $row->let : 0;
?>
<tr>
<td><?= $row->day?></td>
<td><?= $draft ?></td>
<td><?= $publish ?></td>
<td><?= $action ?></td>
<td><?= $sold ?></td>
<td><?= $let ?></td>
</tr>
<?php } ?>
В принципе, я хочу преломить свой PHP-код, чтобы сделать то же самое, что делает оператор Mysql, но сохранить простой запрос и всю обработку на стороне PHP по соображениям производительности.
Ответ №1:
Начните с предварительного создания постоянной таблицы со списком «дней», уходящих далеко в будущее. Проиндексируйте его на день. Затем используйте эту таблицу вместо Y
.
Вместо
from listings l, Y
where l.added_date <= Y.day
вы, наверное, хотите
FROM Y
LEFT JOIN listings AS l ON l.added date = Y.day
WHERE Y.day BETWEEN ... AND ...
Таким образом, дни, которые отсутствуют, listings
будут показаны в выходных данных. Однако значения будут отображаться как NULL
, поэтому вы можете захотеть что-то вроде COALESCE(col, 0)
вместо NULL
.
Вы пытаетесь получить «совокупные» промежуточные итоги? (cf l.added_date <= Y.day
) Если это так, вам нужно взглянуть на «оконные» функции 8.0; они, вероятно, будут намного быстрее. (Вы используете 8.0?)