1
votes

Recherche de valeurs correspondantes dans un champ, séparées par des espaces

Dans SQL Server, j'ai un champ contenant des données délimitées (par un espace).

Ex.

2|1 2 3 3 5
3|1 1 1 1 1

Je dois parcourir tous les enregistrements du DB et interrogez le champ de données délimité et comparez les troisième et quatrième parties de données les unes par rapport aux autres et si elles correspondent, retournez le recid et le champ délimité entier.

Donc, d'après mon exemple, les enregistrements 2 et 3 ont une correspondance parties de données, donc il renverrait: -

recid| Delimited data field
1| 1 2 3 4 5
2| 1 2 3 3 5
3| 1 1 1 1 1

Parce que 3 3 correspond, tout comme 1 1.

Merci.

p >


4 commentaires

Corrigez votre modèle de données! Vous ne devez pas stocker de nombres sous forme de chaînes. Vous ne devez pas non plus stocker plusieurs valeurs dans une seule colonne. Je ferais l'effort de corriger les données plutôt que d'essayer de résoudre ce problème.


Vos données sont-elles toujours en 5 parties? Serait-ce moins / plus? Qu'avez-vous essayé? (Gordan a raison cependant, vous devriez réparer votre structure, si vous pouvez le faire, les bénévoles ici se feront un plaisir de vous montrer comment.)


Les tables ont des colonnes , pas des champs.


Et ce ne sont pas des lignes des enregistrements.


6 Réponses :


2
votes

S'il s'agit toujours d'un chiffre et du même format, vous pouvez essayer comme suit.

;WITH cte 
     AS (SELECT F1.recid, 
                F1.[data], 
                O.splitdata, 
                Row_number() 
                  OVER( 
                    partition BY recid 
                    ORDER BY (SELECT 1)) rn 
         FROM   (SELECT *, 
                        Cast('<X>' + Replace(F.data, ' ', '</X><X>') + '</X>' AS 
                             XML) 
                        AS 
                                xmlfilter 
                 FROM   @table F)F1 
                CROSS apply (SELECT fdata.d.value('.', 'varchar(50)') AS 
                                    splitdata 
                             FROM   f1.xmlfilter.nodes('X') AS fdata(d)) O) 
SELECT c1.recid, 
       c1.data 
FROM   cte c1 
       INNER JOIN cte c2 
               ON c1.recid = c2.recid 
                  AND c1.rn = 3 
                  AND c2.rn = 4 
                  AND c1.splitdata = c2.splitdata 
GROUP  BY c1.recid, 
          c1.data 

Sinon (les nombres ne sont pas à un seul chiffre), vous pouvez essayer comme suit.

select * from @table
where SUBSTRING([data], 5, 1) = SUBSTRING([data], 7, 1)

Démo en ligne


8 commentaires

Cela suppose que les données délimitées ne comportent qu'un seul caractère. Cela pourrait être une hypothèse de coût.


@Larnu, je suis d'accord, c'est pourquoi j'ai mentionné dans la réponse. Je mettrai à jour pour l'approche différente


Je sais, mais je soupçonne qu'il est très peu probable que les valeurs ne soient que 0-9 .


@Larnu, j'ai également mis à jour la réponse pour l'autre scénario.


Excellent merci beaucoup @PSK comment pourrais-je récupérer les 4 premiers numéros de ligne. par exemple 1 2 3 3 1 1 1 1?


Je suis désolé de ne pas comprendre votre question, pouvez-vous l'expliquer plus en détail.


donc si j'avais `` 1 22 33 33 44 '' et que cela correspond à `` 33 33 '', comment pourrais-je sélectionner uniquement les 3 premières parties de la colonne, par exemple «1 22 33»?


pouvez-vous vérifier cela rextester.com/KMX12033 , vous pouvez également voter pour la réponse si vous le souhaitez :)



0
votes

Il faut diviser les données, donner le numéro de ligne, puis comparer.

Schéma:

recid   Delimited_data_field
2       1 2 3 3 5
3       1 1 1 1 1

Solution:

;WITH CTE
AS (
    SELECT recid
        ,Delimited_data_field
        ,ROW_NUMBER() OVER (PARTITION BY recid ORDER BY (SELECT 1)) RNO
        ,splt.X.value('.', 'INT') VAL
    FROM (
        SELECT recid
            ,Delimited_data_field
            ,CAST('<M>' + REPLACE(Delimited_data_field, ' ', '</M><M>') + '</M>' AS XML) DATA
        FROM #TAB
        ) A
    CROSS APPLY A.DATA.nodes('/M') splt(x)
    )
SELECT C.recid
    ,C2.Delimited_data_field
FROM CTE C
INNER JOIN CTE C2 ON C.recid = C2.recid AND C.RNO = 3 AND C2.RNO = 4
AND C.VAL = C2.VAL 

Résultat:

SELECT *  INTO #TAB FROM (
SELECT 1, '1 2 3 4 5' UNION ALL
SELECT 2, '1 2 3 3 5' UNION ALL
SELECT 3, '1 1 1 1 1'  
)A (recid , Delimited_data_field)


2 commentaires

J'ai posté exactement la même réponse avant vous :)


Oui .. exactement la même chose .. :) @PSK



0
votes

Votre question comprend deux parties: trouvez la nième division, puis comparez. Votre première approche devrait être de résoudre le problème jusqu'à ce que vous trouviez des fonctions intégrées capables de faire le travail. voici une méthode qui renvoie le résultat de la requête interne après la séparation et les comparaisons externes:

