Sql Server 实现通过正则表达式拆分数据,并分类汇总

需求说明

由于小伙伴们各自提交的爱好字符分隔各有千秋,希望能将大家的爱好进行详细分类,并汇总各类爱好的人数分别有多少。

目标拆解

1、创建临时表和数据

CREATE TABLE #tmp (
	ID INT IDENTITY(1, 1),
	Name NVARCHAR(50),
	Hobby NVARCHAR(100)
)

INSERT INTO #tmp ( Name, Hobby )
VALUES ('小亮', '打篮球')
INSERT INTO #tmp ( Name, Hobby )
VALUES ('小清', '画画、唱歌')
INSERT INTO #tmp ( Name, Hobby )
VALUES ('小舞', '画画 跳舞 书法')
INSERT INTO #tmp ( Name, Hobby )
VALUES ('小华', '跑步/踢足球、唱歌')

2、查看数据结构

Sql Server 实现通过正则表达式拆分数据,并分类汇总

原始数据

3、对数据进行拆分处理,生成明细表

(Tip:由于爱好字段内容包含不规则字符,需要对各类不规则字符替换成统一字符后,才方便通过Split函数进行分隔)

3.1 封装 Split 分隔函数(只需要执行一次即可重复调用)

CREATE FUNCTION [dbo].[SplitString]
(
    @Input NVARCHAR(MAX), --需要split的字符串
    @Separator NVARCHAR(MAX) = ',' --格式化时分隔符,默认分隔符为,
)
RETURNS @TABLE TABLE 
(
    [Id] INT IDENTITY(1, 1),
    [Value] NVARCHAR(MAX)
) 
AS
BEGIN
    DECLARE @Index INT, @Entry NVARCHAR(MAX)
    SET @Index = CHARINDEX(@Separator, @Input)

    WHILE (@Index > 0)
    BEGIN
        SET @Entry = LTRIM(RTRIM(SUBSTRING(@Input, 1, @Index-1)))
        
        IF (@Entry<>'')
        BEGIN
            INSERT INTO @TABLE([Value]) VALUES(@Entry)
        END

        SET @Input = SUBSTRING(@Input, @Index + DATALENGTH(@Separator)/2, LEN(@Input))
        SET @Index = CHARINDEX(@Separator, @Input)
    END
    
    SET @Entry = LTRIM(RTRIM(@Input))
    IF (@Entry<>'')
    BEGIN
		INSERT INTO @TABLE([Value]) VALUES(@Entry)
    END

    RETURN
END

3.2 封装 正则替换 函数(只需要执行一次即可重复调用)

CREATE FUNCTION [dbo].[RegexReplace] (  
    @string VARCHAR(MAX),   --被替换的字符串  
    @pattern VARCHAR(255),  --替换模板  
    @replacestr VARCHAR(255),   --替换后的字符串  
    @IgnoreCase INT = 0 --0区分大小写 1不区分大小写  
)
RETURNS VARCHAR(8000)  
AS   
BEGIN  
    DECLARE @objRegex INT, @retstr VARCHAR(8000)  
    --创建对象  
    EXEC sp_OACreate 'VBScript.RegExp', @objRegex OUT  
    --设置属性  
    EXEC sp_OASetProperty @objRegex, 'Pattern', @pattern  
    EXEC sp_OASetProperty @objRegex, 'IgnoreCase', @IgnoreCase  
    EXEC sp_OASetProperty @objRegex, 'Global', 1  
    --执行  
    EXEC sp_OAMethod @objRegex, 'Replace', @retstr OUT, @string, @replacestr  
    --释放  
    EXECUTE sp_OADestroy @objRegex  
    RETURN @retstr  
END  
GO

--保证正常运行的话,需要将Ole Automation Procedures选项置为1    
EXEC sp_configure 'show advanced options', 1    
RECONFIGURE WITH OVERRIDE   
EXEC sp_configure 'Ole Automation Procedures', 1    
RECONFIGURE WITH OVERRIDE

3.3 通过执行 正则替换函数 查看字符替换效果(统一替换成 | 字符)

DECLARE @RegexStr NVARCHAR(100);
SET @RegexStr = '[\s\p{P}
\r=+$¥<>^`~|,,/\ ;、]';  -- 可能遇到的分隔符都可以放入
SELECT [dbo].[RegexReplace](ISNULL(Hobby, 'NULL'), @RegexStr, '|', 1) FROM #tmp
Sql Server 实现通过正则表达式拆分数据,并分类汇总

正则替换后

3.4 通过执行 Split函数 查看字符分隔成行数据效果

DECLARE @RegexStr NVARCHAR(100), @Hobby NVARCHAR(100);
SET @RegexStr = '[\s\p{P}
\r=+$¥<>^`~|,,/\ ;、]';
SELECT @Hobby = [dbo].[RegexReplace](ISNULL(Hobby, 'NULL'), @RegexStr, '|', 1) FROM #tmp

SELECT t.Value
FROM [dbo].[SplitString](@Hobby, '|') AS t
JOIN #tmp o ON t.ID = o.ID


Sql Server 实现通过正则表达式拆分数据,并分类汇总

分隔后

3.5 创建明细表,对爱好数据进行遍历,通过正则替换拆分后写入

CREATE TABLE #detail (
	ID INT IDENTITY(1, 1),
	tID INT,  --原始临时表主键ID
	Name NVARCHAR(50),
	Hobby NVARCHAR(100)
)

SELECT * INTO #t FROM #tmp

WHILE EXISTS (SELECT 1 FROM #t)
BEGIN
    DECLARE @ID INT, @Name NVARCHAR(50), @Hobby NVARCHAR(100);
	DECLARE @RegexStr NVARCHAR(100);
	
	SET @RegexStr = '[\s\p{P}
\r=+$¥<>^`~|,,/\ ;、]';

	SELECT TOP 1 @ID = ID, @Name = Name, @Hobby = [dbo].[RegexReplace](ISNULL(Hobby, 'NULL'), @RegexStr, '|', 1) FROM #t ORDER BY ID;

	-- 判断是否多个爱好
	IF (PATINDEX('%|%', @Hobby) > 0)
	BEGIN
	    INSERT INTO #detail ( tID, Name, Hobby )
		SELECT @ID, @Name, Value FROM [dbo].[SplitString](@Hobby, '|')
	END
	ELSE
    BEGIN
        INSERT INTO #detail ( tID, Name, Hobby )
        VALUES (@ID, @Name, @Hobby)
    END

	DELETE FROM #t WHERE ID = @ID;
END
DROP TABLE #t

SELECT * FROM #detail
Sql Server 实现通过正则表达式拆分数据,并分类汇总

拆分后明细

4、对明细数据进行汇总,汇总各类爱好的人数

SELECT Hobby, COUNT(*) AS ahCount
FROM #detail
GROUP BY Hobby
ORDER BY COUNT(*) DESC
Sql Server 实现通过正则表达式拆分数据,并分类汇总

分类汇总结果

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章