Expressions régulières SQL Server dans T-SQL

127

Existe-t-il une bibliothèque d'expressions régulières écrite en T-SQL (pas de CLR, pas de SPT-SQL étendu et pur) pour SQL Server, et qui devrait fonctionner avec l'hébergement partagé?

Éditer:

  • Merci, je sais sur PATINDEX, LIKE, xp_ spset des solutions CLR
  • Je sais aussi que ce n'est pas le meilleur endroit pour les regex, la question est théorique :)
  • La fonctionnalité réduite est également acceptée
xnagyg
la source
2
J'ai aussi cette question. Je sais qu'une base de données n'est pas le meilleur endroit pour avoir cela, mais la réalité est que d'autres solutions nécessitent des autorisations d'administrateur SQL pour reconfigurer le serveur. Malheureusement, certains de nos clients ne choisiront pas d'activer CLR, etc., et nous nous en tenons uniquement aux solutions de base de données.
Paul Draper
@PaulDraper et xnagyg: pourquoi exclure SQLCLR? C'est le moyen le plus approprié pour obtenir des expressions régulières dans les requêtes. Et pourquoi certains de vos clients choisiraient-ils de ne pas activer CLR? Je n'ai pas encore trouvé de raison valable . Bien sûr, j'entends «sécurité» et «performance», mais ce sont de fausses raisons qui résultent du fait de ne pas comprendre comment fonctionne SQLCLR et comment il peut être restreint.
Solomon Rutzky le
3
@srutzky: la plupart des hébergeurs mutualisés n'autorisent pas le CLR. Vous devriez leur poser des questions sur la "sécurité" et les "performances" :)
xnagyg
@xnagyg Bien sûr, je peux en poser quelques-unes. Cependant, pointer du doigt le comportement d'un groupe ne répond en aucun cas à la question «existe-t-il une raison valable » à ce comportement. Il se pourrait tout aussi bien que tous ces fournisseurs d'hébergement partagé définissent leur politique sur la base du même malentendu. Et, à tout le moins, le simple fait que tous n'interdisent pas SQLCLR soutient en fait l'idée qu'il n'y a pas plus de problème que l'idée qu'il y a un problème car si ces problèmes existaient, les fournisseurs qui autorisent SQLCLR seraient confrontés ces problèmes et cesserait de le permettre.
Solomon Rutzky
@xnagyg Aussi, je devrais préciser que je parle en termes d'assemblys marqués SAFEet non marqués comme l'un EXTERNAL_ACCESSou l' autre ou UNSAFE(car je comprends pourquoi ces 2 derniers ensembles d'autorisations seraient problématiques pour un environnement d'hébergement partagé). Microsoft Azure SQL Database V12 (c'est-à-dire la nouvelle version de fin 2014), qui est un environnement partagé, autorise les assemblys marqués comme SAFE(et chargés via FROM 0x...plutôt qu'à partir d'une DLL car vous ne pouvez pas télécharger une DLL). Mais SAFEc'est tout ce qui est nécessaire pour les expressions régulières et BEAUCOUP d'autres fonctions très utiles.
Solomon Rutzky

Réponses:

77

Que diriez - vous de la PATINDEX fonction?

La correspondance de modèles dans TSQL n'est pas une bibliothèque regex complète, mais elle vous donne les bases.

(À partir de livres en ligne)

Wildcard  Meaning  
% Any string of zero or more characters.

_ Any single character.

[ ] Any single character within the specified range 
    (for example, [a-f]) or set (for example, [abcdef]).

[^] Any single character not within the specified range 
    (for example, [^a - f]) or set (for example, [^abcdef]).
Eric Z Beard
la source
7
Depuis au moins une décennie (SQL Server 2005+), LIKEa pris en charge tout ce qu'il PATINDEXfait. Je ne sais pas avant ça ...
TJ Crowder
1
Pourtant, cela ne me permet pas de spécifier un modèle qui correspond, par exemple, à un nombre variable de lettres ascii. %correspond à 0 ou plusieurs caractères (peu importe), ne [...]correspond qu'à un seul et il n'y a rien entre les deux.
Martijn Pieters
LIKE est le même que PATINDEX> 0
Ingénieur inversé
21

