2010-11-02 5 views
4

J'ai essayé d'utiliser une table temporaire en tant que porte-résultats intermédiaire pour une instruction SELECT. Le problème est cependant que je ne peux pas accéder à la table temporaire plusieurs fois dans d'autres requêtes, ce qui, je l'espérais, serait possible, c'est-à-dire rendrait la table temporaire inutile.Accès multiple à une table temporaire dans MySQL

Existe-t-il une alternative aux tables temporaires dans MySQL qui me permet d'extraire mon instruction SQL.

Je ne peux pas utiliser les procédures de stockage (je ne peux pas y accéder à partir de la version web-framework utilisée dans l'entreprise) et je ne souhaite pas utiliser de curseur.

Edit:

Eh bien mon code ressemble un peu à ceci:

création de la table Temp:

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; 

ensuite le code où j'utilise ma table temp ressemble un peu comme ça (je simpled il jusqu'au problème que j'ai ..)

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 
); 

Les chiffres seront affichés plus tard remplacé par ruby, ceci est seulement pour tester l'instruction SQL.

+0

Montrer quelques exemples de SQL pour la façon dont vous créez et utilisez la table temporaire. –

Répondre

3

Une façon de contourner cela est de créer simplement une table « réelle », au lieu d'un table temporaire.

Les avantages que les tables temporaires offrent:

  1. Les espaces de noms. Vous pouvez créer plusieurs tables temporaires portant le même nom dans des sessions distinctes.
  2. Nettoyage automatique. Vous n'avez pas besoin de laisser tomber la table lorsque vous avez terminé avec . Il disparaît lorsque vous terminez votre session

Si le numéro 1 est crucial pour vous, vous devez probablement vous en tenir aux tables temporaires. Sinon, si une seule instance de ce programme s'exécute à la fois, ou si vous créez dynamiquement le nom de la table pour la rendre unique, je vous recommande de choisir un nom unique approprié pour cette table et de le créer comme table "réelle", puis déposez-le lorsque vous avez terminé.

+0

Ok, donc la seule façon d'atteindre mon objectif est d'utiliser un hack en définissant une table réelle .. Eh bien, je suppose que je vais devoir aller avec cette idée si je ne veux pas de duplication de code .. – Mark

2

bug connu (fonction) - lire http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html

Voici comment je travaille autour du problème ...

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); 
0

Pour ce problème, où la table temporaire ne doit être lu, je crée une deuxième table temporaire comme une copie de la première utilisation puis ceci dans la requête:

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

Puis

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 
); 
Questions connexes