นิพจน์ทั่วไปของเซิร์ฟเวอร์ SQL ใน T-SQL


127

มีไลบรารีนิพจน์ทั่วไปที่เขียนด้วย T-SQL (ไม่มี CLR ไม่มีส่วนขยายSPT-SQL บริสุทธิ์) สำหรับ SQL Server และควรใช้กับโฮสติ้งที่ใช้ร่วมกันได้หรือไม่

แก้ไข:

  • ขอบคุณฉันรู้เกี่ยวกับPATINDEX, LIKE, xp_ spsและการแก้ปัญหา CLR
  • ฉันยังรู้ว่ามันไม่ใช่สถานที่ที่ดีที่สุดสำหรับ regex คำถามคือทฤษฎี :)
  • นอกจากนี้ยังยอมรับฟังก์ชันการทำงานที่ลดลง

2
ฉันก็มีคำถามนี้เช่นกัน ฉันรู้ว่าฐานข้อมูลไม่ใช่สถานที่ที่ดีที่สุดที่จะมีสิ่งนี้ แต่ความจริงก็คือโซลูชันอื่น ๆ ต้องการสิทธิ์ผู้ดูแลระบบ SQL เพื่อกำหนดค่าเซิร์ฟเวอร์ใหม่ น่าเสียดายที่ลูกค้าของเราบางรายไม่เลือกที่จะเปิดใช้งาน CLR และอื่น ๆ และเราติดอยู่กับโซลูชันฐานข้อมูลเท่านั้น
Paul Draper

@PaulDraper และ xnagyg: ทำไมต้องออกกฎ SQLCLR? เป็นวิธีที่เหมาะสมที่สุดในการรับนิพจน์ทั่วไปในแบบสอบถาม แล้วทำไมลูกค้าของคุณบางคนถึงเลือกที่จะไม่เปิดใช้งาน CLR? ฉันยังไม่พบเหตุผลที่ถูกต้อง แน่นอนว่าฉันได้ยินคำว่า "ความปลอดภัย" และ "ประสิทธิภาพ" แต่นั่นเป็นสาเหตุปลอมซึ่งเป็นผลมาจากการไม่เข้าใจว่า SQLCLR ทำงานอย่างไรและสามารถ จำกัด ได้อย่างไร
Solomon Rutzky

3
@srutzky: ผู้ให้บริการโฮสติ้งที่ใช้ร่วมกันส่วนใหญ่ไม่อนุญาตให้ใช้ CLR คุณควรถามพวกเขาเกี่ยวกับ "ความปลอดภัย" และ "ประสิทธิภาพ" :)
xnagyg

@xnagyg แน่นอนฉันขอไม่กี่คนก็ได้ อย่างไรก็ตามการชี้ไปที่พฤติกรรมของกลุ่มไม่ได้ช่วยตอบคำถามที่ว่า "มีเหตุผลที่ถูกต้อง " สำหรับพฤติกรรมนั้น แต่อย่างใด อาจเป็นไปได้อย่างง่ายดายว่าผู้ให้บริการโฮสติ้งที่ใช้ร่วมกันทั้งหมดเหล่านั้นกำหนดนโยบายตามความเข้าใจผิดเดียวกัน และหากไม่มีอะไรอื่นความจริงง่ายๆที่ว่าไม่ใช่ทั้งหมดที่ไม่อนุญาต SQLCLR จริง ๆ แล้วสนับสนุนแนวคิดที่ว่าไม่มีปัญหามากกว่าความคิดที่ว่ามีปัญหาเนื่องจากหากมีปัญหาเหล่านั้นผู้ให้บริการที่อนุญาต SQLCLR จะประสบ ปัญหาเหล่านั้นและจะหยุดปล่อยให้มัน
Solomon Rutzky

@xnagyg นอกจากนี้ฉันควรชี้แจงว่าฉันกำลังพูดในแง่ของแอสเซมบลีที่ถูกทำเครื่องหมายเป็นSAFEและไม่ได้ทำเครื่องหมายเป็นEXTERNAL_ACCESSหรือUNSAFE(ตามที่ฉันเข้าใจว่าเหตุใดชุดการอนุญาต 2 ชุดหลังจึงเป็นปัญหาสำหรับสภาพแวดล้อมการโฮสต์ที่ใช้ร่วมกัน) Microsoft Azure SQL Database V12 (เช่นเวอร์ชันใหม่ปลายปี 2014) ซึ่งเป็นสภาพแวดล้อมที่ใช้ร่วมกันช่วยให้แอสเซมบลีที่ทำเครื่องหมายเป็นSAFE(และโหลดผ่านFROM 0x...แทนจาก DLL เนื่องจากคุณไม่สามารถอัปโหลด DLL ได้) แต่SAFEเป็นสิ่งที่จำเป็นสำหรับนิพจน์ทั่วไปและฟังก์ชันที่มีประโยชน์อื่น ๆ อีกมากมาย
Solomon Rutzky

