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.
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.
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:
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...