IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement SQL Server Discussion :

Procédure stockée et sous requete qui retourne plus d'une valeur


Sujet :

Développement SQL Server

  1. #1
    Membre régulier
    Profil pro
    IT Développeur
    Inscrit en
    Mars 2009
    Messages
    274
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : IT Développeur

    Informations forums :
    Inscription : Mars 2009
    Messages : 274
    Points : 96
    Points
    96
    Par défaut Procédure stockée et sous requete qui retourne plus d'une valeur
    Bonjour,

    j'écris une procédure stockée(non terminée !) qui reçoit différents paramètres dont 1 Table Value Parameters dont le type est définit comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CREATE TYPE [dbo].[CoursType] AS TABLE(
    	[CoursId] [int] NULL,
    	[CoursNom] [varchar](50) NULL
    Ma procédure stocké reçoit le paramètre @CoursSuivis qui est de ce type.

    Le but de cette procédure est de modifier une fiche élève et de parcourir la Table EleveCours et modifier les cours d'un même élève. Elle se présente comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    CREATE PROCEDURE [dbo].[sp_EditerEleve]
    	@idEleve int,
    	@nom varchar(50),
    	@prenom varchar(50),
    	@age int,
    	@idstatut int,
    	@annee int,
    	@actif int,
    	@cheminPhoto varchar(350),
    	@CoursSuivis CoursType READONLY
     
    AS
    BEGIN
    IF(@age BETWEEN 12 AND 20)
    	BEGIN
    		UPDATE Eleve SET Nom=@nom , Prenom=@prenom, Age=@age, IDStatut=@idstatut, Annee=@annee, Actif=@actif, Photo=@cheminPhoto
    		WHERE IDEleve = @idEleve 
    	END
     
     
    	BEGIN
    	DECLARE @NbreCoursActuel int
    	DECLARE @NbreCours int
    	BEGIN
    		set @NbreCoursActuel = (SELECT COUNT(*) FROM EleveCours WHERE IDEleve = @idEleve);
    		set @NbreCours = (SELECT COUNT(*) FROM @CoursSuivis);
    	END
    	IF @NbreCoursActuel = @NbreCours
    	PRINT 'OK_1'
    		BEGIN
    		DECLARE @identifiantEleve int;
    		SET @identifiantEleve  = ( SELECT IDEleve FROM EleveCours WHERE IDEleve = @idEleve);
    		While (@identifiantEleve = @idEleve)
    			BEGIN
    			UPDATE EleveCours SET IDCours = (SELECT CoursId FROM @CoursSuivis), CoursNom = (SELECT CoursNom FROM @CoursSuivis) WHERE IDEleve = @idEleve;
    			END
    		END
    	END
    END
    Mon problème est que lorsque j'exécute ma procédure, ma sous requète retourne visiblement plusieurs valeurs ce qui n 'est pas permis lorsqu'elle suit un =, !=, <... . Le message d'erreur est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Msg 512, Niveau 16, État 1, Procédure sp_EditerEleve, Ligne 38
    Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
    Auriez-vous une idée?

    Merci

  2. #2
    Membre expert Avatar de iberserk
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    Novembre 2004
    Messages
    1 795
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2004
    Messages : 1 795
    Points : 3 173
    Points
    3 173
    Par défaut
    Mon problème est que lorsque j'exécute ma procédure, ma sous requète retourne visiblement plusieurs valeurs ce qui n 'est pas permis lorsqu'elle suit un =, !=, <... . Le message d'erreur est :
    JE ne vois pas ce que l'on peut vous dire de plus, vous connaissez manifestement la réponse... inclue dans votre question

    L'une de ces deux sous-requêtes retourne plusieurs résultat... a vous de voir pourquoi

  3. #3
    Membre habitué
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2011
    Messages
    118
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 118
    Points : 180
    Points
    180
    Par défaut
    Bonjour,

    C'est cette ligne là qui doit poser problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    UPDATE EleveCours SET IDCours = (SELECT CoursId FROM @CoursSuivis), CoursNom = (SELECT CoursNom FROM @CoursSuivis) WHERE IDEleve = @idEleve;
    Si la variable de type udt @CoursSuivis contient plusieurs valeurs, ce qui est fort probable sinon pas la peine d'utiliser ce type de données, cette erreur ce produira.
    Vous tentez de mette à jour chaque ligne de la table EleveCours où votre condition est remplie (filtre sur IDEleve) avec plusieurs valeurs (le nombre de ligne trouvée dans @CoursSuivis).

    Il va falloir gérer vos traitements plus finement, en comparant les données de la table EleveCours à celles de la variable @CoursSuivi et faire les traitements qui s'imposent (UPDATE, DELETE, INSERT)

    D'un point de vue général, vous allez avoir quelques problèmes pour obtenir le résultat que vous attendez, cette partie de code est très critique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    		DECLARE @identifiantEleve int;
    		SET @identifiantEleve  = ( SELECT IDEleve FROM EleveCours WHERE IDEleve = @idEleve);
    		While (@identifiantEleve = @idEleve)
    			BEGIN
    			UPDATE EleveCours SET IDCours = (SELECT CoursId FROM @CoursSuivis), CoursNom = (SELECT CoursNom FROM @CoursSuivis) WHERE IDEleve = @idEleve;
    			END
    		END
    Boucle infinie très probable.
    Déjà @identifiantEleve sera toujours égal à @idEleve s'il existe dans la table EleveCours.
    Ensuite votre boucle While teste une condition sur 2 variables qui ne varient jamais dans votre boucle, la condition n'évoluera donc jamais, ce qui fait que si vous rentrez dans la boucle vous n'en ressortirez pas.

    Vous mettez également beaucoup de BEGIN / END qui ne servent pas.

  4. #4
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 862
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 862
    Points : 53 013
    Points
    53 013
    Billets dans le blog
    6
    Par défaut
    Déjà on enlève toutes les BEGIN END inutiles et les parenthèses qui servent à rien et on indente... (on se croirait en primaire)...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    CREATE PROCEDURE [dbo].[sp_EditerEleve]
    	@idEleve int,
    	@nom varchar(50),
    	@prenom varchar(50),
    	@age int,
    	@idstatut int,
    	@annee int,
    	@actif int,
    	@cheminPhoto varchar(350),
    	@CoursSuivis CoursType READONLY
     
    AS
    IF @age BETWEEN 12 AND 20
    		UPDATE Eleve 
            SET    Nom=@nom ,  
                   Prenom=@prenom, 
                   Age=@age, 
                   IDStatut=@idstatut, 
                   Annee=@annee, 
                   Actif=@actif, 
                   Photo=@cheminPhoto
    		WHERE  IDEleve = @idEleve 
     
    DECLARE @NbreCoursActuel int, @NbreCours int
    BEGIN
    	SELECT @NbreCoursActuel = COUNT(*) 
        FROM EleveCours WHERE IDEleve = @idEleve;
        SELECT @NbreCours = COUNT(*) 
        FROM @CoursSuivis;
    END
    IF @NbreCoursActuel = @NbreCours
    	PRINT 'OK_1'
     
    DECLARE @identifiantEleve int;
    SELECT @identifiantEleve  = IDEleve 
    FROM   EleveCours 
    WHERE IDEleve = @idEleve;
    WHILE @identifiantEleve = @idEleve
       UPDATE EleveCours 
       SET IDCours =  (SELECT CoursId  
                       FROM @CoursSuivis), 
           CoursNom = (SELECT CoursNom 
                       FROM @CoursSuivis) 
       WHERE IDEleve = @idEleve;
    Ensuite vous utilisez des sous requêtes là ou des jointures devraient être faites et du procédural là ou des requêtes devrait être...

    A +

  5. #5
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 862
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 862
    Points : 53 013
    Points
    53 013
    Billets dans le blog
    6
    Par défaut
    De plus ce code ne sert à rien dans votre PS :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    DECLARE @NbreCoursActuel int, @NbreCours int
    BEGIN
    	SELECT @NbreCoursActuel = COUNT(*) 
        FROM EleveCours 
        WHERE IDEleve = @idEleve;
        SELECT @NbreCours = COUNT(*) 
        FROM @CoursSuivis;
    END
    IF @NbreCoursActuel = @NbreCours
    	PRINT 'OK_1'
    Ces variables ne sont pas utilisées ailleurs...

    A +

  6. #6
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 862
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 862
    Points : 53 013
    Points
    53 013
    Billets dans le blog
    6
    Par défaut
    En sus cette boucle est une boucle infinie :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    WHILE @identifiantEleve = @idEleve
       UPDATE EleveCours 
       SET IDCours =  (SELECT CoursId  
                       FROM @CoursSuivis), 
           CoursNom = (SELECT CoursNom 
                       FROM @CoursSuivis) 
       WHERE IDEleve = @idEleve;
    A +

Discussions similaires

  1. Delete avec sous requetes qui retourne plusieurs resultats
    Par Biosox dans le forum Langage SQL
    Réponses: 3
    Dernier message: 02/07/2010, 14h55
  2. l'équivalent de CF mais qui retourne plus qu'une résultat
    Par monpseudonom dans le forum Reports
    Réponses: 6
    Dernier message: 21/05/2009, 16h34
  3. Réponses: 16
    Dernier message: 04/09/2006, 10h27
  4. Requete qui fontionne plus sous MySQL 4.0
    Par Gamleur84 dans le forum Requêtes
    Réponses: 2
    Dernier message: 30/08/2006, 15h08
  5. Cette sous-requete peut retourner au plus un enregistrement?
    Par zorba49 dans le forum Langage SQL
    Réponses: 1
    Dernier message: 09/03/2006, 11h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo