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 :

Cherche idées pour une requête assembliste pour reconstituer une chaîne de caractères


Sujet :

Développement SQL Server

  1. #1
    FMJ
    FMJ est déconnecté
    Membre averti
    Profil pro
    tutu
    Inscrit en
    Octobre 2003
    Messages
    416
    Détails du profil
    Informations personnelles :
    Localisation : France, Aveyron (Midi Pyrénées)

    Informations professionnelles :
    Activité : tutu

    Informations forums :
    Inscription : Octobre 2003
    Messages : 416
    Points : 356
    Points
    356
    Par défaut Cherche idées pour une requête assembliste pour reconstituer une chaîne de caractères
    Bonjour,
    Je vous soumets le problème suivant.
    Soit une Table T1 qui contient la colonne T1.CLASSEMENT qui est un CHAR(999) avec des valeurs de la forme "---------X-----------------------------X------------------ ........etc.......". Où "-" représente une position non utilisée et "X" une position utilisée.
    Soit la Table T2 qui contient la colonne T2.ID qui est un identifiant unique et la colonne T2.RANG qui est un INT . Ce T2.RANG représente la position d'une ligne donnée dans un CLASSEMENT donné (ex: 10 et 30 dans l'exemple ci-dessus).

    Le but serait de pouvoir reconstituer les valeurs de T1.CLASSEMENT à partir des valeurs de T2.
    Je ne vois pour l'instant que 2 approches possibles :
    > La plus évidente mais la moins séduisante : utilisation d'un curseur qui parse T2. Moins on utilise de curseur, mieux on se porte !
    > Soit de façon ensembliste avec un CTE qui permettrait créer une table avec toutes les positions de CLASSEMENT (de 1 à 999) et de faire dessus une requête avec une agrégation de caractères FOR XML PATH qui parse toutes les positions possibles de CLASSEMENT (et qui met "X" si le ligne correspond à la position et "-" dans le cas contraire). Ce n'est pas orthodoxe et il faut ponctuellement lever la limitation des CTE à 100 récurrences.
    Trouvant cette méthode "un peu" tirée par les cheveux, j'aimerais bien trouver une autre approche.
    Si vous avez des idées, merci d'avance.

  2. #2
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Bonjour,

    Pour ce type de probléme, fournir un jeu d'essai sous forme de CREATE TABLE + INSERT serait une bonne chose pour aider a comprendre et chercher une solution.

    Voici une solution à base de CTE récursive...
    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
     
    WITH T2 AS (
    	SELECT 2 AS Rang
    	UNION ALL SELECT 4
     
    ),
    	T2RN AS (
    		SELECT Rang, ROW_NUMBER() OVER(ORDER BY Rang ASC) AS RNAsc,  ROW_NUMBER() OVER(ORDER BY Rang DESC) AS RNDesc
    		FROM T2
    ),
    	Rec AS (
    	SELECT STUFF(REPLICATE('-', 5),Rang, 1, 'X') AS Res, T2RN.RNDesc, T2RN.RNAsc
    	FROM T2RN
    	WHERE RNDesc = 1
    	UNION ALL
    	SELECT STUFF(Res,Rang, 1, 'X'), T2RN.RNDesc, T2RN.RNAsc
    	FROM Rec
    	INNER JOIN T2RN
    		ON T2RN.RNDesc = Rec.RNDesc + 1
    	)
    SELECT Res
    FROM Rec
    WHERE RNAsc = 1
    ça risque de pas être terrible au niveau performances.

    Une solution en effet à base de XML PATH est possible également, mais pas forcément mieux niveau Perfs.

    Pouvez vous préciser un peu le contexte (besoin et volumétrie)

    Faire une fonction d'agrégation en SQL CLR serait peut-être à tester

  3. #3
    FMJ
    FMJ est déconnecté
    Membre averti
    Profil pro
    tutu
    Inscrit en
    Octobre 2003
    Messages
    416
    Détails du profil
    Informations personnelles :
    Localisation : France, Aveyron (Midi Pyrénées)

    Informations professionnelles :
    Activité : tutu

    Informations forums :
    Inscription : Octobre 2003
    Messages : 416
    Points : 356
    Points
    356
    Par défaut
    Bonjour,
    Merci pour ta réponse que je vais analyser.
    Je vais tâcher de donner un jeu de test.
    Il n'y a pas de contrainte de perf, la volumétrie est insignifiante. Actuellement, j'ai fait au plus simple en codant avec un curseur. C'est juste qu'intellectuellement, j'aurais bien aimé faire quelque chose de plus sexy.

  4. #4
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Une solution avec une fonction de fenêtrage et un agrégat :
    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
    create table tab ( ID int , RANG int );
     
    insert into tab (ID, RANG) values (1, 10), (1, 30),
                                      (2,  1), (2, 50),
                                      (3,  1),
                                      (4, 50);
     
     
    with cte_tab (ID, RANG) as
    (
    select distinct ID,    0 from tab union all
    select distinct ID,   51 from tab union all
    select ID, RANG from tab
    )
      ,  cte_replicate as
    (
    select ID
         , RANG
         , REPLICATE('-', RANG - 1 - lag(RANG) over(partition by ID order by RANG asc)) as rep
      from cte_tab
    )
      select ID
           , left(STRING_AGG(rep, 'X'), 50) as CLASSEMENT
        from cte_replicate
    group by ID;
     
    ID                                          CLASSEMENT
    --  --------------------------------------------------
     1  ---------X-------------------X--------------------
     2  X------------------------------------------------X
     3  X-------------------------------------------------
     4  -------------------------------------------------X
    NB : je me suis arrêté à 50 pour la lisibilité.

  5. #5
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Citation Envoyé par Waldar Voir le message
    Une solution avec une fonction de fenêtrage et un agrégat :
    bien vu, j'aime beaucoup le concept !

Discussions similaires

  1. Réponses: 14
    Dernier message: 09/02/2018, 11h19
  2. [XL-2007] Difficulté à faire une importation "à partir d'un site web"
    Par MathosDelFos dans le forum Excel
    Réponses: 1
    Dernier message: 28/12/2017, 23h50
  3. [SQL2K] Faire un requête conditionnelle pour un CURSOR
    Par zooffy dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 07/08/2007, 14h00
  4. Requête sur une chaîne de caractères
    Par Hakunamatata dans le forum Langage SQL
    Réponses: 9
    Dernier message: 02/04/2006, 18h27
  5. Problème pour exécuter une chaîne de caractères
    Par Pongo dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 02/09/2005, 10h34

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