从下表的第 1-4 列中,我想创建一个可以返回第 5 列和第 6 列的查询:
我的日期 | cat_1_id | cat_2_id | 我的值 | cat_2_id_1_值 | cat_2_id_2_值 |
---|---|---|---|---|---|
2024年1月1日 | 1 | 1 | 1 | 1 | 空 |
2024年1月1日 | 2 | 1 | 2 | 2 | 空 |
2024年2月1日 | 1 | 2 | 3 | 1 | 3 |
2024年2月1日 | 2 | 2 | 4 | 2 | 4 |
2024年3月1日 | 1 | 1 | 5 | 5 | 3 |
2024年3月1日 | 2 | 1 | 6 | 6 | 4 |
查询逻辑:
这本质上是第 1-4 列中包含的数据的旋转。
第 5 栏:
cat_2_id
= 1,则显示该行的 my_value
cat_2_id
!= 1,则在最后一行显示 my_value
,其中 cat_id_1
与当前行匹配且 cat_2_id
= 1第 6 栏:
这与第 5 列的原理相同,只是
cat_2_id
= 2。所以:
cat_2_id
= 2,则显示该行的 my_value
cat_2_id
!= 2,则在最后一行显示 my_value
,其中 cat_id_1
与当前行匹配且 cat_2_id
= 2目前进度:
我已经找到了一个涉及
CASE
的解决方案:
my_value
条件,则得到
cat_2_id
,或者;my_value
窗口函数以及 LAST_VALUE
(PARTITION BY
) 和 cat_1_id
(ORDER BY
) 和 my_date
的组合获得最后一行的 RANGE BETWEEN
。但是,我无法理解如何在窗口函数中构建附加过滤器以确保最后一行满足
cat_2_id
条件。
我发现this post使用
FILTER
用于postgresql,但我在MySQL文档中找不到这个(而且它说它没有针对非聚合窗口函数实现)。
如果没有窗口函数方法可以做到这一点,那么我会对任何能完成这项工作的东西感到满意!
这是要重新创建的数据:
CREATE TABLE test.pivot_cols (
pivot_by_cols_id INT AUTO_INCREMENT PRIMARY KEY,
my_date DATE NOT NULL,
cat_1_id INT NOT NULL,
cat_2_id INT NOT NULL,
my_value INT NOT NULL
);
INSERT INTO `test`.`pivot_cols` (`my_date`, `cat_1_id`, `cat_2_id`, `my_value`) VALUES ('2000-01-01', '1', '1', '1');
INSERT INTO `test`.`pivot_cols` (`my_date`, `cat_1_id`, `cat_2_id`, `my_value`) VALUES ('2000-01-01', '2', '1', '2');
INSERT INTO `test`.`pivot_cols` (`my_date`, `cat_1_id`, `cat_2_id`, `my_value`) VALUES ('2000-01-02', '1', '2', '3');
INSERT INTO `test`.`pivot_cols` (`my_date`, `cat_1_id`, `cat_2_id`, `my_value`) VALUES ('2000-01-02', '2', '2', '4');
INSERT INTO `test`.`pivot_cols` (`my_date`, `cat_1_id`, `cat_2_id`, `my_value`) VALUES ('2000-01-02', '1', '1', '5');
INSERT INTO `test`.`pivot_cols` (`my_date`, `cat_1_id`, `cat_2_id`, `my_value`) VALUES ('2000-01-02', '2', '1', '6');
您可以从更容易实现和理解的相关子查询开始:
select *, case when cat_2_id = 1 then my_value else (
select my_value
from pivot_cols as x
where cat_1_id = pivot_cols.cat_1_id
and cat_2_id = 1
and my_date < pivot_cols.my_date
order by my_date desc
limit 1
) end as id_1_value, case when cat_2_id = 2 then my_value else (
select my_value
from pivot_cols as x
where cat_1_id = pivot_cols.cat_1_id
and cat_2_id = 2
and my_date < pivot_cols.my_date
order by my_date desc
limit 1
) end as id_2_value
from pivot_cols
order by my_date, cat_1_id
如果您必须使用窗口函数,如果 MySQL 在窗口函数中支持
ignore nulls
,那么事情可能会很简单。遗憾的是事实并非如此,因此您需要使用一些技巧。在以下查询中,我使用 max() over ()
有条件地查找先前日期。使用附加连接来获取值:
with cte as (
select
*,
max(case when cat_2_id = 1 then my_date end) over prev_rows as date_1,
max(case when cat_2_id = 2 then my_date end) over prev_rows as date_2
from pivot_cols
window prev_rows as (
partition by cat_1_id
order by my_date rows between unbounded preceding and 1 preceding
)
)
select
cte.*,
case when cte.cat_2_id = 1 then cte.my_value else j1.my_value end as id_1_value,
case when cte.cat_2_id = 2 then cte.my_value else j2.my_value end as id_2_value
from cte
left join pivot_cols as j1 on cte.cat_1_id = j1.cat_1_id and cte.date_1 = j1.my_date
left join pivot_cols as j2 on cte.cat_1_id = j2.cat_1_id and cte.date_2 = j2.my_date
order by cte.my_date, cte.cat_1_id