Delen via


Zelfstudie: Zoeken naar een tekenreeks met behulp van reguliere expressies (regex) in C#

Van toepassing op: SQL Server 2019 (15.x) en latere versies

In deze zelfstudie leert u hoe u SQL Server Language Extensions gebruikt om een C#-klasse te maken die twee kolommen (id en tekst) van SQL Server en een reguliere expressie (regex) ontvangt als invoerparameter. De klasse retourneert twee kolommen terug naar SQL Server (id en tekst).

Voor een bepaalde tekst in de tekstkolom die naar de C#-klasse wordt verzonden, controleert de code of aan de opgegeven reguliere expressie is voldaan en wordt die tekst samen met de oorspronkelijke id geretourneerd.

Deze voorbeeldcode maakt gebruik van een reguliere expressie die controleert of een tekst het woord C# bevat of c#.

Vereiste voorwaarden

Compilatie van opdrachtregels is dotnet build voldoende voor deze zelfstudie.

Voorbeeldgegevens maken

Maak eerst een nieuwe database en vul een testdata tabel met ID en text kolommen.

CREATE DATABASE csharptest;
GO

USE csharptest;
GO

CREATE TABLE testdata
(
    [id] INT,
    [text] VARCHAR (100)
);
GO

INSERT INTO testdata (id, "text") VALUES (4, 'This sentence contains C#');
INSERT INTO testdata (id, "text") VALUES (1, 'This sentence does not');
INSERT INTO testdata (id, "text") VALUES (3, 'I love c#!');
INSERT INTO testdata (id, "text") VALUES (2, NULL);
GO

De hoofdklasse maken

In deze stap maakt u een klassebestand met de naam RegexSample.cs en kopieert u de volgende C#-code naar dat bestand.

Deze hoofdklasse importeert de SDK, wat betekent dat het C#-bestand dat in de eerste stap is gedownload, kan worden gedetecteerd vanuit deze klasse.

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using Microsoft.Data.Analysis;
using Microsoft.SqlServer.CSharpExtension.SDK;
using System.Text.RegularExpressions;

namespace UserExecutor
{
    /// <summary>
    /// This class extends the AbstractSqlServerExtensionExecutor and uses
    /// a regular expression that checks if a text contains the word "C#" or "c#"
    /// </summary>
    public class CSharpRegexExecutor: AbstractSqlServerExtensionExecutor
    {
        /// <summary>
        /// This method overrides the Execute method from AbstractSqlServerExtensionExecutor.
        /// </summary>
        /// <param name="input">
        /// A C# DataFrame contains the input dataset.
        /// </param>
        /// <param name="sqlParams">
        /// A Dictionary contains the parameters from SQL server with name as the key.
        /// </param>
        /// <returns>
        /// A C# DataFrame contains the output dataset.
        /// </returns>
        public override DataFrame Execute(DataFrame input, Dictionary<string, dynamic> sqlParams){
            // Drop NULL values and sort by id
            //
            input = input.DropNulls().OrderBy("id");

            // Create empty output DataFrame with two columns
            //
            DataFrame output = new DataFrame(new PrimitiveDataFrameColumn<int>("id", 0), new StringDataFrameColumn("text", 0));

            // Filter text containing specific substring using regex expression
            //
            DataFrameColumn texts = input.Columns["text"];
            for(int i = 0; i < texts.Length; ++i)
            {
                if(Regex.IsMatch((string)texts[i], sqlParams["@regexExpr"]))
                {
                    output.Append(input.Rows[i], true);
                }
            }

            // Modify the parameters
            //
            sqlParams["@rowsCount"]  = output.Rows.Count;
            sqlParams["@regexExpr"] = "Success!";

            // Return output dataset as a DataFrame
            //
            return output;
        }
    }
}

Een DLL-bestand compileren en maken

Verpakt uw klassen en afhankelijkheden in een DLL. U kunt een .csproj bestand maken met de naam RegexSample.csproj en de volgende code naar dat bestand kopiëren.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <EnableDynamicLoading>true</EnableDynamicLoading>
  </PropertyGroup>
  <PropertyGroup>
    <OutputPath>$(BinRoot)/$(Configuration)/</OutputPath>
    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Data.Analysis" Version="0.4.0" />
  </ItemGroup>
  <ItemGroup>
    <Reference Include="Microsoft.SqlServer.CSharpExtension.SDK">
      <HintPath>[path]\Microsoft.SqlServer.CSharpExtension.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>

Ga naar de projectmap en voer het uit, waarmee het volgende bestand wordt gegenereerd dotnet build:

path\to\project\bin\Debug\RegexSample.dll

