Expressões regulares do SQL Server em T-SQL

127

Existe alguma biblioteca de expressão regular escrita em T-SQL (sem CLR, sem SPT-SQL estendido e puro) para SQL Server e que funcione com hospedagem compartilhada?

Editar:

  • Obrigado, eu sei sobre PATINDEX, LIKE, xp_ spse soluções CLR
  • Eu também sei que não é o melhor lugar para regex, a questão é teórica :)
  • Funcionalidade reduzida também é aceita
xnagyg
fonte
2
Eu também tenho essa pergunta. Eu sei que um banco de dados não é o melhor lugar para fazer isso, mas a realidade é que outras soluções exigem permissões de administrador do SQL para reconfigurar o servidor. Infelizmente, alguns de nossos clientes não optam por ativar o CLR, etc., e estamos presos a soluções somente de banco de dados.
Paul Draper
@PaulDraper e xnagyg: por que descartar o SQLCLR? É o meio mais apropriado de obter expressões regulares em consultas. E por que alguns de seus clientes optam por não ativar o CLR? Ainda não encontrei um motivo válido . Claro, ouço "segurança" e "desempenho", mas esses são motivos falsos resultantes de não entendermos como o SQLCLR funciona e como ele pode ser restringido.
Solomon Rutzky
3
@srutzky: a maioria dos provedores de hospedagem compartilhada não permite CLR. Você deve perguntar-lhes sobre "segurança" e "performance" :)
xnagyg
@xnagyg Claro, posso pedir alguns. No entanto, apontar para o comportamento de um grupo não aborda de forma alguma a questão de "existe uma razão válida " para esse comportamento. Com a mesma facilidade, todos os provedores de hospedagem compartilhada definem sua política com base no mesmo mal-entendido. E, se nada mais, o simples fato de que nem todos eles desaprovam o SQLCLR realmente apóia a idéia de que não há um problema mais do que a ideia de que existe um problema, pois, se esses problemas existissem, os provedores que permitem o SQLCLR estariam enfrentando esses problemas e deixaria de permitir.
Solomon Rutzky,
@xnagyg Além disso, devo esclarecer que estou falando em termos de assemblies marcados como SAFEe não marcados como um EXTERNAL_ACCESSou outro UNSAFE(como eu entendo por que esses dois últimos conjuntos de permissões seriam problemáticos para um ambiente de hospedagem compartilhada). O Banco de Dados SQL do Microsoft Azure V12 (ou seja, a nova versão a partir do final de 2014), que é um ambiente compartilhado, permite Assemblies marcados como SAFE(e carregados por meio FROM 0x...de uma DLL, pois não é possível carregar uma DLL). Mas SAFEé tudo o que é necessário para expressões regulares e muitas outras funções muito úteis.
Solomon Rutzky

Respostas:

77

E a função PATINDEX ?

A correspondência de padrões no TSQL não é uma biblioteca completa de expressões regulares, mas fornece o básico.

(De livros on-line)

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
fonte
7
Por pelo menos uma década (SQL Server 2005+), LIKEoferece suporte a tudo o que PATINDEXfaz. Não sei sobre antes disso ...
TJ Crowder
1
No entanto, isso não me permite especificar um padrão que corresponda, digamos, a um número variável de letras ascii. %corresponde a 0 ou mais caracteres (independentemente), [...]corresponde a apenas um e não há nada no meio.
Martijn Pieters
LIKE é o mesmo que PATINDEX> 0
Engineer
21

Se alguém estiver interessado em usar regex com CLR, aqui está uma solução. A função abaixo (C # .net 4.5) retorna 1 se o padrão for correspondido e 0 se o padrão não for correspondido. Eu o uso para marcar linhas em subconsultas. O atributo SQLfunction informa ao sql server que esse método é o UDF real que o SQL server usará. Salve o arquivo como uma DLL em um local onde você possa acessá-lo no Management Studio.

// 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;
        }
    }
}

No management studio, importe o arquivo dll via programabilidade - assemblies - new assembly

Em seguida, execute esta consulta:

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

Então você deve ter acesso completo à função através do banco de dados em que armazenou o assembly.

Em seguida, use em consultas como:

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
fonte
14

