sql: multiselect en un seul... - Programmation
Marsh Posté le 04-04-2001 à 11:18:30
lut 
C'est bizarre ta clé étrangère sur la même table (jamais vu un truc pareil !) 
Et la récursivité n'est pas gérable sous SQL. 
Transact SQL ou PL/SQL avec des boucles ca doit le faire
Marsh Posté le 04-04-2001 à 11:22:20
Je ne comprends pas. b référence la PK de toto, soit a????? 
 
Tu peux nous mettre un pseudo-script de création de table?
Marsh Posté le 04-04-2001 à 11:25:41
La solution doit être avec CONNECT BY toto un truc du genre.
Marsh Posté le 04-04-2001 à 11:32:31
voila un script sous sql server... enfin, a ma sauce  
 
 
create table toto  
( 
  a numeric(10) IDENTITY PRIMARY KEY, 
  b numeric(10), 
  c varchar(20), 
  constraint FK_toto_toto foreign key (b) references toto(a) 
)
Marsh Posté le 04-04-2001 à 11:37:11
bah.. c pour mon histoire de jointure. 
Tu sais les jointure du genre: 
 
 A.1=B.1 AND B.2=C.2 AND C.3=D.2 AND etc... 
 
Enfin, bref... Un chtit exemple de script plz... jsuis un peu perdu la 
Marsh Posté le 04-04-2001 à 11:39:25
A priori, je te proposerais ça : 
 
select   t2.* 
from 
         toto      t1, 
         toto      t2 
where 
         t1.a    = t2.b 
and 
         t1.a      = 1
[edit]--Message édité par Fred999--[/edit]
Marsh Posté le 04-04-2001 à 11:50:37
Fred999> J'y avais pensé, mais de cette manière, on n'obtient que les lignes liées d'un nivo. seulement. 
 
Moi il me fodrait tous les nivos: c.a.d la ligne ki est donnee par b ainsi ke celle ki est eventuellement donnee ar cette derniere, pi etc.... 
En fait, je pense ke le pb. est un truc recursif. Mais comment le resoudre...  
 
 
thegti> tu pourrais pas me faire le script avec les cuseur...  paske moi jy connais kedal (enfin, pas grd chose) en curseur.
 paske moi jy connais kedal (enfin, pas grd chose) en curseur. 
Marsh Posté le 04-04-2001 à 11:57:13
OK j'ai (enfin) compris. Et, effectivement, c'est un truc récursif.
Marsh Posté le 04-04-2001 à 12:02:36
Je te donne une méthode, je pense avoir trouvé. 
 
10 minutes le temps que je ponde le script.
Marsh Posté le 04-04-2001 à 12:06:15
Tu peux faire un truc du genre : 
 
create table #tmp_toto ( 
           a numeric(10), 
           b numeric(10), 
           c varchar(20), 
           rang int 
) 
 
declare @inCompteur int 
declare @inRang int 
 
select @inCompteur = 1, 
       @inRang = 0 
 
/* Insertion initiale */ 
insert #tmp_toto 
select 
       t2.a, 
       t2.b, 
       t2.c, 
       @inRang 
from 
       toto   t1, 
       toto  t2 
where 
       t1.a = 1 
and 
       t1.a = t2.b 
 
/* Insertions récursives */ 
while (@inCompteur != 0) 
begin 
 
   insert #tmp_toto (a, b, c, rang) 
   select 
          t1.a, 
          t1.b, 
          t1.c, 
          @inRang + 1 
   from 
          toto  t1, 
          #tmp_toto t2 
   where 
          t1.b = t2.a 
   and 
          t2.rang = @inRang 
 
select @inCompteur = @@rowcount 
 
select @inRang = @inRang + 1 
 
end 
 
select * from #tmp_toto 
 
 
Bon, l'insertion initiale te donne les lignes qui sont directement reliées de premier niveau. 
 
Et, ensuite, on insère les lignes reliées aux lignes du niveau donné, de manière récursive ; quand on n'en trouve plus, on sort de la boucle. 
 
Le souci, c'est que si tu t'emmèles les pinceaux au momoent de l'insertion, tu risques de tourner en rond : prévoir, donc, une porte de sortie (par exemple, au niveau 50, il doit commencer à y avoir un gros souci...). 
 
Bon, j'utilise une table temporaire, ça me paraît adapté à la situation, et c'est bien dans l'esprit de SQL Server (qui n'aime pas trop les curseurs...) 
 
