2010-10-15 21 views
1

J'utilise la base de données suivante:sqlite2: Rejoindre des valeurs max par colonne d'une autre table (référence de sous-requête)?

CREATE TABLE datas (d_id INTEGER PRIMARY KEY, name_id numeric, countdata numeric); 
INSERT INTO datas VALUES(1,1,20); //(NULL,1,20); 
INSERT INTO datas VALUES(2,1,47); //(NULL,1,47); 
INSERT INTO datas VALUES(3,2,36); //(NULL,2,36); 
INSERT INTO datas VALUES(4,2,58); //(NULL,2,58); 
INSERT INTO datas VALUES(5,2,87); //(NULL,2,87); 
CREATE TABLE names (n_id INTEGER PRIMARY KEY, name text); 
INSERT INTO names VALUES(1,'nameA'); //(NULL,'nameA'); 
INSERT INTO names VALUES(2,'nameB'); //(NULL,'nameB'); 

Ce que je voudrais faire, est de sélectionner toutes les valeurs (lignes) de names - auquel toutes les colonnes de datas sera ajouté, pour la ligne où datas . countdata est maximale pour n_id (et bien sûr, où name_id = n_id).

Je peux y arriver un peu avec la requête suivante:

sqlite> .header ON 

sqlite> SELECT * FROM names AS n1 
    LEFT OUTER JOIN (
     SELECT d_id, name_id, countdata FROM datas AS d1 
     WHERE d1.countdata IN (
      SELECT MAX(countdata) FROM datas 
      WHERE name_id=1 
      ) 
     ) AS p1 ON n_id=name_id; 

n1.n_id|n1.name|p1.d_id|p1.name_id|p1.countdata 
1|nameA|2|1|47 
2|nameB||| 

... mais - évidemment - il ne fonctionne que pour une seule ligne (celle explicitement définie par name_id=1).

Le problème est, la requête SQL échoue chaque fois que j'essaie de référence en quelque sorte le « courant » n_id:

sqlite> SELECT * FROM names AS n1 
    LEFT OUTER JOIN (
     SELECT d_id, name_id, countdata FROM datas AS d1 
     WHERE d1.countdata IN (
      SELECT MAX(countdata) FROM datas 
      WHERE name_id=n1.n_id 
      ) 
     ) AS p1 ON n_id=name_id; 

SQL error: no such column: n1.n_id 

Est-il possible d'obtenir ce que je veux dans sqlite2 ??

Merci d'avance,

Cheers!

Répondre

2

Oh, bien - qui n'était pas banal du tout, mais voici une solution:

sqlite> SELECT * FROM names AS n1 
     LEFT OUTER JOIN ( 
      SELECT d1.* 
      FROM datas AS d1, ( 
       SELECT max(countdata) as countdata,name_id 
       FROM datas 
       GROUP BY name_id 
       ) AS ttemp 
      WHERE d1.name_id = ttemp.name_id AND d1.countdata = ttemp.countdata 
     ) AS p1 ON n1.n_id=p1.name_id; 


n1.n n1.name  p1.d_id  p1.name_id p1.countdata      
---- ------------ ---------- ---------- ----------------------------------- 
1  nameA   2   1   47         
2  nameB   5   2   87         

   

Eh bien, espérons que cela finit par aider quelqu'un, :) Cheers!

     

Remarques: Notez que simplement appeler vis max (countdata) jusqu'à competely d_id:

sqlite> select d_id,name_id,max(countdata) as countdata from datas group by name_id; 

d_id name_id  countdata 
---- ------------ ---------- 
3  2    87   
1  1    47   

pour ainsi obtenir correct correspondant d_id, nous devons faire max() sur datas séparément - et ensuite effectuer une sorte d'intersection avec le plein datas (sauf que l'intersection dans sqlite requiert un nombre égal de colonnes dans les deux ensembles de données, ce qui n'est pas le cas ici - et même si nous l'avons fait comme ci-dessus d_id sera erroné, donc l'intersection ne fonctionnera pas).

Une façon de le faire est en utilisant une sorte de table temporaire, puis utiliser une table plusieurs requêtes SELECT afin de définir les conditions entre plein datas et le sous-ensemble retourné par max(countdata), comme indiqué ci-dessous:

sqlite> CREATE TABLE ttemp AS SELECT max(countdata) as countdata,name_id FROM datas GROUP BY name_id; 
sqlite> SELECT d1.*, ttemp.* FROM datas AS d1, ttemp WHERE d1.name_id = ttemp.name_id AND d1.countdata = ttemp.countdata; 

d1.d d1.name_id d1.countda ttemp.coun ttemp.name_id      
---- ------------ ---------- ---------- ----------------------------------- 
2  1    47   47   1         
5  2    87   87   2         

sqlite> DROP TABLE ttemp; 

ou, on peut réécrire ce qui précède donc un sous-requête SELECT (sous-sélection?) est utilisé, comme ceci:

sqlite> SELECT d1.* FROM datas AS d1, (SELECT max(countdata) as countdata,name_id FROM datas GROUP BY name_id) AS ttemp WHERE d1.name_id = ttemp.name_id AND d1.countdata = ttemp.countdata; 

d1.d d1.name_id d1.countda 
---- ------------ ---------- 
2  1    47   
5  2    87