Existe alguma correspondência básica de padrões disponível através do uso de LIKE, onde% corresponde a qualquer número e combinação de caracteres, _ corresponde a qualquer caractere e [abc] pode corresponder a, b ou c ... Há mais informações no site do MSDN .

Steven Murawski
fonte
5

Se você estiver usando o SQL Server 2016 ou superior, poderá usar sp_execute_external_scriptjunto com o R. Ele possui funções para pesquisas de Expressão Regular, como grepe grepl.

Aqui está um exemplo para endereços de email. Vou consultar algumas "pessoas" por meio do mecanismo de banco de dados do SQL Server, passar os dados para essas pessoas para R, deixar R decidir quais pessoas têm endereços de email inválidos e fazer com que R repasse esse subconjunto de pessoas para o SQL Server. As "pessoas" são da [Application].[People]tabela no [WideWorldImporters]banco de dados de exemplo. Eles são passados ​​para o mecanismo R como um dataframe nomeado InputDataSet. R usa a função grepl com o operador "not" (ponto de exclamação!) Para descobrir quais pessoas têm endereços de email que não correspondem ao padrão de pesquisa de cadeia de caracteres 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)))

Observe que os recursos apropriados devem ser instalados no host do SQL Server. Para o SQL Server 2016, ele é chamado de "SQL Server R Services". Para o SQL Server 2017, ele foi renomeado para "SQL Server Machine Learning Services".

Considerações finais A implementação do SQL (T-SQL) da Microsoft não tem suporte nativo para o RegEx. Essa solução proposta pode não ser mais desejável para o OP do que o uso de um procedimento armazenado CLR. Mas oferece uma maneira adicional de abordar o problema.

Dave Mason
fonte
4

Caso outra pessoa ainda esteja estudando essa questão, http://www.sqlsharp.com/ é uma maneira fácil e gratuita de adicionar funções CLR de expressão regular ao seu banco de dados.

John Fisher
fonte
3
Mais uma vez, é uma solução de CLR - e não o que o OP solicitou
Reversed Engineer
10
@DaveBoltman: Ele fez a pergunta em 2008. As pessoas pesquisam isso algumas vezes e se deparam com essa questão sem querer evitar o CLR. Isso me ajudou e pode ajudá-los.
31515 John John Fisher
Claro, concordo com você @JohnFisher - é uma resposta útil para alguém que usa o CLR. Mas em 2015, ainda gostaríamos de uma solução apenas SQL em nosso projeto SQL (sem CLR) por vários motivos, assim como o OP em 2008. O ano não importa :) Por exemplo, a bateria do seu carro foi lançada em 1859 . Mas você ainda gostaria de evitar o uso de baterias mais modernas, como as baterias de NiMH, lançadas mais de 100 anos depois, por vários motivos (como poder comprar um carro): #
Engenheiro
2
@ DaveBoltman: Você perdeu a parte em que "as pessoas pesquisam isso às vezes e se deparam com essa questão sem querer evitar o CLR". Esse foi o ponto chave.
John Fisher
com certeza - você está certo @ JohnFisher, você disse isso. Ainda bem que ajudou você, e tenho certeza que também ajudará os outros #
3300 Reversed Engineer
2

Você pode usar os recursos de expressão regular do VBScript usando a automação OLE. Isso é muito melhor do que a sobrecarga de criar e manter uma montagem. Por favor, verifique a seção de comentários para obter uma versão melhorada da versão principal.

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;

Se você receber um SQL Server blocked access to procedure 'sys.sp_OACreate'...erro, use sp_reconfigurepara ativar Ole Automation Procedures. (Sim, infelizmente, isso é uma alteração no nível do servidor!)

Mais informações sobre o Testmétodo estão disponíveis aqui

Feliz codificação

James Poulose
fonte
sry, eu sei que isso é antigo, MAS: Por que o VBScript através do OLE "é muito melhor" que o CLR? Se você só pensa em manutenção, você pode estar certo, mas e em desempenho?
19716
1
@swe Por 'maneira melhor', eu estava me referindo ao tempo economizado devido à sobrecarga de criação e manutenção de um assembly .NET apenas para esse fim.
21416 James Poulose