Si quelqu'un est intéressé par l'utilisation de regex avec CLR, voici une solution. La fonction ci-dessous (C # .net 4.5) renvoie un 1 si le modèle correspond et un 0 si le modèle ne correspond pas. Je l'utilise pour marquer des lignes dans les sous-requêtes. L'attribut SQLfunction indique au serveur SQL que cette méthode est l'UDF réelle que le serveur SQL utilisera. Enregistrez le fichier en tant que dll dans un endroit où vous pouvez y accéder à partir du studio de gestion.

// default using statements above
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text.RegularExpressions;

namespace CLR_Functions
{   
    public class myFunctions
    {
        [SqlFunction]
        public static SqlInt16 RegexContain(SqlString text, SqlString pattern)
        {            
            SqlInt16 returnVal = 0;
            try
            {
                string myText = text.ToString();
                string myPattern = pattern.ToString();
                MatchCollection mc = Regex.Matches(myText, myPattern);
                if (mc.Count > 0)
                {
                    returnVal = 1;
                }
            }
            catch
            {
                returnVal = 0;
            }

            return returnVal;
        }
    }
}

Dans Management Studio, importez le fichier dll via la programmation - Assemblys - Nouvel assemblage

Ensuite, exécutez cette requête:

CREATE FUNCTION RegexContain(@text NVARCHAR(50), @pattern NVARCHAR(50))
RETURNS smallint 
AS
EXTERNAL NAME CLR_Functions.[CLR_Functions.myFunctions].RegexContain

Ensuite, vous devriez avoir un accès complet à la fonction via la base de données dans laquelle vous avez stocké l'assembly.

Ensuite, utilisez dans des requêtes comme ceci:

SELECT * 
FROM 
(
    SELECT
        DailyLog.Date,
        DailyLog.Researcher,
        DailyLog.team,
        DailyLog.field,
        DailyLog.EntityID,
        DailyLog.[From],
        DailyLog.[To],
        dbo.RegexContain(Researcher, '[\p{L}\s]+') as 'is null values'
    FROM [DailyOps].[dbo].[DailyLog]
) AS a
WHERE a.[is null values] = 0
Matt Farguson
la source
14

Il existe des correspondances de motifs de base disponibles via l'utilisation de LIKE, où% correspond à n'importe quel nombre et combinaison de caractères, _ correspond à n'importe quel caractère et [abc] peut correspondre à a, b ou c ... Il y a plus d'informations sur le site MSDN .

Steven Murawski
la source
5

Si vous utilisez SQL Server 2016 ou version ultérieure, vous pouvez utiliser sp_execute_external_scriptavec R. Il a des fonctions pour les recherches d'expressions régulières, telles que grepet grepl.

Voici un exemple d'adresses e-mail. Je vais interroger certaines «personnes» via le moteur de base de données SQL Server, transmettre les données de ces personnes à R, laisser R décider quelles personnes ont des adresses électroniques non valides et demander à R de renvoyer ce sous-ensemble de personnes à SQL Server. Les «personnes» proviennent de la [Application].[People]table de la [WideWorldImporters]base de données exemple. Ils sont transmis au moteur R en tant que dataframe nommé InputDataSet. R utilise la fonction grepl avec l'opérateur "not" (point d'exclamation!) Pour trouver quelles personnes ont des adresses e-mail qui ne correspondent pas au modèle de recherche de chaîne RegEx.

EXEC sp_execute_external_script 
 @language = N'R',
 @script = N' RegexWithR <- InputDataSet;
OutputDataSet <- RegexWithR[!grepl("([_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,4}))", RegexWithR$EmailAddress), ];',
 @input_data_1 = N'SELECT PersonID, FullName, EmailAddress FROM Application.People'
 WITH RESULT SETS (([PersonID] INT, [FullName] NVARCHAR(50), [EmailAddress] NVARCHAR(256)))

Notez que les fonctionnalités appropriées doivent être installées sur l'hôte SQL Server. Pour SQL Server 2016, il s'appelle «Services SQL Server R». Pour SQL Server 2017, il a été renommé «SQL Server Machine Learning Services».

Conclusion L'implémentation de SQL par Microsoft (T-SQL) n'a pas de support natif pour RegEx. Cette solution proposée peut ne pas être plus souhaitable pour l'OP que l'utilisation d'une procédure stockée CLR. Mais cela offre un moyen supplémentaire d'aborder le problème.

Dave Mason
la source
4

Au cas où quelqu'un d'autre se pencherait encore sur cette question, http://www.sqlsharp.com/ est un moyen gratuit et facile d'ajouter des fonctions d' expressions régulières CLR dans votre base de données.

John Fisher
la source
3
Encore une fois, c'est une solution CLR - pas ce que l'OP a demandé
Ingénieur inversé
10
@DaveBoltman: Il a posé la question en 2008. Les gens recherchent parfois cela et se heurtent à cette question sans vouloir éviter le CLR. Cela m'a aidé et pourrait les aider.
John Fisher
Bien sûr, je suis d' accord avec vous @JohnFisher - il est une réponse utile pour quelqu'un en utilisant CLR. Mais en 2015, nous aimerions toujours une solution SQL uniquement dans notre projet SQL (pas de CLR) pour diverses raisons, tout comme l'OP l'a fait en 2008. L'année n'a pas d'importance :) Par exemple, la batterie de votre voiture est sortie en 1859 . Mais vous aimeriez quand même éviter d'utiliser des batteries plus modernes telles que les batteries NiMH commercialisées plus de 100 ans plus tard, pour diverses raisons (comme avoir les moyens d'acheter une voiture du tout :)
Ingénieur inversé
2
@DaveBoltman: Vous avez manqué la partie où «les gens recherchent parfois cela et rencontrent cette question sans vouloir éviter le CLR». C'était le point clé.
John Fisher
bien sûr - vous avez raison @JohnFisher, vous avez dit cela. Heureux que cela vous ait aidé, et je suis sûr que cela aidera les autres aussi
Ingénieur inversé
2

Vous pouvez utiliser les fonctionnalités d'expression régulière VBScript à l'aide d'OLE Automation. C'est bien mieux que la surcharge de création et de maintenance d'un assemblage. Veuillez vous assurer de parcourir la section des commentaires pour obtenir une version mieux modifiée de la version principale.

http://blogs.msdn.com/b/khen1234/archive/2005/05/11/416392.aspx

DECLARE @obj INT, @res INT, @match BIT;
DECLARE @pattern varchar(255) = '<your regex pattern goes here>';
DECLARE @matchstring varchar(8000) = '<string to search goes here>';
SET @match = 0;

-- Create a VB script component object
EXEC @res = sp_OACreate 'VBScript.RegExp', @obj OUT;

-- Apply/set the pattern to the RegEx object
EXEC @res = sp_OASetProperty @obj, 'Pattern', @pattern;

-- Set any other settings/properties here
EXEC @res = sp_OASetProperty @obj, 'IgnoreCase', 1;

-- Call the method 'Test' to find a match
EXEC @res = sp_OAMethod @obj, 'Test', @match OUT, @matchstring;

-- Don't forget to clean-up
EXEC @res = sp_OADestroy @obj;

Si vous obtenez une SQL Server blocked access to procedure 'sys.sp_OACreate'...erreur, utilisez sp_reconfigurepour activer Ole Automation Procedures. (Oui, malheureusement, c'est un changement au niveau du serveur!)

Plus d'informations sur la Testméthode sont disponibles ici

Bon codage

James Poulose
la source
désolé, je sais que c'est vieux, MAIS: Pourquoi VBScript via OLE est-il "bien meilleur" que CLR? Si vous pensez UNIQUEMENT à la maintenance, vous POUVEZ avoir raison, MAIS qu'en est-il des performances?
swe
1
@swe Par «bien mieux», je faisais référence au temps gagné en raison de la surcharge de création et de maintenance d'un assemblage .NET juste à cette fin.
James Poulose