SQL优化:SQL模拟Split二维数组
文章目录
- 1、需求
- 2、落地
- 3、实现
- 4、总结
1、需求
有一个excel,读取到datatable后,需要通过id,获取name,并替换到excel的对应列。
那么可能查询需求有10行,返回只有9行。
为了替换的1对1匹配,查询和结果的key(行号)一致就很主要了。
2、落地
将
11[A]‘‘AA’’ [T] 22[A]‘‘BB’’ [T] 33[A]‘‘CC’’
// 仿 [{Row:‘11’,Id=‘AA’},{Row:‘22’,Id=‘BB’},{Row:‘33’,Id=‘CC’}]
转换为
(SELECT Top 1 11 as ROW, Name From TableA Where Id=‘AA’) UNION ALL
(SELECT Top 1 22 as ROW, Name From TableA Where Id=‘BB’ ) UNION ALL
(SELECT Top 1 33 as ROW, Name From TableA Where Id=‘CC’ )
不能使用STRING_SPLIT,有点打脑壳。
但是查了要改到前端,所以必须锁定数据和查询的1对1关系。
3、实现
-- =============================================
ALTER FUNCTION [dbo].[F_OptimizeOr]
( @WhereStr NVARCHAR(MAX)
)
RETURNS NVARCHAR(MAX)
AS BeginDECLARE @Delimiter1 NVARCHAR(3)='[A]'DECLARE @Delimiter2 NVARCHAR(3)='[T]'DECLARE @StartIndex INT= 1; -- 子字符串起始索引DECLARE @EndIndex INT; -- 子字符串结束索引DECLARE @Substring NVARCHAR(MAX) -- 提取的子字符串 DECLARE @Result NVARCHAR(MAX)='' --结果DECLARE @DoCount INT= 1 --循环次数 WHILE @StartIndex > 0BEGINIF (@DoCount%2=1)--奇次-- 找到下一个分隔符的位置SET @EndIndex = CHARINDEX(@Delimiter1, @WhereStr, @StartIndex);--[A]到[T]止ELSE SET @EndIndex = CHARINDEX(@Delimiter2, @WhereStr, @StartIndex);--[T]到[A]止-- 如果未找到分隔符,则设置结束位置为字符串长度加一IF (@EndIndex = 0)SET @EndIndex = LEN(@WhereStr) + 1;-- 提取当前子字符串SET @Substring = SUBSTRING(@WhereStr,@StartIndex,@EndIndex - @StartIndex);-- 更新起始索引至下一位置之后SET @StartIndex = @EndIndex + LEN(@Delimiter2);-- 将子字符串插入结果表中IF(@EndIndex>LEN(@WhereStr))BEGINSET @Result+= ' Id='+@Substring+' ) ';BREAK;--中止循环ENDIF (@DoCount%2=1)--奇次--[A]到[T]止SET @Result+= ' (SELECT Top 1 '+ @Substring +' as ROW, Name From TableA Where ';ELSE --偶次--[T]到[A]止SET @Result+= ' Id='+@Substring+' ) UNION ALL';Set @DoCount+=1 --循环次数ENDRETURN @Result
ENDGO
4、总结
问题主要在于前端拼接SQL后,传输的不安全(注入)、长字符不稳定(语句过长可能…)。
而逻辑放在SQL又过于难实现,毕竟逻辑确实是SQL的短板。
本次记录主要是split的挨个、循环截取,将11[A]‘‘AA’’ [T] 22[A]‘‘BB’’ [T] 33[A]‘‘CC’’
转换为 11 ‘‘AA’’ 22 ‘BB’’ 33 ‘‘CC’’ ,并穿插入SQL的巧思。