sql语法巧用之not取反

2023-05-16

🚀 优质资源分享 🚀

学习路线指引(点击解锁)知识定位人群定位
🧡 Python实战微信订餐小程序 🧡进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
💛Python量化交易实战💛入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统
目录
  • 1. 举几个正反案例的例子
  • 2. 正面硬刚反义词
  • 3. sql语法巧用
  • 4. 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..
 ...
}

可以看出,应该还是可行的,但是对于像优先级,括号,四则运算之类的处理,那应该是相当的复杂的。对于非专业搞数据库开发,或者编译器的同学而言,应该是非常之难的。具体咱也不知道,看你咯。

返回顶部### 3. sql语法巧用

我们知道,一个sql的bool表达式,有true/false之分,正常情况下都是以 true 作为判断条件的。比如 is null 为true, 那么 is not null 就为false。 =1为true, 那么 !=false, in 为true, 那么 not in 就为false。between 为true, 那么 not between 就为false.

虽然情况很多,但是我们已经看到,sql中天然就有一个词代表了取反的意思。只是好像只有特定的场景下才可以使用not关键词。好像有点失望了。

为什么不试一试呢?比如 x=1 的反义词是否可以是 not x = 1 ? 为测试方便,我们直接使用内存数据库sqllite测试, https://www.sqlite.org/download.html  。参考下载链接: https://www.sqlite.org/2022/sqlite-tools-win32-x86-3390400.zip

接下来我们用两张表测试下。

-- 新建测试表1
create table test1 (
 id int, name varchar(50), 
 age int 
) 
-- comment '用户基础信息表';
-- 新建测试表2
create table test2 (
 uid int, 
 salary double, 
 company varchar(50)
) 
-- comment '用户工作信息表';
-- 插入测试数据
insert into test1 (id, name, age) values (1, 'zhangsan', 18);
insert into test1 (id, name, age) values (2, 'lisi', 20);
insert into test1 (id, name, age) values (3, 'wanger', 30);
insert into test2 (uid, salary, company) values (1, 1000.1, 'axxx');
insert into test2 (uid, salary, company) values (2, 2000.1, 'bxxx');
insert into test2 (uid, salary, company) values (3, 3000.1, 'cxxx');

接下来我们用not语法和非not语法测试下。

sqlite> select * from test1 where name = 'zhangsan';
1|zhangsan|18
sqlite> select * from test1 where name != 'zhangsan';
2|lisi|20
3|wanger|30
sqlite> select * from test1 where not (name = 'zhangsan');
2|lisi|20
3|wanger|30

看起来语法是支持的,而且两个语法的简单语句执行结果居然是一样的。接下来我们测试稍微复杂点的:

sqlite> select * from test1 where name = 'zhangsan' or name = 'lisi';
1|zhangsan|18
2|lisi|20
sqlite> select * from test1 where name != 'zhangsan' and name != 'lisi';
3|wanger|30
sqlite> select * from test1 where not( name = 'zhangsan' or name = 'lisi');
3|wanger|30

看起来多个条件的连接not语法也是支持的,而且结果也是正确的呢。我们来测试一个三条件的语句:

sqlite> select * from test1 where name = 'zhangsan' or name = 'lisi' and age = 20;
1|zhangsan|18
2|lisi|20
sqlite> select * from test1 where name != 'zhangsan' and (name != 'lisi' or age != 20);
3|wanger|30
sqlite> select * from test1 where not (name = 'zhangsan' or name = 'lisi' and age = 20);
3|wanger|30
sqlite> select * from test1 where age > 20;
3|wanger|30
sqlite> select * from test1 where age <= 20;
1|zhangsan|18
2|lisi|20
sqlite> select * from test1 where not( age > 20 );
1|zhangsan|18
2|lisi|20

好吧,看起来单表的操作并没有问题。会不会是因为单表简单的原因?我们试试多表join的:

sqlite> select t1.name,t1.age, t2.salary from test1 t1 left join test2 t2 on t1.id = t2.uid where t1.age >= 20 and t2.salary > 2000;
lisi|20|2000.1
wanger|30|3000.1
sqlite> select t1.name,t1.age, t2.salary from test1 t1 left join test2 t2 on t1.id = t2.uid where t1.age < 20 or t2.salary <= 2000;
zhangsan|18|1000.1
sqlite> select t1.name,t1.age, t2.salary from test1 t1 left join test2 t2 on t1.id = t2.uid where not (t1.age >= 20 and t2.salary > 2000);
zhangsan|18|1000.1

