惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

I
InfoQ
G
Google Developers Blog
Engineering at Meta
Engineering at Meta
月光博客
月光博客
博客园 - 聂微东
博客园 - Franky
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
有赞技术团队
有赞技术团队
A
About on SuperTechFans
Microsoft Azure Blog
Microsoft Azure Blog
Blog — PlanetScale
Blog — PlanetScale
U
Unit 42
T
Tailwind CSS Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
云风的 BLOG
云风的 BLOG
S
SegmentFault 最新的问题
F
Fortinet All Blogs
H
Help Net Security
J
Java Code Geeks
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 叶小钗
L
LangChain Blog
Martin Fowler
Martin Fowler
N
Netflix TechBlog - Medium

博客园 - eyye的眼睛

又到清明节 sql中去除重复的项 戒烟吧 李开复:如何设计你的2015年度计划 网易邮箱已经忘记了客户 从天气网提取气象预报数据 sql 几点记录 sql 重复数据只保留一条 (转)android-sdk_r20.0.3-windows无法正常更新 RichTextBox的拖放功能DragDrop 合并两个rtf文件 杀掉叽哩瓜叽(jlguaji.exe)的两种方法 股票数据(转) word转化为图片(2) 如何将格式文本转化为图片 SQL Server 的事务处理的两种格式 sql IN语句如何优化?(转) 向EXCEL批量导出数据(转) 禅语
用程序集编写clr表值函数:把正则表达式引入数据库中
eyye的眼睛 · 2014-06-25 · via 博客园 - eyye的眼睛

正则表达式非常好,但在数据库中就是没有,但可以通过程序集方式扩展

先编写一个dll,标量函数很好写,表值函数麻烦一点

下面是C#代码

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text.RegularExpressions;
using System.Collections;
public partial class RegExpFunctions
{

    [SqlFunction(
      DataAccess = DataAccessKind.Read,
      FillRowMethodName = "MatchsFun_FillRow",
      TableDefinition = "pos int,match NVARCHAR(500)")]
    public static IEnumerable MatchsFun(string input, string patten)
    {
      MatchCollection mc;
      Regex r = new Regex(patten);
      mc = r.Matches(input);
      return mc;
    }


    public static void MatchsFun_FillRow(object mc,out int pos,out SqlString sqlmatch)
    {
      Match it = (Match)mc;
      pos = it.Index;
      sqlmatch = it.Value;
    }

};

程序集名称是RegulerExp2

代码中有几点解释一下:

(1)表值函数必须是IEnumerable,简单讲是必须有这个接口的类,MatchCollection就具有这个接口;

(2)必须提供一个回调函数,在函数属性FillRowMethodName = "MatchsFun_FillRow"中指明,这个函数负责填充数据,

    public static void MatchsFun_FillRow(object mc,out int pos,out SqlString sqlmatch)
    {
      Match it = (Match)mc;
      pos = it.Index;
      sqlmatch = it.Value;
    }

这里的object mc是什么呢?

我们可以想象一下遍历

foreach (Match it in mc)
{  
}

这里的object mc就是foreach里的Match it。

然后数据库把out int pos,out SqlString sqlmatch这两个量取出去放进表里。

下一步是添加程序集

第一步是把数据库的clr打开,不细说,自己网上查

第二步添加程序集

第三步,写一个数据库表值函数包装

create FUNCTION [dbo].[MatchList](@input [nvarchar](1000), @patten [nvarchar](1000))
RETURNS  TABLE (
    pos int,[match] [nvarchar](500) NULL
) WITH EXECUTE AS CALLER
AS 
EXTERNAL NAME [RegulerExp2].[RegExpFunctions].[MatchsFun]

可以了。

前面写了一个小示例,大家好像没兴趣,写一个实用点的例子吧。数据库中没有split函数,用正则表达式就很容易了

select match from dbo.MatchList('1,2,4,12,24,41','(?<=,|^).*?(?=,|$)')

结果为

如果以一个存储过程方式

C#代码为

[Microsoft.SqlServer.Server.SqlProcedure]
    public static void Matches(string input, string patten)
    {
        //像构造Table一样来构造SqlDataRecord,其中SqlMetaData类似DataColumn
        SqlDataRecord dataRecord = new SqlDataRecord(new SqlMetaData[] {                
                new SqlMetaData("ID", SqlDbType.Int),
                new SqlMetaData("index", SqlDbType.Int),
                new SqlMetaData("match", SqlDbType.NVarChar,100)
                    });
        //开始填充
        SqlContext.Pipe.SendResultsStart(dataRecord);

        MatchCollection mc;
        Regex r = new Regex(patten);
        mc = r.Matches(input);
        for (int i = 0; i < mc.Count; i++)
        {            
            //SqlDataRecord.SetString类似DataRow的功能,像Table中填充值
            dataRecord.SetInt32(0, i);
            dataRecord.SetInt32(1, mc[i].Index);
            dataRecord.SetString(2,  mc[i].Value);
            //通过SendResultsRow把数据填充到Table,相关于Table.Rows.Add(DataRow);
            SqlContext.Pipe.SendResultsRow(dataRecord);
        }

        
        //填充结束,返回结果集
        SqlContext.Pipe.SendResultsEnd();
    }

数据库端写一个存储过程包装

CREATE PROCEDURE [dbo].[Macths]
    @input [nvarchar](1000),
    @patten [nvarchar](1000)
WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [RegulerExp].[RegulerExp].[Matches]

别的一样

运行

exec dbo.Macths '1,2,4,12,24,41','(?<=,|^).*?(?=,|$)'

结果为

其他标量函数很简单,自己百度,类似