web-dev-qa-db-fra.com

Comment déterminer si un trait d'union (-) existe à l'intérieur d'une colonne

Dans une expression CASE, j'essaie de rechercher dans une colonne de texte pour identifier un trait d'union (-):

CASE 
     WHEN SUBSTRING(al.ALT_ADDRESS,1,1) IN('1','5','7') 
      AND al.NEW_ADDRESS CONTAINS '-' 
     THEN CONCAT(al.ALT_ADDRESS,al.NEW_ADDRESS)

Le trait d'union peut être situé n'importe où dans la colonne, et j'ai donc juste besoin de savoir s'il existe, peu importe où il se trouve réellement dans la colonne.

J'utilise actuellement exactement le même code que @ Josh fourni (LIKE '%-%'), mais cela ne fonctionne pas, car il ne renvoie pas les données correctes pour plusieurs cas spécifiques où je sais que cela "devrait" être. Le texte exact dans ALT_ADDRESS est: "2754 Churchill Circle". Le texte exact dans NEW_ADDRESS est: "O-89421". Toutefois, les résultats renvoyés n'incluent pas le NEW_ADDRESS (O-89421).

J'ai confirmé ce tiret dans NEW_ADDRESS correspond vraiment au tiret que j'utilise la recherche (ASCII 45).

4
Mike Jones

Une approche alternative à la réponse existante consiste à utiliser la fonction CHARINDEX () qui renvoie la position de la chaîne spécifiée si elle existe, sinon 0.

select charindex('-','kevin-')

Renvoie 6, car le trait d'union est situé à la sixième position de la chaîne, par rapport à

select charindex('-','kevin')

renvoie 0 car le "-" n'est pas présent dans la chaîne.


Par suggestion de John Eisbrener , PATINDEX est également une option, et il permet des caractères génériques - qui peuvent s'avérer bénéfiques dans certaines circonstances.

10
kevinnwhat

Vous n'avez pas mentionné pourquoi le code que vous avez fourni ne fonctionne pas. CONTAINS est destiné à être utilisé avec la fonction de recherche de texte intégral de SQL Server. Si vous ne l'utilisez pas, vous devez utiliser une clause LIKE avec des caractères génériques:

CASE WHEN SUBSTRING(al.ALT_ADDRESS,1,1) IN('1','5','7') AND al.NEW_ADDRESS LIKE '%-%' 
THEN CONCAT(al.ALT_ADDRESS,al.NEW_ADDRESS)

Même si vous utilisez la recherche en texte intégral, le comportement de correspondance avec les tirets peut être inattend et Microsoft recommande d'utiliser à la place LIKE.


Vous pouvez vérifier que le caractère est vraiment un trait d'union, quelque chose comme ça devrait fonctionner:

SELECT 
    ASCII('-') as RealHypen,
    ASCII(SUBSTRING(NEW_ADDRESS, 1, 1))
FROM YourTable
WHERE ALT_ADDRESS = '2754 Churchill Circle';

Soit dit en passant, l'expression LIKE ci-dessus n'est pas en mesure d'utiliser les capacités de recherche d'un index b-tree dans SQL Server, donc les performances peuvent souffrir sur les grandes tables si une opération d'analyse importante est requise. La meilleure façon d'atténuer cela (si cela s'applique à vous ou à d'autres dans une situation similaire) dépend fortement du contexte, mais en général, les principales alternatives sont:

  • Indexation d'une colonne calculée qui évalue la condition de recherche
  • Utilisation de déclencheurs pour conserver à l'avance le résultat de la recherche
  • Utilisez un outil externe plus adapté à la recherche de texte (Elasticsearch est populaire)
  • Utilisez n-grammes (généralement pour les sous-chaînes de 3 caractères ou plus)
  • Utilisez la recherche en texte intégral (cela n'aidera pas les caractères génériques en soi, ou ce cas spécifique, mais peut fonctionner pour la recherche basée sur Word).

Si vous êtes intéressé à explorer l'aspect performance, veuillez poser une question de suivi.

14
Josh Darnell

LIKE '%-%'

J'utilise actuellement le même code que celui fourni par @Josh (LIKE '%-%'), mais cela ne fonctionne pas, car il ne renvoie pas les données correctes pour plusieurs cas spécifiques où je sais que cela "devrait" être. Le texte exact dans ALT_ADDRESS est: "2754 Churchill Circle". Le texte exact dans NEW_ADDRESS est: "O-89421". Cependant, les résultats renvoyés n'incluent pas la NEW_ADDRESS (O-89421).

Je n'ai pas du tout ce problème,

SELECT new_address
FROM ( VALUES
  ('O-89421')
) AS t(new_address)
WHERE new_address LIKE '%-%';

Semble fonctionner pour moi

1
Evan Carroll