คำตอบ:


78

วิธีการเกี่ยวกับPATINDEXฟังก์ชั่น?

การจับคู่รูปแบบใน TSQL ไม่ใช่ไลบรารี regex ที่สมบูรณ์ แต่ให้ข้อมูลพื้นฐานแก่คุณ

(จากหนังสือออนไลน์)

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 ตัวขึ้นไป (โดยไม่คำนึงถึง) [...]จับคู่เพียงตัวเดียวและไม่มีอะไรอยู่ระหว่าง
Martijn Pieters

LIKE เหมือนกับ PATINDEX> 0
Reversed Engineer

21

หากใครสนใจใช้ regex กับ 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พร้อมกับอาร์มันมีฟังก์ชั่นสำหรับการค้นหานิพจน์ปกติเช่นและgrepgrepl

นี่คือตัวอย่างสำหรับที่อยู่อีเมล ฉันจะสอบถาม "บุคคล" บางคนผ่านทางเอ็นจินฐานข้อมูล SQL Server ส่งข้อมูลของบุคคลเหล่านั้นไปยัง R ปล่อยให้ R ตัดสินใจว่าบุคคลใดมีที่อยู่อีเมลที่ไม่ถูกต้องและให้ R ส่งกลับบุคคลกลุ่มนั้นไปยัง SQL Server "คน" มาจาก[Application].[People]ตารางใน[WideWorldImporters]ฐานข้อมูลตัวอย่าง พวกเขาได้รับการส่งผ่านไปยังเครื่องยนต์ R เป็น dataframe 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 Services" สำหรับ SQL Server 2017 เปลี่ยนชื่อเป็น "SQL Server Machine Learning Services"

การปิดความคิด การใช้ SQL (T-SQL) ของ Microsoft ไม่มีการสนับสนุนดั้งเดิมสำหรับ RegEx โซลูชันที่นำเสนอนี้อาจไม่เป็นที่ต้องการของ OP มากกว่าการใช้กระบวนงานที่จัดเก็บ CLR แต่จะเสนอวิธีเพิ่มเติมในการแก้ไขปัญหา


4

ในกรณีที่คนอื่นยังคงมองคำถามนี้อยู่http://www.sqlsharp.com/เป็นวิธีที่ง่ายและฟรีในการเพิ่มฟังก์ชัน CLRนิพจน์ทั่วไปลงในฐานข้อมูลของคุณ


3
อีกครั้งฉันไม่ใช่โซลูชัน CLR ไม่ใช่สิ่งที่ OP ขอ
Reversed Engineer

10
@DaveBoltman: เขาถามคำถามนี้ในปี 2008 บางครั้งผู้คนค้นหาสิ่งนี้และพบกับคำถามนี้โดยไม่ต้องการหลีกเลี่ยง CLR สิ่งนี้ช่วยฉันและอาจช่วยพวกเขาได้
John Fisher

แน่นอนว่าผมไม่เห็นด้วยกับคุณ @JohnFisher - มันเป็นคำตอบที่เป็นประโยชน์สำหรับคนที่ใช้ CLR แต่ในปี 2015 เรายังคงต้องการโซลูชัน SQL เพียงอย่างเดียวในโครงการ SQL ของเรา (ไม่มี CLR) ด้วยเหตุผลหลายประการเช่นเดียวกับ OP ในปี 2008 ปีไม่สำคัญ :) เช่นแบตเตอรี่ในรถของคุณได้รับการปล่อยตัวใน 1859 แต่คุณยังคงต้องการหลีกเลี่ยงการใช้แบตเตอรี่ที่ทันสมัยกว่านี้เช่นแบตเตอรี่ NiMH ที่เปิดตัวมากกว่า 100 ปีต่อมาด้วยเหตุผลหลายประการ (เช่นสามารถซื้อรถได้เลย :)
Reversed Engineer

2
@DaveBoltman: คุณพลาดส่วนที่ "บางครั้งผู้คนค้นหาสิ่งนี้และพบกับคำถามนี้โดยไม่ต้องการหลีกเลี่ยง CLR" มันเป็นประเด็นสำคัญ
John Fisher

แน่ใจ - คุณพูดถูก @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 ถ้าคุณคิดเฉพาะเรื่องการบำรุงรักษาคุณก็คิดถูก แต่ประสิทธิภาพล่ะ?
เหงื่อ

1
@swe โดย 'วิธีที่ดีกว่า' ฉันหมายถึงเวลาที่บันทึกไว้เนื่องจากค่าใช้จ่ายในการสร้างและบำรุงรักษาชุดประกอบ. NET เพื่อจุดประสงค์นี้
James Poulose
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.