Регулярные выражения SQL Server в T-SQL

127

Есть ли библиотека регулярных выражений, написанная на T-SQL (без CLR, без расширенного SP, чистого T-SQL) для SQL Server, и которая должна работать с общим хостингом?

Редактировать:

  • Спасибо, я знаю о том PATINDEX, LIKE, xp_ spsи решения CLR
  • Я также знаю, что это не лучшее место для регулярного выражения, вопрос теоретический :)
  • Допускается также ограниченная функциональность
xnagyg
источник
2
У меня тоже есть этот вопрос. Я знаю, что база данных - не лучшее место для этого, но реальность такова, что для других решений требуются разрешения администратора SQL для перенастройки сервера. К сожалению, некоторые из наших клиентов не захотят включить CLR и т. Д., И мы придерживаемся решений только для баз данных.
Paul Draper
@PaulDraper и xnagyg: почему исключают SQLCLR? Это наиболее подходящий способ получения регулярных выражений в запросах. И почему некоторые из ваших клиентов решили не включать CLR? Я еще не нашел веской причины. Конечно, я слышу «безопасность» и «производительность», но это ложные причины, которые являются результатом непонимания того, как работает SQLCLR и как его можно ограничить.
Соломон Рутцки
3
@srutzky: большинство провайдеров виртуального хостинга не разрешают CLR. Вы должны спросить их о «безопасности» и «производительности» :)
xnagyg
@xnagyg Конечно, я могу спросить несколько. Однако, указывая на поведение группы не в коей мере не рассматривается вопрос «есть ли действительный повод» для такого поведения. Так же легко могло случиться, что все эти провайдеры виртуального хостинга установили свою политику, основываясь на одном и том же недоразумении. И, по крайней мере , тот простой факт, что не все из них запрещают SQLCLR, на самом деле поддерживает идею об отсутствии проблемы больше, чем идею о наличии проблемы, поскольку, если бы эти проблемы действительно существовали, поставщики, разрешающие SQLCLR, столкнулись бы с эти проблемы и перестанут позволять это.
Соломон Рутцки
@xnagyg Кроме того, я должен уточнить, что я говорю в терминах сборок, отмеченных как SAFEи не отмеченных как либо EXTERNAL_ACCESSили UNSAFE(поскольку я понимаю, почему эти два последних набора разрешений будут проблематичными для среды общего хостинга). База данных Microsoft Azure SQL V12 (т.е. новая версия на конец 2014 года), которая является общей средой, позволяет использовать сборки, помеченные как SAFE(и загружаемые через, FROM 0x...а не из DLL, поскольку вы не можете загрузить DLL). Но SAFEэто все, что нужно для регулярных выражений и МНОГО других очень полезных функций.
Соломон Рутцки

Ответы:

78

Как насчет функции PATINDEX ?

Сопоставление с образцом в TSQL - это не полная библиотека регулярных выражений, но она дает вам основы.

(Из электронной книги)

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]).
Эрик Зи Берд
источник
7
По крайней мере, десять лет (SQL Server 2005+) LIKEподдерживал все, что PATINDEXесть. Не знаю до этого ...
TJ Crowder
1
Однако это не позволяет мне указать шаблон, который соответствует, скажем, переменному количеству букв ascii. %соответствует 0 или более символам (независимо), [...]соответствует только одному, и между ними ничего нет.
Мартейн Питерс
LIKE - это то же самое, что и PATINDEX> 0
Reversed Engineer
21