是了,没问题,语法支持,结果正确。换成其他的sql类数据库做同样的测试,仍然一致。基本可以确定,not语法是可以覆盖结果取反的场景的。

返回顶部### 4. not语法的底层原理

虽然not语法看起来没啥问题,但是在官方的介绍里,貌似并没有找到相应的章节描述,为什么呢?不得而知。

那么sql的not在底层是怎么实现的呢?两个思路吧:一是像咱们前面提到的进行反面条件转换,得到后再进行执行;二是直接计算的时候,先正向计算出结果,然后遇到not之后,当作一个运算符,直接将结果取反,从而决定结果是抛弃还是保留。

因为数据库底层都是是根据规则依次计算结果判定,所以最合适的方式是正向计算结果,然后遇到not进行true/false反转,这是其正常的执行引擎流程。但具体是否如此,暂不得而知,待以后有机会再研究研究。

通过本文的介绍,在以后的工作中,咱们也可以多了一个选择了,虽然少见,但不排除遇见。希望能为大家多一点参考。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

sql语法巧用之not取反 的相关文章

  • SQL 国家字符 (NCHAR) 数据类型的真正用途是什么?

    也CHAR CHARACTER and VARCHAR CHARACTER VARYING SQL 提供了NCHAR NATIONAL CHARACTER and NVARCHAR NATIONAL CHARACTER VARYING 类型
  • MS ACCESS 计数/求和行数,不重复

    我有下表 我需要计算总行数而不包括任何重复记录 CustomerID test1 test1 test2 test3 test4 test4 如您所见 总行数为 6 但有两个 test1 和两个 test4 我希望查询返回 4 IOW 我想
  • POINT 列上的 MySQL INSERT/UPDATE

    我正在尝试用我国家的地理位置填充我的数据库 我的一张表有 4 个字段 ID PK 纬度 经度和地理点 EDIT SCDBs Punto Geografico SET lat 18 469692 SET lon 63 93212 SET g
  • 在 SELECT IN 中使用 Oracle 参数时出现问题

    我在将一串数字插入sql查询时遇到问题 SELECT FROM tablename a WHERE a flokkurid IN 3857 3858 3863 3285 ORDER BY sjodategund rodun or SELEC
  • MySQL - 从临时表插入

    这看起来非常简单 但我坚持使用简单的插入语句 见下文 begin work CREATE TEMPORARY TABLE IF NOT EXISTS insert table AS select r resource id fr file
  • java ResultSet,使用MAX sql函数

    你好 这就是我想要的 我连接到数据库并检索 UniqueId 列的最大元素 并将其分配给名为 maxID 的整数变量 这是我的方法 int maxID 0 Statement s2 con createStatement s2 execut
  • SQL 错误:“没有这样的表”

    我试图解决为什么我的代码为所有查询返回 null 的原因 最后发现 sql 查询什么也没有返回 我使用简约代码创建了一个新的 AIR 文档 s WindowedApplication
  • 将 .MDF SQL Server 数据库与 ASP.NET 结合使用与使用 SQL Server

    我目前正在 ASP NET MVC 中编写一个网站 我的数据库 其中还没有任何数据 只有正确的表 使用 SQL Server 2008 我已将其安装在我的开发计算机上 我使用服务器资源管理器从应用程序连接到数据库 然后使用 LINQ to
  • PostgreSQL 中“-”处或附近的语法错误

    我正在尝试运行查询来更新用户密码 alter user dell sys with password Pass 133 但因为 它给了我这样的错误 ERROR syntax error at or near LINE 1 alter use
  • SQL Join 列上类似于另一列[重复]

    这个问题在这里已经有答案了 可能的重复 mysql连接查询使用like https stackoverflow com questions 1930809 mysql join query using like 我想要进行连接 其中一列包含
  • SQL Server 2008R2 和创建 XML 文档

    论坛上的第一篇文章 因为我真的被这个问题困住了 以下查询正确地将有效的 XML 文档分配给 xTempXML 变量 类型为 xml 注 文档的长度 转换为varchar max 711 select xTempXML select Pres
  • 通过 osql.exe 运行脚本时出现问题

    我尝试以这种格式运行我的软件的更新脚本 osql exe i path to script U 用户 P 密码 S sqlserver 位置 d 数据库名称 n b 大多数脚本的格式相同 并且都以 GO 结尾 其中很多都运行得很好 但随机脚
  • 内置函数将每个单词的第一个字母大写

    如果 SQL Server 中已存在此类函数 我不想为此创建自定义函数 输入字符串 This is my string to convert预期输出 This Is My String To Convert SET ANSI NULLS O
  • SQL Server 连接其他表中不存在的位置

    Service Asset AssetService Id Name Id Name AssetId ServiceId
  • 提高第一个查询的性能

    如果执行以下数据库 postgres 查询 则第二次调用要快得多 我猜第一个查询很慢 因为操作系统 linux 需要从磁盘获取数据 第二个查询受益于文件系统级别和 postgres 中的缓存 有没有一种方法可以优化数据库以快速获得结果fir
  • 删除数据库中的行后如何重新排序ID

    我正在使用 C 来制作具有 sql 数据库的程序 在数据库中我有一个名为Workers 它有一个自动增量和主键ID column 当我删除一条记录时 ID 之间会出现间隙 删除记录后如何重新排序 ID UPDATE 我要做的就是找到记录后将
  • 解析带下划线的 SQL Server 数字文字

    我想知道它为什么有效以及为什么它不返回错误 SELECT 2015 11 Result 11 2015 第二种情况 SELECT 2 1 a a 2 1 检查元数据 SELECT name system type name FROM sys
  • 从 Getdate() 获取时间

    我想采取Getdate 结果 例如 2011 10 05 11 26 55 000 into 11 26 55 AM 我看过其他地方并发现 Select RIGHT CONVERT VARCHAR GETDATE 100 7 这给了我 11
  • 如何通过SQL查询检查是否有JSON函数?

    有SQL 2016 中的 JSON 函数 https learn microsoft com en us sql t sql functions json functions transact sql例如 JSON VALUE JSON Q
  • SQL 更新 - 更新选定的行

    我正在使用 SQL Server 2008 我有一个名为MYTABLE有两列 ID STATUS 我想编写一个存储过程来返回其记录STATUS是 0 但是这个存储过程必须更新STATUS返回行数为 1 如何在单个查询中执行此选择和更新操作

