MYSQL 从存储过程中的临时表中选择 JOIN 不起作用
Posted
技术标签:
【中文标题】MYSQL 从存储过程中的临时表中选择 JOIN 不起作用【英文标题】:MYSQL Select JOIN from temporary tables inside stored procedures not working 【发布时间】:2020-07-27 16:48:33 【问题描述】:我在存储过程中遇到了选择联接的问题。在这个过程中,我创建了两个临时表 K1 和 K2,它们共享一个公共密钥 (t_id)。每一个只有一个值列。我想要做的是连接两个表以检索带有键的表和带有值的两列。
K1 表是这样的
--------------
t_id | KPI1
--------------
1 0.5
2 0.3
3 0.7
--------------
K2 表是这样的
--------------
t_id | KPI2
--------------
1 0.4
2 0.2
3 0.1
--------------
预期结果是这样的:
--------------------
t_id | KPI1 | KPI2
--------------------
1 0.5 0.4
2 0.3 0.2
3 0.7 0.1
--------------------
如果我在常规查询中运行此代码,它将完美运行:
set @t_ini = '2020-07-01 00:00:00';
set @t_end = '2020-07-04 00:00:00';
create temporary table K12 (t_id int,KPI1 float, KPI2 float);
-- get KPI1 in a temporary table
create temporary table K1 as
select distinct intervaldate.ID as t_id,Value as KPI1
from
kpi_db,intervaldate,controllers
where
kpi_db.Interval_ID = intervaldate.ID and
kpi_db.Ctrl_ID = controllers.ID and
kpi_db.Ctrl_ID = CtrlID and
intervaldate.TStart between @t_ini and @t_end and
kpi_db.KPI_ID = 1;
-- get KPI2 in a temporary table
create temporary table K2 as
select distinct distinct intervaldate.ID as t_id,Value as KPI2
from
kpi_db,intervaldate,controllers
where
kpi_db.Interval_ID = intervaldate.ID and
kpi_db.Ctrl_ID = controllers.ID and
kpi_db.Ctrl_ID = CtrlID and
intervaldate.TStart between @t_ini and @t_end and
kpi_db.KPI_ID = 2;
-- merge the two temporary tables
insert into K12(t_id,KPI1,KPI2)
select K1.t_id,KPI1,KPI2
from K1
left join
K2
on (K1.t_id = K2.t_id);
select * from K12;
但是当我把它放在存储过程中时,K12 只返回空值
--------------------
t_id | KPI1 | KPI2
--------------------
1 Null Null
2 Null Null
3 Null Null
--------------------
存储过程如下
CREATE DEFINER=`root`@`localhost` PROCEDURE `UpdateKPIs1_2`(CtrlID int,EventID int,PCT float)
BEGIN
declare done int default 0;
declare t_ini datetime;
declare t_end datetime;
declare t_id int;
declare kpi1 float;
declare kpi2 float;
declare kpi1_nc float;
declare kpi1_new float;
-- cursors declaration
declare cursor_KPIs cursor for select * from K12;
declare continue handler for not found set done = true;
-- temporary table declaration
create temporary table K12 (t_id int,KPI1 float, KPI2 float);
-- select t_ini and t_end
set t_ini = date((select Turn_OFF from turn_on_off where ID = EventID));
set t_end = date((select Turn_ON from turn_on_off where ID = EventID));
-- get KPI1 in a temporary table
create temporary table K1 as
select distinct intervaldate.ID as t_id,Value as KPI1
from
kpi_db,intervaldate,controllers
where
kpi_db.Interval_ID = intervaldate.ID and
kpi_db.Ctrl_ID = controllers.ID and
kpi_db.Ctrl_ID = CtrlID and
intervaldate.TStart between t_ini and t_end and
kpi_db.KPI_ID = 1;
-- get KPI2 in a temporary table
create temporary table K2 as
select distinct distinct intervaldate.ID as t_id,Value as KPI2
from
kpi_db,intervaldate,controllers
where
kpi_db.Interval_ID = intervaldate.ID and
kpi_db.Ctrl_ID = controllers.ID and
kpi_db.Ctrl_ID = CtrlID and
intervaldate.TStart between t_ini and t_end and
kpi_db.KPI_ID = 2;
-- merge the two temporary tables
insert into K12(t_id,KPI1,KPI2)
select K1.t_id,KPI1,KPI2
from K1
left join
K2
on (K1.t_id = K2.t_id);
-- iterate over the K12 temporary table
open cursor_KPIs;
select * from K1;
select * from K2;
select * from K12;
-- HERE COMES SOME PROCESSING USING THE CURSOR. I droped it
-- to make the script more clear.
drop table K1;
drop table K2;
drop table K12;
-- close cursor
close cursor_KPIs;
END
我想知道这个问题是否与分隔符有关,但我不知道如何在这里正确设置分隔符。
我觉得我在这里做的很傻但是我看不到。
谢谢。
【问题讨论】:
【参考方案1】:看来你在这里把事情复杂化了:
两个查询几乎相同 - 只有 where
子句不同 - 您可以使用条件聚合在单个查询中获得相同的结果
我看不出临时表的意义;您可以直接从查询结果插入到目标表中
我认为这样的事情应该很接近你想要的:
insert into k12(t_id, kpi1, kpi2)
select
i.id as t_id,
max(case when k.kpi_id = 1 then k.value end) as kpi1,
max(case when k.kpi_id = 2 then k.value end) as kpi2
from kpi_db k
inner join intervaldate i on k.interval_id = i.id
inner join controllers c on k.ctrl_id = c.id
where i.tstart between @t_ini and @t_end and k.kpi_id in (1, 2)
group by i.id;
【讨论】:
我运行上面的代码,但它返回一个表,所有值都为 1。 我设法让它工作。缺少一个附加的 where 子句。谢谢!【参考方案2】:有趣的话题!
我想知道是否可以在函数/过程中生成一个临时表,该表随后可用于加入表达式,例如
(语法检查关闭!)
FUNCTION CreateTS(DATETIME from, DATETIME to, INT intervalSec)
BEGIN
-- create temp table having records
-- 1,(from, from+intervalSec),
-- 2,(from+intervalSec,from+intervalSec*2),
-- ...,
-- n,(to-intervalSec,to)
return resultset
END
用于类似的查询
SELECT ts.from,ts.to,(some aggregating expression based on t1)
FROM CreateTS(DATE_SUB(NOW(),30,day),NOW(),3600) ts
JOIN T1 t1 on t1.datetime >= ts.from AND t1.datetime < ts.to
理想情况下,SQL 有一个可以用作虚拟时间刻度表
SELECT * FROM timescale ts WHERE ts.from >= ... and ts.to < ... and ts.type = week
类型可以是所有正常的秒、分、小时、日、周、月、年
所以上面的例子可以是
SELECT ts.from,ts.to,(some aggregating expression based on t1)
FROM TS ts
JOIN T1 t1 on t1.datetime >= ts.from AND t1.datetime < ts.to
WHERE ts.from = DATE_SUB(NOW(),30,day) and ts.to = NOW() and ts.type=hour
谢谢
【讨论】:
以上是关于MYSQL 从存储过程中的临时表中选择 JOIN 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
使用mybatis查询mysql数据库 先调用存储过程,然后再inner join 存储过程返回的临时表出错 高手帮忙看下!