Если кто-то заинтересован в использовании регулярного выражения с CLR, вот решение. Функция ниже (C # .net 4.5) возвращает 1, если шаблон совпадает, и 0, если шаблон не совпадает. Я использую его для пометки строк в подзапросах. Атрибут SQLfunction сообщает серверу sql, что этот метод является фактической UDF, которую будет использовать сервер SQL. Сохраните файл как dll в том месте, где вы можете получить к нему доступ из студии управления.

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

В студии управления импортируйте файл dll через программируемость - сборки - новая сборка

Затем запустите этот запрос:

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

Тогда у вас должен быть полный доступ к функции через базу данных, в которой вы сохранили сборку.

Затем используйте в таких запросах:

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
Мэтт Фаргюсон
источник
14

Существует некоторое базовое сопоставление с образцом, доступное с использованием LIKE, где% соответствует любому количеству и комбинации символов, _ соответствует любому одному символу, а [abc] может соответствовать a, b или c ... Дополнительная информация доступна на сайте MSDN ,

Стивен Муравски
источник
5

Если вы используете SQL Server 2016 или более поздней версии, вы можете использовать sp_execute_external_scriptвместе с R. В нем есть функции для поиска по регулярным выражениям, такие как grepи grepl.

Вот пример адресов электронной почты. Я опрашиваю некоторых «людей» через ядро ​​базы данных SQL Server, передаю данные об этих людях в R, позволяю R решать, какие люди имеют недопустимые адреса электронной почты, и заставляю R передавать это подмножество людей в SQL Server. «Люди» взяты из [Application].[People]таблицы в [WideWorldImporters]образце базы данных. Они передаются механизму R как фрейм данных с именем InputDataSet. R использует функцию grepl с оператором «not» (восклицательный знак!), Чтобы найти людей, адреса электронной почты которых не соответствуют шаблону поиска строки 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)))

Обратите внимание, что соответствующие функции должны быть установлены на узле SQL Server. Для SQL Server 2016 это называется «Службы SQL Server R». Для SQL Server 2017 он был переименован в «Службы машинного обучения SQL Server».

Заключение В реализации Microsoft SQL (T-SQL) нет встроенной поддержки RegEx. Это предлагаемое решение может быть не более желательным для OP, чем использование хранимой процедуры CLR. Но он предлагает дополнительный способ подойти к проблеме.

Дэйв Мейсон
источник
4

На тот случай, если кто-то еще изучает этот вопрос, http://www.sqlsharp.com/ - это бесплатный и простой способ добавить функции CLR регулярных выражений в вашу базу данных.

Джон Фишер
источник
3
Еще раз, я - решение CLR, а не то, о чем просил OP,
Reversed Engineer
10
@DaveBoltman: Он задал вопрос в 2008 году. Люди иногда ищут это и сталкиваются с этим вопросом, не желая избежать CLR. Это помогло мне и может помочь им.
Джон Фишер,
Конечно, я согласен с вами @JohnFisher - это является полезным ответом для кого - то с помощью CLR. Но в 2015 году мы по-прежнему хотели бы, чтобы в нашем проекте SQL (без CLR) было решение только для SQL, как и OP в 2008 году. Год не имеет значения :) Например, аккумулятор в вашей машине был выпущен в 1859 . Но вы все же не хотели бы использовать более современные батареи, такие как NiMH батареи, выпущенные более 100 лет спустя, по разным причинам (например, из-за того, что вы вообще можете позволить себе машину :)
Reversed Engineer
2
@DaveBoltman: Вы пропустили ту часть, где «Люди иногда ищут это и сталкиваются с этим вопросом, не желая избегать CLR». Это был ключевой момент.
Джон Фишер
конечно - ты прав @JohnFisher, ты это сказал. Рад, что это помогло вам, и я уверен, что это поможет и другим
Reversed Engineer
2

Вы можете использовать функции регулярных выражений VBScript с помощью OLE Automation. Это намного лучше, чем накладные расходы на создание и обслуживание сборки. Пожалуйста, не забудьте просмотреть раздел комментариев, чтобы получить лучшую модифицированную версию основной.

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;

Если вы получили SQL Server blocked access to procedure 'sys.sp_OACreate'...ошибку, используйте sp_reconfigureдля включения Ole Automation Procedures. (Да, к сожалению, это изменение уровня сервера!)

Более подробная информация о Testметоде доступна здесь.

Удачного кодирования

Джеймс Пулозе
источник
Извините, я знаю, что это устарело, НО: Почему VBScript через OLE «намного лучше», чем CLR? Если вы думаете ТОЛЬКО об обслуживании, вы МОГУТ быть правы, НО как насчет производительности?
swe
1
@swe К слову «лучше», я имел в виду время, сэкономленное из-за накладных расходов на создание и поддержку сборки .NET только для этой цели.
Джеймс Пулозе,