SELECT recid,Delimited from (
        SELECT recid,Delimited, SUBSTRING(Delimited, 
              charindex(' ', Delimited, (charindex(' ', Delimited, 1))+2)+1,1) 
              third, SUBSTRING(Delimited, charindex(' ',Delimited, 
              (charindex(' ', Delimited, 1))+3)+1,1) 
              fourth FROM YourTable) tr
        WHERE third = fourth

Voir une sous-chaîne simple et charindex peuvent faire le travail.


0 commentaires

0
votes

Voici une autre solution à cela.

J'ai modifié la fonction de fractionnement dans ce lien ( T-SQL: Opposé à la concaténation de chaînes - comment diviser une chaîne en plusieurs enregistrements ) un peu pour le rendre utile dans votre scénario. p>

Voici la fonction.

select recid, deldata
from so1
where dbo.SplitAndGetNumberAt (' ', deldata, 3) = dbo.SplitAndGetNumberAt (' ', deldata, 4)

Vous pouvez maintenant utiliser cette fonction pour obtenir la 3e et 4e position des nombres et comparer facilement.

CREATE FUNCTION dbo.SplitAndGetNumberAt (@sep char(1), @s varchar(512), @pos int)
RETURNS INT
BEGIN
declare @val as varchar(10);

WITH Pieces(pn, start, stop) AS (
    SELECT 1, 1, CHARINDEX(@sep, @s)
    UNION ALL
    SELECT pn + 1, stop + 1, CHARINDEX(@sep, @s, stop + 1)
    FROM Pieces
    WHERE stop > 0
)
SELECT @val = SUBSTRING(@s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END)
FROM Pieces where pn = @pos;

RETURN @val
END

J'espère que cela vous aidera.


0 commentaires

0
votes

Si vous disposez de SQL Server 2016 ou version ultérieure, vous pouvez essayer une approche utilisant OPENJSON () pour fractionner vos données d'entrée. La partie importante ici est le fait que lorsque OPENJSON analyse un tableau JSON, les index des éléments dans le texte JSON sont renvoyés sous forme de clés (basé sur 0).

Entrée:

RecId   Data
2       1 2 3 3 5
3       1 1 1 1 1


0 commentaires

0
votes

Juste pour le plaisir, une sorte de codage fou:

DECLARE @Table Table (
    recid               INT,
    DelimitedDataField  VARCHAR(32)
)

INSERT @Table (recid, DelimitedDataField)
VALUES
    (1, '1 2 3 4 5'),
    (2, '1 2 3 3 5'),
    (3, '1 1 1 1 1')

SELECT *
FROM @Table
WHERE
SUBSTRING (
    STUFF(
        STUFF(
            DelimitedDataField + ' - - -',
            1,
            CHARINDEX(' ', DelimitedDataField + ' - - -'),
            ''
        ),
        1,
        CHARINDEX(' ', STUFF(
                        DelimitedDataField + ' - - -',
                        1,
                        CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
                 ),
        ''),
    1,
    CHARINDEX(' ', STUFF(
        STUFF(
            DelimitedDataField + ' - - -',
            1,
            CHARINDEX(' ', DelimitedDataField + ' - - -'),
            ''
        ),
        1,
        CHARINDEX(' ', STUFF(
                        DelimitedDataField + ' - - -',
                        1,
                        CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
                 ),
        '')
        )
) = 
SUBSTRING (
        STUFF(
            STUFF(
                STUFF(
                    DelimitedDataField + ' - - -',
                    1,
                    CHARINDEX(' ', DelimitedDataField + ' - - -'),
                    ''
                ),
                1,
                CHARINDEX(' ', STUFF(
                                DelimitedDataField + ' - - -',
                                1,
                                CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
                         ),
                ''),
            1,
            CHARINDEX(' ', STUFF(
                STUFF(
                    DelimitedDataField + ' - - -',
                    1,
                    CHARINDEX(' ', DelimitedDataField + ' - - -'),
                    ''
                ),
                1,
                CHARINDEX(' ', STUFF(
                                DelimitedDataField + ' - - -',
                                1,
                                CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
                         ),
                '')
            ),
            ''
        ),
        1,
        CHARINDEX(' ',      STUFF(
            STUFF(
                STUFF(
                    DelimitedDataField + ' - - -',
                    1,
                    CHARINDEX(' ', DelimitedDataField + ' - - -'),
                    ''
                ),
                1,
                CHARINDEX(' ', STUFF(
                                DelimitedDataField + ' - - -',
                                1,
                                CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
                         ),
                ''),
            1,
            CHARINDEX(' ', STUFF(
                STUFF(
                    DelimitedDataField + ' - - -',
                    1,
                    CHARINDEX(' ', DelimitedDataField + ' - - -'),
                    ''
                ),
                1,
                CHARINDEX(' ', STUFF(
                                DelimitedDataField + ' - - -',
                                1,
                                CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
                         ),
                '')
            ),
            ''
        ))
)

AND SUBSTRING (
    STUFF(
        STUFF(
            DelimitedDataField + ' - - -',
            1,
            CHARINDEX(' ', DelimitedDataField + ' - - -'),
            ''
        ),
        1,
        CHARINDEX(' ', STUFF(
                        DelimitedDataField + ' - - -',
                        1,
                        CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
                 ),
        ''),
    1,
    CHARINDEX(' ', STUFF(
        STUFF(
            DelimitedDataField + ' - - -',
            1,
            CHARINDEX(' ', DelimitedDataField + ' - - -'),
            ''
        ),
        1,
        CHARINDEX(' ', STUFF(
                        DelimitedDataField + ' - - -',
                        1,
                        CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
                 ),
        '')
        )
) <>'-'


0 commentaires