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 :

[SQL SERVER 2005] Procédure Transac SQL pour un nul


Sujet :

Développement SQL Server

  1. #1
    Membre expérimenté
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    747
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 747
    Points : 1 332
    Points
    1 332
    Par défaut [SQL SERVER 2005] Procédure Transac SQL pour un nul
    Bonjour à tous,

    J'essaie vainement de créer une procédure transac SQL et je suis super débutant...

    Voilà à quoi ça ressemble

    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
    -- ================================================
    -- Template generated from Template Explorer using:
    -- Create Procedure (New Menu).SQL
    --
    -- Use the Specify Values for Template Parameters 
    -- command (Ctrl-Shift-M) to fill in the parameter 
    -- values below.
    --
    -- This block of comments will not be included in
    -- the definition of the procedure.
    -- ================================================
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    -- =============================================
    -- Author: <Author,,Name>
    -- Create date: <Create Date,,>
    -- Description: <Description,,>
    -- =============================================
    CREATE PROCEDURE [dbo].[csp_CreateTest2] @Fam nvarchar
    -- Add the parameters for the stored procedure here
    AS
    set nocount on
    DECLARE @Fam3204 numeric
    select @Fam3204 = dataid from filedata where lang_00 = @Fam and descid = 3204
    insert into temp_test (tt) values(cast(@Fam3204 as varchar))
    set nocount off
    GO
    alors, si je fait la requête select manuellement sur la table filedata et que je fixe le paramètre @Fam à une valeur 'TOTO', j'ai bien une réponse numérique (1542)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select dataid from filedata where lang_00='TOTO' and descid = 3204
    me renvoie 1542

    la table temp_test a un champ unique TT de type varchar

    si j'exécute la procédure en mettant en paramètre d'entrée TOTO, la table TEMP_TEST a bien un nouvel enregistrement mais il a pour valeur NULL...

    Merci de m'avoir lu

  2. #2
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Bonjour,

    C'est en fait parce que vous avez déclaré @Fam au type nvarchar.
    Comme vous n'avez pas précisé de largeur, celle-ci est par défaut à 1, donc 'TOTO' est tronqué à 'T'

    Pour le vérifier, il suffit d'exécuter :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    DECLARE @Fam nvarchar
    SET	@Fam = 'Toto'
    SELECT	@Fam
    Qui vous retourne 'T'.

    Si vous réécrivez votre procédure en vous débarrassant des fioritures produites par SQL Server Management Studio (SSMS), vous aurez donc :

    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
    CREATE PROCEDURE dbo.csp_CreateTest2
    	@Fam nvarchar
    AS
    BEGIN
    	SET NOCOUNT ON
     
    	DECLARE @Fam3204 NUMERIC
     
    	SELECT	@Fam3204 = dataid 
    	FROM	filedata 
    	WHERE	lang_00 = @Fam 
    	AND	descid = 3204
     
    	INSERT INTO temp_test (tt) 
    	VALUES(cast(@Fam3204 as varchar))
    END
    Vous avez fait d'autres erreurs, que je vais vous donner par ordre décroissant de gravité :

    - Si la colonne lang_00 ne doit jamais contenir des caractères autres que ceux de l'alphabet latin et des chiffres, passez au type varchar(n) si ce n'est pas déjà le cas.
    En effet le type nvarchar stocke les caractères en Unicode, qui consomme deux octets par caractère.
    varchar à l'inverse les stocke en ASCII, qui consomme un octet par caractère, mais ne supporte que les caractères latins (pas ceux des alphabets asiatiques, arabes, ...)
    Vous pouvez changer le type de votre colonne comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ALTER TABLE filedata 
    ALTER COLUMN lang_00 varchar(mêmeLongueurQueLaColonneNvarchar)
    - Écrivez votre requête de façon ensembliste, comme SQL l'est.
    Programmer en SQL est totalement différent de la façon de programmer en langages par objets ou procéduraux.
    SQL est un langage déclaratif, donc il vous suffit d'écrire ce que vous souhaitez faire ou obtenir.
    Dans Les langages par objets ou procéduraux, vous écrivez comment vous voulez arrivez au résultat.

    Votre début de requête SELECT est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT	@Fam3204 = dataid 
    FROM	filedata
    Et dans ce cas vous supposez qu'il n'y aura qu'une seule ligne qui satisfasse la requête, alors qu'il peut y en avoir plus (ou ne peut pas y en avoir), et dans ce cas votre INSERT est "partiel", donc faux.

    Voyez l'instruction INSERT que je vais vous donner plus bas.
    Pour comprendre l'effet, vous pouvez lire ce billet qui traite des triggers, mais l'idée de fond est la même.

    - Déclarez votre variable @Fam au même type que celui de la colonne lang_00, avec la longueur , par exemple varchar(5) ou nvarchar(4).
    Cela évite à SQL Server de faire le transtypage qui peut résulter en une lecture complète de la table, au lieu d'utiliser un index de la table

    - Pourquoi la colonne tt de la table temp_test n'est pas de type numeric ?
    Regardez la liste des types disponibles sous SQL Server ici, notamment pour le type numeric.
    Choisissez l'échelle et la précision en fonction de vos besoin, mais en prenant toujours le plus proche supérieur à vos besoins.
    Par exemple si vous avez besoin de stocker des chaînes dont vous êtes certain qu'elle ne n'auront jamais une longueur plus grande que 40 caractères, il n'y pas besoin de mettre varchar(255)

    - Qualifiez les noms des objets que vous manipulez (tables, fonctions, procédures, vues) par le nom du schéma auquel ils appartiennent.
    Par défaut c'est dbo.

    En bref, plus vous serez précis, moins vous polluerez votre base de données, plus elle a de chances d'être performante (sous réserve que son modèle soit correct !)

    Finalement, votre procédure peut s'écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    CREATE PROCEDURE dbo.csp_CreateTest2
    	@Fam varchar(5)
    AS
    BEGIN
    	SET NOCOUNT ON
     
    	INSERT	INTO dbo.temp_test (tt)
    	SELECT	CAST(dataid AS varchar(5))
    	FROM	dbo.filedata
    	WHERE	lang_00 = @Fam 
    	AND	descid = 3204
    END
    @++

  3. #3
    Membre expérimenté
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    747
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 747
    Points : 1 332
    Points
    1 332
    Par défaut
    Bonjour elsuket,

    Merci de cette réponse trés complète

    Pour éviter les éventuels doublons dans mes réponses, et les null, je devrais peut-être faire une requête du type

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        SELECT TOP 1    @Fam3204 = isnull(dataid, 0)
        FROM    filedata 
        WHERE    lang_00 = @Fam 
        AND    descid = 3204
    ?

    En tout cas merci encore de vos précieux conseils

  4. #4
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Héhé, ça c'est une solution de facilité qui vous posera plus de problèmes qu'autre chose

    Vous pourriez traiter les doublons en amont.
    Quelle est le traitement que vous effectuez et pourquoi avec-vous des doublons ou bien la colonne dataid à NULL ?

    @++

  5. #5
    Membre expérimenté
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    747
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 747
    Points : 1 332
    Points
    1 332
    Par défaut
    Re,

    Normalement il n'y a aucun doublon pour un descid et un lang_00 donné, le TOP 1 serait juste une mesure de "sécurité" (que je devrais coupler avec un tri, je pense)
    dataid ne peut-être null que si la requête SELECT ne trouve aucun enregistrement correspondant... mais est-il vraiment NULL d'ailleurs, dans ce cas ?

    peut-être comme ça ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        SELECT TOP 1  @Fam3204 = dataid
        FROM    filedata 
        WHERE    lang_00 = @Fam 
        AND    descid = 3204
        ORDER BY dataid
    Select @Fam3204  = isnull(@Fam3204, 0)

  6. #6
    Membre expérimenté
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    747
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 747
    Points : 1 332
    Points
    1 332
    Par défaut
    Bonjour à tous,

    en tout cas, j'ai réussi à faire ma procédure grâce à vous alors merci et je considère le fil comme résolu

    à bientôt

  7. #7
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    le TOP 1 serait juste une mesure de "sécurité"
    Justement non, il induira plutôt des erreurs dans vos données.
    Lorsque vous vous en rendrez compte, il sera probablement déjà trop tard pour corriger le tir

    Si vous ne voulez pas les NULL et que vous êtes certain de l'effet de votre requête (c'est à dire ce qu'elle signifie pour l'application que vous participez à écrire), il vous suffit de filtrer la clause SELECT de l'INSERT de la procédure stockée que je vous ai proposée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    INSERT INTO dbo.temp_test (tt)
    SELECT CAST(dataid AS varchar(5))
    FROM dbo.filedata
    WHERE lang_00 = @Fam 
    AND descid = 3204
    AND dataid > 0
    J'ai rajouté la dernière ligne. Comme NULL n'est pas une valeur, il ne vérifie pas le filtre.

    Mais je continue de penser que si vous écrivez ce code par "mesure de sécurité", c'est qu'il y a quelque chose à revoir dans la façon dont les données arrivent dans la table dbo.filedata

    @++

  8. #8
    Membre expérimenté
    Avatar de tototiti2008
    Homme Profil pro
    Formateur/développeur
    Inscrit en
    Octobre 2008
    Messages
    747
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Formateur/développeur

    Informations forums :
    Inscription : Octobre 2008
    Messages : 747
    Points : 1 332
    Points
    1 332
    Par défaut
    Bonjour elsuket,

    Merci, le mieux est que je fouille plus avant le fonctionnement actuel de l'application, ça permettra d'être sûr de la requête à réaliser pour être cohérent avec les données existantes

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [sql server 2005] Import dans sql server
    Par gmailex dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 10/01/2009, 19h19
  2. [SQL Server 2005] Procédure stockée dynamique ?
    Par nitrous007 dans le forum MS SQL Server
    Réponses: 13
    Dernier message: 20/12/2006, 13h54
  3. Réponses: 5
    Dernier message: 13/10/2006, 08h00

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