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 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何从存储过程返回的游标将数据插入临时表

SQL Server 存储过程创建临时表并插入值

使用mybatis查询mysql数据库 先调用存储过程,然后再inner join 存储过程返回的临时表出错 高手帮忙看下!

MySQL 存储过程,获取使用游标查询的结果集

SQL临时表使用

MySql中的视图 触发器 存储过程,以及事物