ATTENTION!!! J'avais fait une couille dans l'initialisation des variables et la condition de sortie de la boucle. C'est corrigé.
[edit]--Message édité par Fred999--[/edit]
Marsh Posté le 04-04-2001 à 12:18:25
je viens de revoir ma problematique, (kel mot  )
 ) 
En fait, on peut resumer ca en faisant une analogie avec un ensemble de listes chainees. 
Donc en fait, ma table toto serait en qq sorte un ensemble de listes chainees. 
Et moi je veux une liste entiere connaissant la tete. En clair je veux une liste particuliere dans l'ensemble de liste  .
. 
 
Je crois ke c un peu tordu kom truc mais bon... 
Marsh Posté le 04-04-2001 à 12:24:04
Merci pour ton script Fred999... meme si j'y comprend pas grd chose. 
Mais bon, si jai bien compris il fodrait ke je mette ca dans une procedure stockee si je veux l'utiliser, non ? 
 
En fait, jai donne un script pour sqlserver paske plus rapide a ecrire... Mais en fait il me fodrait une solution pour oracle 8. 
Marsh Posté le 04-04-2001 à 14:04:30
Je pense qu'en PL/SQL sous Oracle 8 ça devrait pouvoir se faire (c'est une procédure stockée là aussi)
[edit]--Message édité par Irulan--[/edit]
Marsh Posté le 04-04-2001 à 14:11:34
Effectivement, il te faut une procédure stockée. 
 
Bon, la traduction en PL-SQL ne doit pas poser de problème, simplement, PL-SQL préfère les curseurs aux tables tempo. Mais bon, dans ton cas, ça devrait tout de même le faire... 
 
Juste un truc : 
 
Les variables en Transact-SQL sont toujours préfixées par : 
- @ pour les variables utilisateur (@inCompteur et @inRang ici) 
- @@ pour les variables système : @@rowcount représente le nombre de lignes ramenées par la dernière requête exécutée (ici, l'insert : quand @@rowcount = 0, c'est qu'on n'a effectué aucune insertion). 
 
Et les tables temporaires sont toujours préfixées par #. 
 
Voilà, tu devrais pouvoir te débrouiller avec ça non? 
 
Si tu n'as pas compris l'algo, demande...
[edit]--Message édité par Fred999--[/edit]
Marsh Posté le 04-04-2001 à 15:16:14
Fred999> j'ai retouché un peu ton script... je pense ke kom ca il fait un peu mie ce e je veux... mais si tu (ou kkun) pouvais corriger ce serait cool... paske moi jsuis assez mediocre en sql  
 
 
create table #tmp_toto (  
           a numeric(10),  
           b numeric(10),  
           c varchar(20),  
           rang int  
)  
 
declare @inCompteur int  
declare @inRang int  
 
select @inCompteur = 1,  
       @inRang = 0  
 
/* Insertion initiale */  
insert #tmp_toto  
select  
       a,  
       b,  
       c,  
       @inRang  
from  
       toto 
where  
       a = 1  
 
/* Insertions récursives */  
while (@inRang < @inCompteur)  
begin  
 
   select @inRang = @inRang + 1  
 
   if ( #tmp_toto.b is not null ) then 
 
   insert #tmp_toto (a, b, c, rang)  
   select  
          t1.a,  
          t1.b,  
          t1.c,  
          @inRang 
   from  
          toto  t1,  
          #tmp_toto t2  
   where  
          t1.a = t2.b  
   and  
          t2.rang = @inRang  
 
   select count(*) into @inCompteur 
 
   end if 
 
from #tmp_toto 
 
end  
 
select * from #tmp_toto  
 
 
Mais jsais toujours pas komment le transformer en pl/sql... 
Mes souvenirs dans ce domaine me font defaut  
 
Alors, si une ame charitable pouvait...  
 
 
p.s: Comment kon fait pour mettre ce truc en proc. stock. et l'utiliser apres ?
[edit]--Message édité par wouatouwouatou--[/edit]
Marsh Posté le 04-04-2001 à 15:29:47
[citation][nom]wouatouwouatou a écrit[/nom] 
create table #tmp_toto (  
           a numeric(10),  
           b numeric(10),  
           c varchar(20),  
           rang int  
)  
 
declare @inCompteur int  
declare @inRang int  
 
select @inCompteur = 1,  
       @inRang = 0  
 
/* Insertion initiale */  
insert #tmp_toto  
select  
       a,  
       b,  
       c,  
       @inRang  
from  
       toto 
where  
       a = 1  
 
Si tu veux la ligne d'origine, alors OK. Tu l'avais précisé? 
 
