使用JSON來實現資料庫中的動態條件匹配
- 2021 年 7 月 7 日
- 筆記
- OPENJSON, SQL Server, 資料庫技術
在項目的資料庫設計中,可能會碰到不確定列的情況。 使用JSON 格式來保存這種不確定列的數據, 是一種比較靈活且方便的做法。
比如一張表記錄學生的成績。

如果列上的學科是不確定的, 比如有的學生有物理成績, 有的學生有生物成績,那麼我們可能會考慮將表設計成:

但這樣,可能就會在查詢的時候,遇到麻煩。比如我想知道數學成績是4分的有哪些學生?
類似的問題, 我在項目中使用的做法是寫了一個自定義的函數: fun_scale_matchJsonPattern
1 /* 2 * Author : Harvey Hu 3 * Created At :2020-6-5 4 * Description : 按指定單個模式判斷匹配JSON是否滿足(>= 條件即為匹配) 5 * Return =1 匹配 ; =0 不匹配 6 */ 7 CREATE FUNCTION [dbo].[fun_scale_matchJsonPattern] 8 ( 9 @pattern nvarchar(1000), -- 單個模式 10 @input nvarchar(1000) 11 ) returns int 12 begin 13 Declare @targetScore int = 0; 14 Declare @actualScore int = 0; 15 Declare @result int = 0; 16 17 select @targetScore= count(*) from OPENJSON(@pattern) a 18 19 select @actualScore = count(1) 20 from OPENJSON(@pattern) a 21 inner join OPENJSON(@input) b on a.[key]= b.[key] and a.[value] = b.[value] 22 23 IF @targetScore = @actualScore 24 SET @result = 1 25 26 return @result 27 28 end
使用的示例如下
1 select 2 * 3 from dbo.[學生成績表] 4 where 5 dbo.fun_scale_matchJsonPattern([成績],'{"數學":"4"}')=1
簡單的來說,就是比較條件的數量和匹配的條件數量是否一致,如果一致則認為滿足。
這種方式的好處是, 可以使用 ‘and’ 邏輯去匹配多個條件;不好的地方在於只能判斷『相等邏輯』,不適用於『大於』『小於』等其他的二元邏輯。 不過由於工作上夠用了, 所以沒有做更多的擴展。如果有需要可以在評論中留言。
基於上述內容, 下面這個是『多個條件取其一即可滿足』的實現
1 /* 2 * Author : Harvey Hu 3 * Created At :2020-6-5 4 * Description : 按指定多個模式判斷匹配JSON是否滿足(只要有其中之一滿足即為匹配) 5 * Return =1 匹配 ; =0 不匹配 6 */ 7 CREATE FUNCTION [dbo].[fun_scale_matchJsonPatterns] 8 ( 9 @patterns nvarchar(1000), -- 數組JSON格式 10 @input nvarchar(1000) 11 ) returns int 12 as 13 begin 14 DECLARE @key nvarchar(50) 15 DECLARE @value nvarchar(1000) 16 DECLARE @type int 17 DECLARE @result int =0 18 19 DECLARE jsonCursor CURSOR for 20 select * from OPENJSON(@patterns) 21 22 OPEN jsonCursor 23 fetch next from jsonCursor into @key,@value ,@type 24 25 while @@fetch_status=0 --判斷是否成功獲取數據 進入循環 26 begin 27 if @type = 5 and dbo.[fun_scale_matchJsonPattern](@value,@input)=1 -- object 28 set @result = 1 29 fetch next from jsonCursor into @key,@value ,@type 30 end 31 32 33 CLOSE jsonCursor 34 35 return @result 36 end
使用了游標, 所以性能上可能會有影響。 期待改進!


