sql語法巧用之not取反

數據庫的重要性和通用性都不用說了,什么sql的通用性 , sql優化之類的也不必說了,咱們今天來聊聊另一個有意思的話題:如何取一個篩選的反面案例 。
1. 舉幾個正反案例的例子為了讓大家理解我們的假設場景,什么叫做正反案例?比如:
0. 正向案例為:取出年齡為空的用戶 , 那么反面案例為:取出年齡不為空的用戶;1. 正向案例為:取出年齡大于25的用戶,那么反面案例則為:取出年齡小于等于25的用戶;2. 正向案例為:取出姓名為男的用戶,那么反面案例則為:取出性別不等于男的用戶;3. 正向案例為:取出薪資在1000-2000之間的用戶,那么反面案例為:取出薪資小于1000或者大于2000的用戶;4. 正向案例為:取出年齡大于25且性別為男的用戶,那么反面案例為:取出年齡小于25或者性別不為男的用戶;5. 正向案例為:取出年齡大于25且為男性或者薪資大于2000的用戶,那么反面案例為:取出年齡小于25或者性別不為男的用戶且薪資小于等于2000的用戶;
相信大家都理解了,其實就相當于取反義詞 。也就是說輸入是一個正向規則,我們需要輸出一個反向規則 。當然一個前提是咱們使用sql語言 。
從前到后,我們可以理解為一個實現難度的提升,比如第一個 'is null' 的反義詞則是 'is not null',第二個 '>' 的反義詞則是 '<=' 。這些簡單的是單個規則的表述 。
但到第4個案例,就涉及到區間了,相當于有組合詞了 , 即 'between 1000 and 2000', 反義詞則需要向兩邊取值了即: '<= 100 or >= 2000';
第6個則更復雜 , 涉及三個變量,即 'age > 25 and sex = '男' or salary > 2000', 反義詞則需要考慮到優先級的問題了 。
至于更復雜的咱們就不說了 。
2. 正面硬剛反義詞通過以上案例,相信大家已經明白我在說什么了 。沒錯,就是求反義詞 。具體應用場景是啥呢?舉個例子,用戶配置了一個基礎規則,然后其他地方可以引用 , 正向引用,則是條件為真 , 反向引用則是條件為假 。
不管怎么樣 , 考題就是如何求解一個條件的反向表示?
正向解題思路是啥呢?首先 , 如果想要自行求反解,那么第一步就是必須要先理解正向表達的語義 , 即你至少得有分詞、構建語法樹、理解語義的過程 。
這樣做完之后 , 至少你可以做一些事了,就像前面幾個簡單的單條件配置,為空的反義詞就是不為空,中間加個 not 就可以了,則可以直接套用固定反轉即可 。抽象點說就是,根據一個固定的規則映射字典,就可以找到反義詞了 。
但是 , 針對有多個條件表達的情況,則會復雜起來,先來看有兩個條件連接為'且'的表達,那么求反就不能通過單個字典映射進行處理了 。但仍然可以拆解為兩個求反操作,即'條件1求反' 或者 '條件2求反' 。
而針對兩個條件連接為'或'的表達,則需要對單個未反,然后用'且'連接,即 '條件1求反' 且 '條件2求反' 。
以上,仍然停留在比較簡單的場景,即只有1個條件或者2個條件的情況下 , 而更多的是,可能3個、4個、10個甚至更多個,甚至還有'()'括號的場景,多層嵌套,這樣的求反,其實就相當復雜了 。但到底能不能實現求反呢?理論上可行的,實際上不管條件有多少個,在sql的表達中,都是一個個的bool表達式,然后使用'and'/'or' 連接,而且更重要的 , 不管有多少個'and'/'or', 最終總要一個個計算,所以我們只需要一直拆解條件表達式,直到它是一個原子表達式,然后再套用字典轉換,就可以做到求反的效果了 。當然了,這個實現應該還是一個很復雜的過程 , 而且不一定適用,咱們就只給出一些偽代碼供參考了 。
表達式求反函數(入參: 原始表達式) {分詞;語法樹構建;語義解析構造優先級的bool表達式樹;復雜條件求反 -> 代入現有解析好的bool表達式;}復雜條件求反(入參: bool表達式) {if 原子表達式:return 字典映射求反表達式;if 當前連接符是 'and':復雜條件求反 -> 代入左邊的bool表達式;復雜條件求反 -> 代入左邊的bool表達式;return 以上兩個結果用'or'連接;if 當前連接符是 'or':復雜條件求反 -> 代入左邊的bool表達式;復雜條件求反 -> 代入左邊的bool表達式;return 以上兩個結果用'and'連接;}字典映射求反表達式(入參: bool表達式) {為空 -> 不為空;等于 -> 不等于;大于 -> 小于等于;in -> not..in.....}可以看出,應該還是可行的,但是對于像優先級 , 括號,四則運算之類的處理,那應該是相當的復雜的 。對于非專業搞數據庫開發 , 或者編譯器的同學而言,應該是非常之難的 。具體咱也不知道,看你咯 。

推薦閱讀