/* Insertions récursives */  
while (@inRang < @inCompteur)  
begin  
 
   select @inRang = @inRang + 1  
 
 Tu ne peux pas incrémenter le rang dès le début de la boucle... Au premier passage, tu n'auras que du rang 0 dans ta table tempo, et la requête va aller chercher les lignes de rang 1. Si j'avais fait un petit mic-mac sur l'incrémentation, ce n'était pas pour rien... 
Ou alors, le 2e critère du WHERE devient t2.rang = @inRang - 1 
 
De plus, donner comme critère de sortie de boucle @inRang < @inCompteur me paraît plus que douteux. Tu peux justifier? 
 
   if ( #tmp_toto.b is not null ) then 
 
   insert #tmp_toto (a, b, c, rang)  
   select  
          t1.a,  
          t1.b,  
          t1.c,  
          @inRang 
   from  
          toto  t1,  
          #tmp_toto t2  
   where  
          t1.a = t2.b  
   and  
          t2.rang = @inRang  
 
   select count(*) into @inCompteur 
   from #tmp_toto 
 
 La syntaxe PL-SQL n'est-clle pas select @inCompteur := count (*) ... ?  
 
   end if 
 
end  
 
select * from #tmp_toto  
 
 
Bon, après, tu mets ça en proc stock, tu compiles, et tu exécutes avec la commande @@nom_proc (si mes souvenirs sont bons)
Marsh Posté le 04-04-2001 à 15:47:57
bon... ok pour inRang.. 
la ligne d'origine , i me la fo aussi  donc ok aussi.
 donc ok aussi. 
 
Pour la condition de sortie, tas raison... de toute maniere, il ne devrai y avoir kune seule ligne trouvee a la fois, du fait ke c la cle primaire. 
 
Et le if... dans la boucle devrai normalement faire une sorte de  break; 
 
Quant a la syntaxe... moi, jsais pas... car mon pl/sql est aussi bon ke mon transac voire pire  
 
Donc apres tout ca je refait le script ki donne ( syntaxiquement fo  ) :
 ) : 
 
 
create table #tmp_toto (   
           a numeric(10),   
           b numeric(10),   
           c varchar(20),   
           rang int   
)   
 
declare @inCompteur int   
declare @inRang int   
 
select @inCompteur = 1,   
       @inRang = 0   
 
/* Insertion initiale */   
insert #tmp_toto   
select   
       a,   
       b,   
       c,   
       @inRang   
from   
       toto  
where   
       a = 1   
 
/* Insertions récursives */   
while ( @inCompteur != 0 ) 
begin   
 
   if ( #tmp_toto.b is null ) then  
     exit; 
   end if 
 
   insert #tmp_toto (a, b, c, rang)   
   select   
          t1.a,   
          t1.b,   
          t1.c,   
          @inRang + 1 
   from   
          toto  t1,   
          #tmp_toto t2   
   where   
          t1.a = t2.b   
   and   
          t2.rang = @inRang   
 
   select @inCompteur = @@rowcount  
   select @inRang = @inRang + 1   
 
end   
 
select * from #tmp_toto   
 
Marsh Posté le 04-04-2001 à 15:54:09
create table #tmp_toto (   
           a numeric(10),   
           b numeric(10),   
           c varchar(20),   
           rang int   
)   
 
declare @inCompteur int   
declare @inRang int   
 
select @inCompteur = 1,   
       @inRang = 0   
 
/* Insertion initiale */   
insert #tmp_toto   
select   
       a,   
       b,   
       c,   
       @inRang   
from   
       toto  
where   
       a = 1   
 
