【问题标题】:Accessing a temporary table multiple times in MySql在 MySql 中多次访问临时表
【发布时间】:2010-11-02 14:55:33
【问题描述】:

我尝试使用临时表作为 SELECT 语句的中间结果持有者。问题是我无法在其他查询语句中多次访问临时表,我希望这是可能的,即使临时表无用。

MySql 中是否有替代临时表的方法,可以让我提取我的 SQL 语句。

我不能使用存储过程(不能从公司使用的网络框架版本访问它们),我不想使用光标。

编辑:

我的代码看起来有点像这样:

创建临时表:

CREATE TEMPORARY TABLE dates_with_entries (
  seq  INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  datum VARCHAR(32)
);

INSERT INTO dates_with_entries (datum) SELECT datum AS Datum from project_times
    WHERE user_id = 20 GROUP BY datum ORDER BY datum desc LIMIT 13;

然后我使用临时表的代码看起来有点像这样(我把它简化为我遇到的问题......)

SELECT 
...
FROM (SELECT entrie_date AS datum FROM dates_with_entries ) AS sub_result
INNER JOIN project_times
    ON sub_result.datum = project_times.datum AND project_times.user_id = 20
LEFT JOIN works AS w ON project_times.work_id = w.id
LEFT JOIN sub_projects AS sp ON sp.id = w.sub_project_id
LEFT JOIN projects AS p ON p.id = sp.project_id
GROUP BY datum
UNION(
    SELECT
      ..
  FROM (SELECT entrie_date AS datum FROM dates_with_entries ) AS sub_result
  INNER JOIN project_times AS pt ON pt.datum = sub_result.datum
  INNER JOIN works AS w on w.id = pt.work_id
  INNER JOIN sub_projects AS sp on w.sub_project_id = sp.id
  INNER JOIN projects AS p ON sp.project_id = p.id
  WHERE pt.user_id = 20
);

后面的数字会被ruby代替,这只是为了测试SQL语句。

【问题讨论】:

  • 展示一些关于如何创建和使用临时表的示例 SQL。

标签: mysql temp-tables


【解决方案1】:

解决此问题的一种方法是简单地创建一个“真实”表,而不是临时表。

临时表的优势:

  1. 命名空间。您可以创建多个 同名临时表 在单独的会话中。
  2. 自动清理。完成后不需要显式删除表格 它。当您结束会话时它会消失

如果 #1 对您至关重要,那么您可能需要坚持使用临时表。否则,如果一次只运行该程序的一个实例,或者如果您动态创建表名以使其唯一,我建议您为该表选择一个适当唯一的名称并将其创建为“真实”表,然后完成后放下它。

【讨论】:

  • 好的,所以实现我的目标的唯一方法是通过定义一个真实的表来使用 hack。如果我不想要任何代码重复,我想我将不得不采用这个想法。
  • 如果您已经知道查询将是什么样子,请创建与第一个临时表具有相同架构的第二个临时表,然后执行INSERT INTO dates_with_entries2 SELECT * FROM dates_with_entires,最后,在您的最终查询中,在一个地方引用第一个临时表,在另一个地方引用第二个临时表。
【解决方案2】:

已知错误(功能)-阅读http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html

这是我解决问题的方法...

drop table if exists employees;
create table employees
(
emp_id smallint unsigned not null auto_increment primary key,
name varchar(255) not null,
boss_id smallint unsigned null,
key (boss_id)
)
engine = innodb;

insert into employees (name, boss_id) values
('f00',null), 
  ('ali later',1), 
  ('megan fox',1), 
      ('jessica alba',3), 
      ('eva longoria',3), 
         ('keira knightley',5), 
            ('liv tyler',6), 
            ('sophie marceau',6);


drop procedure if exists employees_hier;

delimiter #

create procedure employees_hier
(
in p_emp_id smallint unsigned
)
begin

declare v_done tinyint unsigned default(0);
declare v_dpth smallint unsigned default(0);

create temporary table hier(
 boss_id smallint unsigned, 
 emp_id smallint unsigned, 
 depth smallint unsigned
)engine = memory;

insert into hier select boss_id, emp_id, v_dpth from employees where emp_id = p_emp_id;

/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */

create temporary table emps engine=memory select * from hier;

while not v_done do

    if exists( select 1 from employees e inner join hier on e.boss_id = hier.emp_id and hier.depth = v_dpth) then

        insert into hier select e.boss_id, e.emp_id, v_dpth + 1 
            from employees e inner join emps on e.boss_id = emps.emp_id and emps.depth = v_dpth;

        set v_dpth = v_dpth + 1;            

        truncate table emps;
        insert into emps select * from hier where depth = v_dpth;

    else
        set v_done = 1;
    end if;

end while;

select 
 e.emp_id,
 e.name as emp_name,
 p.emp_id as boss_emp_id,
 p.name as boss_name,
 hier.depth
from 
 hier
inner join employees e on hier.emp_id = e.emp_id
left outer join employees p on hier.boss_id = p.emp_id;

drop temporary table if exists hier;
drop temporary table if exists emps;

end #

delimiter ;

-- call this sproc from your php

call employees_hier(1);

【讨论】:

    【解决方案3】:

    对于这个问题,临时表只能被读取,我创建了第二个临时表作为第一个临时表的副本,然后在查询中使用它:

    CREATE TEMPORARY TABLE t2 as (SELECT * FROM dates_with_entries);
    

    然后

    SELECT 
    ...
    FROM (SELECT entrie_date AS datum FROM dates_with_entries ) AS sub_result
    INNER JOIN project_times
        ON sub_result.datum = project_times.datum AND project_times.user_id = 20
    LEFT JOIN works AS w ON project_times.work_id = w.id
    LEFT JOIN sub_projects AS sp ON sp.id = w.sub_project_id
    LEFT JOIN projects AS p ON p.id = sp.project_id
    GROUP BY datum
    UNION(
        SELECT
          ..
      FROM (SELECT entrie_date AS datum FROM t2) AS sub_result
      INNER JOIN project_times AS pt ON pt.datum = sub_result.datum
      INNER JOIN works AS w on w.id = pt.work_id
      INNER JOIN sub_projects AS sp on w.sub_project_id = sp.id
      INNER JOIN projects AS p ON sp.project_id = p.id
      WHERE pt.user_id = 20
    ); 
    

    【讨论】:

      【解决方案4】:

      我为这个问题尝试了“WITH”,但显然我的服务器上的 MySQL 还不支持它。我遇到了这个似乎可行的解决方案。它使用“CREATE VIEW”在 MySQL 中复制“WITH”

      http://guilhembichot.blogspot.com/2013/11/with-recursive-and-mysql.html

      【讨论】:

      • 使用链接回答时,请将代码的相关部分复制到您的回答中(如果链接上的许可允许) - 即使链接失效,您的回答仍然有用。注意:正如您所提到的,该链接显示使用“CREATE VIEW”,这是一个非临时定义,尽管它具有每个查询填充当前数据的好处。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-09
      • 1970-01-01
      相关资源
      最近更新 更多