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 :

Remplacer les valeurs NULL par un intitulé


Sujet :

Développement SQL Server

  1. #1
    Membre habitué
    Remplacer les valeurs NULL par un intitulé
    Bonjour,

    j'essaye de faire des sous-totaux par mois et par année mais lorsque je veux remplacer les NULL correspondant à ma ligne de sous-totaux par un intitulé via le COALESCE il n'accepte pas

    il m'affiche l'erreur suivante : Échec de la conversion de la valeur varchar 'total' en type de données int

    si vous pouviez m'aider svp

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    SELECT coalesce(code_client, 'total_client')
    	,coalesce(month(DATE_COMMANDE), 'total') mois
    	,YEAR(DATE_COMMANDE) annee
    	,sum(port) frais_port
    FROM commandes
    GROUP BY code_client
    	,month(DATE_COMMANDE)
    	,YEAR(DATE_COMMANDE)
    WITH rollup;


    merci

  2. #2
    Expert éminent sénior
    J'avais mal lu votre requête, je vois que vous cherchez à remplacer une date par une constante chaine de caractères, c'est ça qui ne convient pas je pense.

    Vous pouvez par exemple coder coalesce(month(DATE_COMMANDE), 0) mois

  3. #3
    Membre habitué
    oui vous avez raison mais est ce qu'il y a un moyen d'intégrer du texte pour intituler les sous totaux ? pour une meilleure lisibilité

  4. #4
    Expert éminent
    Oui mais il va falloir faire attention au type des données : un libellé en varchar versus un numéro de mois en INT, il va falloir faire de la conversion et ça risque de ne pas être super performant.
    les règles du forum - mode d'emploi du forum
    Aucun navigateur ne propose d'extension boule-de-cristal : postez votre code et vos messages d'erreurs. (Rappel : "ça ne marche pas" n'est pas un message d'erreur)
    JE NE RÉPONDS PAS aux questions techniques par message privé.

  5. #5
    Membre habitué
    merci

    mais comment je fais du coup dans le code ?

    dois je utiliser un cast pour lui faire comprendre qu'il dois lire mon intitulé en INT malgré qu'il soit en VARCHAR ? car effectivement ma colonne est en INT

  6. #6
    Expert éminent sénior
    quelque chose comme coalesce(convert(char(2),month(DATE_COMMANDE)), 'XX')

  7. #7
    Expert éminent
    Bonjour,

    Même si c'est clairement pas une bonne pratique, vu qu'on est sur SQL Server, il est préférable d'utiliser la fonction spécifique de SQL Server ISNULL() plutôt que COALESCE().

    J'ai toujours pas compris pourquoi, mais ISNULL() peut s'avérer drastiquement plus rapide, ce n'est pas un simple alias.
    On ne jouit bien que de ce qu’on partage.

  8. #8
    Expert éminent sénior
    Je suppose que ce constat ne vaut que quand les arguments sont de types différents, en effet, COALESCE convertit les types si besoin (par exemple un char(10) et un char(5) ==> char(10)) alors que ISNULL ne le fait pas.
    Si on convertit en amont comme je l'ai proposé plus haut, il ne doit pas y avoir de différence

  9. #9
    Expert éminent
    En relisant la documentation, je pense que la très grosse différence de performances réside surtout dans le fait que COALESCE n'est pas une fonction à proprement parler, mais plutôt une sorte de "MACRO" au sens C++, à savoir que l'optimiseur converti l'insrtuction en un CASE :

    L’expression COALESCE est un raccourci syntaxique de l’expression CASE. Autrement dit, le code COALESCE(expression1, ...n) est réécrit par l’optimiseur de requête sous la forme de l’expression CASE suivante :
    SQL

    Copier
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    CASE  
    WHEN (expression1 IS NOT NULL) THEN expression1  
    WHEN (expression2 IS NOT NULL) THEN expression2  
    ...  
    ELSE expressionN  
    END

    Cela signifie que les valeurs d’entrée (expression1, expression2, expressionN, etc.) sont évaluées plusieurs fois. Une expression de valeur contenant une sous-requête est considérée comme non déterministe et la sous-requête est évaluée deux fois. Ce résultat est conforme à la norme SQL. Dans l’un ou l’autre cas, les résultats retournés peuvent être différents entre la première évaluation et les suivantes.
    Par exemple, lorsque le code COALESCE((subquery), 1) est exécuté, la sous-requête est évaluée deux fois. Par conséquent, vous pouvez obtenir des résultats différents selon le niveau d'isolement de la requête.
    Du coup, surtout si on ne travaille pas avec des valeurs littérales et constantes, on peut effectivement avoir des performances très dégradées... le pire, c'est que COALESCE peut au final retourner NULL quand bien même si l'un des paramètres est une expression littérale non nulle : il suffit qu'un précédent paramètre soit une sous-requête qui retourne non null à la première exécution, et null à la seconde !

    Bref, pour des raisons de performances, mais aussi de santé mentale du gars qui fait la maintenance, ISNULL() est donc à privilégier quand applicable

    https://docs.microsoft.com/fr-fr/sql...l-server-ver15
    https://docs.microsoft.com/fr-fr/sql...l-server-ver15
    On ne jouit bien que de ce qu’on partage.

  10. #10
    Expert éminent sénior
    une bizarrerie de SQLserver , mais c'est bon à savoir !

  11. #11
    Modérateur

    Bonjour,

    Point de bizarrerie ici, juste une mise en application de la norme SQL.
    C'est en effet elle qui définit COALESCE comme une forme abréviée de CASE (au même titre que NULLIF), avec d'ailleurs une définition récursive :

    ‘‘COALESCE (V1, V2, . . . , Vn)’’, for n >= 3, is equivalent to the following <case specification>:
    CASE WHEN V1 IS NOT NULL THEN V1 ELSE COALESCE (V2, . . . , Vn) END
    De ce fait, la première expression non nulle sera en effet évaluée deux fois, comme pour tout CASE : une fois pour le test de nullité (CASE WHEN V1 IS NOT NUL), une deuxième fois pour le retour (THEN V1).
    Deux conséquences donc :
    1/ si l'expression testée est complexe (sous requete scalaire scalaire par exemple), alors les performances seront moindres qu'avec ISNULL qui n’évalue qu'une fois chaque expression.
    2/ une résultat potentiellement différent, voire un retour NULL comme l'a indiqué StringBuilder, si l'expression évaluée n'est pas déterministe (résultat différent à chaque évaluation)

    Enfin, concernant le type de retour, COALESCE - toujours selon la norme - renvoie le type de l'argument ayant la plus forte précédence, alors que ISNULL renvoie le type du premier argument.
    Là aussi, ça peut engendrer des petites différences de comportement :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    DECLARE @NULL CHAR(2);
     
    SELECT 
    	COALESCE(@NULL, '1234') AS resultCOALESCE
    	,ISNULL(@NULL, '1234') AS resultISNULL

    ==>
    resultCOALESCE	resultISNULL
    1234		12
    

###raw>template_hook.ano_emploi###