/* Insertions récursives */   
while ( @inCompteur != 0 ) 
begin   
 
   if ( #tmp_toto.b is null ) then  
     exit; 
   end if 
 
J'avais pas vu cette ligne  
 
if (#tmp_toto.b is null) Alors là... c'est du barbarisme!!! 
Si tu veux vérifier un champ de la table #tmp_toto, il faut que tu fasses un if exists(). Mais tu veux faire quoi exactement? 
 
ET LES AUTRES, VOUS Y AVEZ JETE UN OEIL AU SCRIPT? 
 
Sinon, pour le reste, ça m'a l'air OK. 
 
   insert #tmp_toto (a, b, c, rang)   
   select   
          t1.a,   
          t1.b,   
          t1.c,   
          @inRang + 1 
   from   
          toto  t1,   
          #tmp_toto t2   
   where   
          t1.a = t2.b   
   and   
          t2.rang = @inRang   
 
   select @inCompteur = @@rowcount  
   select @inRang = @inRang + 1   
 
end   
 
select * from #tmp_toto   
 
 
Et à dans 10 minutes  
 
Marsh Posté le 04-04-2001 à 16:09:41
bah.. en fait, c la condition de sortie de la boucle  
 
 
while ( #tmp_toto.b is not null ) do ... 
 
Car si la ligne trouvee ne pointe plus sur une ligne (donc b vaut null) alors i fo s'arreter la.
Marsh Posté le 04-04-2001 à 16:14:29
OK... Deux manières différentes d'aborder le problème. 
 
1. while (select count (*) from #tmp_toto where b is null and rang = @inRang - 1) = 0 
C'est ce que tu veux faire : vérifier que toutes les lignes du rang max de la table #tmp_toto ne pointent sur rien : pas de suivantes. 
 
2. While @inCompteur != 0 
Tant qu'on trouve des lignes qui suivent...
Marsh Posté le 04-04-2001 à 16:19:50
ouais... en clair, elle sert a rien cette condition donc...  
 
merci... au fait comment tu fait pour le mettre en ps ? 
c koi la syntaxe ? 
Pi fo pas dropper la table tmp ?
Marsh Posté le 04-04-2001 à 16:29:10
Si, ta condition est bonne fonctionnellement parlant, mais la syntaxe laissait fortement à désirer. 
 
"mettre en ps"??????  
 
 
Et si, il faut virer la table tempo. J'avais oublié.
Marsh Posté le 04-04-2001 à 16:33:26
ps pour proc. stock.  
 
Désolé, ce sont mes abreviations...
[edit]--Message édité par wouatouwouatou--[/edit]
Marsh Posté le 04-04-2001 à 16:40:48
Bin pour le mettre en proc stock... Tu n'as pas d'exemples de procs stockées à ton bureau? 
Marsh Posté le 04-04-2001 à 16:49:01
Super ca marche impec ton script... 
Un grand MERCI !!   :jap::jap::jap::jap::jap::jap::jap::jap::jap::jap::jap::jap:
:jap::jap::jap::jap::jap::jap::jap::jap::jap::jap::jap::jap: 
 
P.S: voila le script final: (en transac.. désolé.. mais bon il marche  )
 ) 
 
 
drop table toto 
GO 
 
create table toto ( 
a numeric(10) identity primary key, 
b numeric(10), 
c varchar(20), 
constraint fk_toto_toto foreign key (b) references toto(a) 
) 
GO 
 
drop procedure sp_test_toto 
go 
 
create procedure sp_test_toto 
  @tete numeric(10) 
as 
begin 
 
create table #tmp_toto (    
           a numeric(10),    
           b numeric(10),    
           c varchar(20),    
           rang int    
); 
 
declare @inCompteur int; 
declare @inRang int; 
 
select @inCompteur = 1, 
       @inRang = 0    
 
/* Insertion initiale */    
insert #tmp_toto    
select    
       a,    
       b,    
       c,    
       @inRang    
from    
       toto   
where    
       a = @tete; 
 
/* Insertions récursives */    
while ( @inCompteur != 0 )  
begin    
 
   insert #tmp_toto (a, b, c, rang)    
   select    
          t1.a,    
          t1.b,    
          t1.c,    
          @inRang + 1  
   from    
          toto  t1,    
          #tmp_toto t2    
   where    
          t1.a = t2.b    
   and    
          t2.rang = @inRang    
 
   select @inCompteur = @@rowcount   
   select @inRang = @inRang + 1    
 
end    
 
select * from #tmp_toto    
 
drop table #tmp_toto 
 
end 
go 
 
Marsh Posté le 04-04-2001 à 16:57:48
Pas de problème. C'était quand même assez tordu ton truc, on ne me l'avait jamais fait faire, j'aurai au moins appris quelque chose aujourd'hui!
Marsh Posté le 04-04-2001 à 10:38:58
J'ai un table toto de trois colonnes a,b,c.

a etant la cle primaire.
b est une cle etrangere referencant toto
c est une colonne de valeurs...
Bon, voila le pb.: Est-il possible d'obtenir toutes les lignes dépendant d'une ligne connue.
Par exemple, je veux toutes les lignes liées a la ligne dont la colonne a vaut 1 (En supposant kil ny aura pas de recursivité sans fin avec les valeurs entre a et b)
Bien sur, la colonne b peut 'pointer' sur une ligne ki elle meme pointe sur une autre, etc...
Merci pour les reponses...