Zie Een .NET DLL maken op basis van een C#-project voor meer informatie.

Externe taal maken

U moet een externe taal maken in de database. De externe taal is een database-scoped object, wat betekent dat externe talen zoals C# moeten worden gemaakt voor elke database waarin u deze wilt gebruiken.

  1. Maak een .zip bestand met de extensie.

    Als onderdeel van de INSTALLATIE van SQL Server in Windows wordt het .NET-extensiebestand .zip op deze locatie geïnstalleerd: <SQL Server install path>\MSSQL\Binn>\dotnet-core-CSharp-lang-extension.zip. Dit ZIP-bestand bevat de nativecsharpextension.dll.

  2. Maak een externe taal dotnet op basis van het .zip bestand:

    CREATE EXTERNAL LANGUAGE [dotnet]
    FROM (
        CONTENT = N'<path>\dotnet-core-CSharp-lang-extension.zip',
        FILE_NAME = 'nativecsharpextension.dll'
    );
    GO
    

Machtigingen instellen

Als u .NET C#-code wilt uitvoeren, moet de gebruiker SID S-1-15-2-1 (<LocalMachineName>\ALL APPLICATION PACKAGES) leesmachtigingen voor de \MSSQL map krijgen.

  1. Klik met de rechtermuisknop op de map en kies Eigenschappenbeveiliging>
  2. Bewerken selecteren
  3. Selecteer Toevoegen
  4. Selecteer gebruikers, computers, serviceaccounts of groepen:
    1. Objecttypen selecteren en ervoor zorgen dat ingebouwde beveiligingsprincipes en groepen zijn geselecteerd
    2. Selecteer Locaties om de naam van de lokale computer boven aan de lijst te selecteren
    3. Voer in ALL APPLICATION PACKAGES, controleer de naam en selecteer OK om toe te voegen. Als de naam niet wordt omgezet, gaat u opnieuw naar de stap Locaties . De systeem-id (SID) is lokaal op uw computer.

Zie CREATE EXTERNAL LANGUAGE voor meer informatie.

Externe bibliotheken maken

Gebruik CREATE EXTERNAL LIBRARY om een externe bibliotheek te maken voor uw DLL-bestanden. SQL Server heeft toegang tot de .dll bestanden en u hoeft geen speciale machtigingen in te stellen op de classpath.

Maak een externe bibliotheek voor de RegEx-code.

CREATE EXTERNAL LIBRARY [regex.dll]
FROM (CONTENT = N'<path>\RegexSample.dll')
WITH (LANGUAGE = 'Dotnet');
GO

De C#-klasse aanroepen

Roep de opgeslagen procedure sp_execute_external_script aan om de C#-code aan te roepen vanuit SQL Server. Definieer in de scriptparameter welke libraryname;namespace.classname u wilt aanroepen. U kunt ook definiëren welke namespace.classname u wilt aanroepen zonder de naam van de bibliotheek op te geven. De extensie vindt de eerste bibliotheek met de overeenkomende namespace.classnamebibliotheek. In de volgende code behoort de klasse tot een naamruimte die wordt aangeroepen UserExecutor en een klasse met de naam CSharpRegexExecutor.

De code definieert niet welke methode moet worden aangeroepen. Standaard wordt de Execute methode aangeroepen. Dit betekent dat u de SDK-interface moet volgen en een Execute methode in uw C#-klasse moet implementeren als u de klasse vanuit SQL Server wilt kunnen aanroepen.

De opgeslagen procedure gebruikt een invoerquery (invoergegevensset) en een reguliere expressie en retourneert de rijen die aan de opgegeven reguliere expressie hebben voldaan. Er wordt een reguliere expressie [Cc]# gebruikt die controleert of een tekst het woord c#C# of .

DECLARE @rowsCount AS INT;
DECLARE @regexExpr AS VARCHAR (200);

SET @regexExpr = N'[Cc]#';

EXECUTE sp_execute_external_script
    @language = N'dotnet',
    @script = N'regex.dll;UserExecutor.CSharpRegexExecutor',
    @input_data_1 = N'SELECT * FROM testdata',
    @params = N'@regexExpr VARCHAR(200) OUTPUT, @rowsCount INT OUTPUT',
    @regexExpr = @regexExpr OUTPUT,
    @rowsCount = @rowsCount OUTPUT
    WITH RESULT SETS
(
        (id INT, TEXT VARCHAR (100))
);

SELECT @rowsCount AS rowsCount, @regexExpr AS message;

Results

Nadat de aanroep is uitgevoerd, krijgt u een resultatenset met twee van de rijen.

Schermopname van de resultaten van het C#-voorbeeld.