随机推荐

  • 怎么在IDEA中配置power shell

    第一步 xff1a 接下来 xff0c 在步骤3那里找到黄色方框里面的powershell exe文件 在点击OK之后 xff0c 你就能看到以下 说明 xff0c 已经配置成功了
  • 【数据结构】——二叉树的创建详解

    之前有篇文章概要的叙述了一下关于二叉树的创建 xff0c 参考博文二叉树的c语言创建但是很不全面 xff0c 这篇文章就让我们来好好探讨一下关于二叉树的创建吧 首先 xff0c 我们要做一些前期准备 xff0c 有关于本课二叉树的结点信息和
  • Fortify--安装与使用

    Fortify是Micro Focus旗下AST xff08 应用程序安全测试 xff09 产品 xff0c 其产品组合包括 xff1a Fortify Static Code Analyzer提供静态代码分析器 xff08 SAST xf
  • [web安全]burpsuite抓取微信公众号、小程序数据包

    最近在接触微信公众号和微信小程序的渗透 xff0c 用过模拟器 xff0c 也直接在手机上设置代理 xff0c 都遇到各种问题 xff0c 用起来很不舒心 记录遇到的一些问题 xff0c 帮助和我一样踩过坑的 xff0c 亲测好用 IE浏览
  • 安全-开源项目安全检查规范

    有些公司为了提高在IT圈的技术知名度 xff0c 增加行业影响力 xff0c 一些技术会定期将非核心业务源代码以公司级名义上传到源码开源平台 xff0c 如GitHub 特此输出相关的安全检查规范 第一条 开源的代码项目可以为通用的解决方案
  • 安全-系统上线安全检查规范

    现在各个公司都开始重视安全 xff0c 不仅仅是因为国家开始重视安全 xff0c 而是安全漏洞一旦暴露 xff0c 被有心之人发现进行破坏 xff0c 损失将无法估量 xff1b 比如 xff1a 前端时间拼多多优惠券事件 安全测试是一项比
  • 应用安全测试技术DAST、SAST、IAST对比分析-持续更新

    应用安全测试技术DAST SAST IAST对比分析 持续更新 版权来源 xff1a 安全牛首发文章 xff0c 本文仅补充完善 一 全球面临软件安全危机 我们即将处于一个软件定义一切的时代 xff0c 这是 一个最好的时代 xff0c 也
  • Python中函数和方法的区别

    简单总结 xff1a 与类和实例无绑定关系的function都属于函数 xff08 function xff09 xff1b 与类和实例有绑定关系的function都属于方法 xff08 method xff09 首先摒弃错误认知 并不是类
  • 九宫格,二十五宫格,甚至八十一宫格 技巧

    九宫格 二十五宫格 甚至八十一宫格 只要是奇数的平方宫格者能做到横格相加 坚格相加 斜格相加得数相同 而偶数的宫格只有十六宫格有些规律 下面是三宫格 五宫格 七宫格 九宫格图 填写技巧 第一行中间填1 xff0c 右上没有的 xff0c 就
  • python 编写输出到csv

    def test write self fields 61 fields append orderCode with open r 39 test001 csv 39 39 a 39 newline 61 34 34 as f writer
  • Vagrant 共享目录出现 mount:unknown filesystem type ‘vboxsf‘

    环境 xff1a Windows 10 VirtualBox 7 0 6 Vagrant 2 3 4 错误如下 xff1a 61 61 gt default Attempting graceful shutdown of VM 61 61
  • 利用python进行企业微信机器人自动发送消息

    def test 004 robot self headers 61 34 Content Type 34 34 text plain 34 s 61 34 卖品 xff0c 打印码 xff1a 验证码 34 format str prin
  • js修改页面hidden属性

    想获取这个value的值 xff0c 但是看其是个input标签 xff0c 他的type属性是hidden 也就是只能定位 xff0c 不能对其操作 xff0c 想要通过元素的 get attribute 34 value 34 是不可能
  • mybatis的多表查询(一对一,一对多,多对多)

    mybatis多表查询 表之间的关系有几种 xff1a 一对多 多对一 一对一 多对多 举例 xff1a 用户和订单就是一对多 订单和用户就是多对一 一个用户可以下多个订单 多个订单属于同一个用户 人和身份证号就是一对一 一个人只能有一个身
  • 8款纯CSS3搜索框

    效果如下 xff1a 代码实现如下 xff1a span class token doctype lt DOCTYPE html gt span span class token tag span class token tag span
  • ViewBinding和DataBinding的理解和区别

    之前一直把ViewBinding当成了DataBinding xff0c 直到最近的学习中才发现他们不是一个东西 于是写下这篇笔记帮助理解和区分他们俩 一 ViewBinding 1 什么是ViewBinding 先来看看官方是怎么说的 通
  • Android KeyStore的使用

    在我们App开发过程中 xff0c 可能会涉及到一些敏感和安全数据需要加密的情况 xff0c 比如登录token的存储 我们往往会使用一些加密算法将这些敏感数据加密之后再保存起来 xff0c 需要取出来的时候再进行解密 此时就会有一个问题
  • 2流高手速成记(之四):SpringBoot整合redis及mongodb

    x1f680 优质资源分享 x1f680 学习路线指引 xff08 点击解锁 xff09 知识定位人群定位 x1f9e1 Python实战微信订餐小程序 x1f9e1 进阶级本课程是python flask 43 微信小程序的完美结合 xf
  • RabbitMQ延迟消息指南【.NET6+EasyNetQ】

    x1f680 优质资源分享 x1f680 学习路线指引 xff08 点击解锁 xff09 知识定位人群定位 x1f9e1 Python实战微信订餐小程序 x1f9e1 进阶级本课程是python flask 43 微信小程序的完美结合 xf
  • sql语法巧用之not取反

    x1f680 优质资源分享 x1f680 学习路线指引 xff08 点击解锁 xff09 知识定位人群定位 x1f9e1 Python实战微信订餐小程序 x1f9e1 进阶级本课程是python flask 43 微信小程序的完美结合 xf