分享

轻松学SQL(3)

 夜猫速读 2022-05-05 发布于湖北

算术运算符和比较运算符

学习重点

● 运算符就是对其两边的列或者值进行运算(计算或者比较大小等)的符号。

● 使用算术运算符可以进行四则运算。

● 括号可以提升运算的优先顺序(优先进行运算)。

● 包含NULL的运算,其结果也是NULL。

● 比较运算符可以用来判断列或者值是否相等,还可以用来比较大小。

● 判断是否为NULL,需要使用IS NULL或者IS NOT NULL运算符。

算术运算符

SQL语句中可以使用计算表达式。用SELECT语句,把各个商品单价的2倍(sale_price的2倍)以"sale_price_x2"列的形式读取出来。

SQL语句中也可以使用运算表达式

select product_name,sale_price, sale_price*2 as "sale_price_x2"from Product;

执行结果

sale_price_x2列中的sale_price * 2就是计算销售单价的2倍的表达式。以product_name列的值为’T恤衫’的记录行为例,sale_price列的值1000的2倍是2000,它以sale_price_x2列的形式被查询出来。同样,’打孔器’记录行的值500的2倍1000,'运动T恤’记录行的值4000的2倍8000,都被查询出来了。运算就是这样以行为单位执行的。

SQL语句中可以使用的四则运算的主要运算符

四则运算所使用的运算符(+、-、*、/)称为算术运算符。运算符就是使用其两边的值进行四则运算或者字符串拼接、数值大小比较等运算,并返回结果的符号。加法运算符(+)前后如果是数字或者数字类型的列名的话,就会返回加法运算后的结果。SQL中除了算术运算符之外还有其他各种各样的运算符。

SELECT子句中可以使用常数或者表达式。

当然,SQL中也可以像平常的运算表达式那样使用括号( )。括号中运算表达式的优先级会得到提升,优先进行运算。例如在运算表达式(1+2)* 3中,会先计算1+2的值,然后再对其结果进行* 3运算。

括号的使用并不仅仅局限于四则运算,还可以用在SQL语句的任何表达式当中。

需要注意NULL

SQL语句中进行运算时,需要特别注意含有NULL的运算。请大家考虑一下在SQL语句中进行如下运算时,结果会是什么呢?

A.5+NULL

B.10- NULL

C. 1 * NULL

D.4 / NULL

E.NULL / 9

F.NULL / 0

正确答案全部都是NULL。大家可能会觉得奇怪,为什么会这样呢?实际上所有包含NULL的计算,结果肯定是NULL。即使像F那样用NULL除以0时这一原则也适用。通常情况下,类似5/0这样除数为0的话会发生错误,只有NULL除以0时不会发生错误,并且结果还是NULL。

尽管如此,很多时候我们还是希望NULL能像0一样,得到5+NULL=5这样的结果。不过也不要紧,SQL中也为我们准备了可以解决这类情况的方法.

FROM子句真的有必要吗?

在第1节中我们介绍过SELECT语句是由SELECT子句和FROM子句组成的。可实际上FROM子句在SELECT语句中并不是必不可少的,只使用SELECT子句进行计算也是可以的。

只包含SELECT子句的SELECT语句

select (100+200)*3 as calculation;

执行结果为:

calculation

-----------

900

实际上,通过执行SELECT语句来代替计算器的情况基本上是不存在的。不过在极少数情况下,还是可以通过使用没有FROM子句的SELECT语句来实现某种业务的。例如,不管内容是什么,只希望得到一行临时数据的情况。

但是也存在像OracIe这样不允许省略SELECT语句中的FROM子句的RDBMS,请大家注意。

注在Oracle中,FROM子句是必需的,这种情况下可以使用DUAL这个临时表。另外,DB2中可以使用SYSIBM.SYSDUMMY1这个临时表。

比较运算符

下面让我们再使用符号=选取出销售单价(sale_price)为500日元(数字500)的记录

选取出sale_price列为500的记录

select product_name,product_type from Product where sale_price=5;

执行结果

  product_name  product_type

像符号=这样用来比较其两边的列或者值的符号称为比较运算符,符号=就是比较运算符。在WHERE子句中通过使用比较运算符可以组合出各种各样的条件表达式.

接下来,我们使用“不等于”这样代表否定含义的比较运算符<>,选取出sale_price列的值不为500的记录:

select product_name,product_type from Product where sale_price<>500;

执行结果

SQL中主要的比较运算符如表2-2所示,除了等于和不等于之外,还有进行大小比较的运算符。

这些比较运算符可以对字符、数字和日期等几乎所有数据类型的列和值进行比较。例如,从Product表中选取出销售单价(sale_price)大于等于1000日元的记录,或者登记日期(regist_date)在2009年9月27日之前的记录,可以使用比较运算符>=和<,在WHERE子句中生成如下条件表达式.

选取出销售单价大于等于1000日元的记录

select product_name,product_type,sale_price from Product where sale_price>=1000;

执行结果

选取出登记日期在2009年9月27日之前的记录

select product_name,product_type,regist_date from Product whereregist_date<'2021-07-18';

执行结果

小于某个日期就是在该日期之前的意思。想要实现在某个特定日期(包含该日期)之后的查询条件时,可以使用代表大于等于的>=运算符。

另外,在使用大于等于(>=)或者小于等于(<=)作为查询条件时,一定要注意不等号(<、>)和等号(=)的位置不能颠倒。一定要让不等号在左,等号在右。如果写成(=<)或者(=>)就会出错。当然,代表不等于的比较运算符也不能写成(><)。

使用比较运算符时一定要注意不等号和等号的位置。

除此之外,还可以使用比较运算符对计算结果进行比较。代码清单2-22在WHERE子句中指定了销售单价(sale_price)比进货单价(purchase_price)高出500日元以上的条件表达式。为了判断是否高出500日元,需要用sale_price列的值减去purchase_price列的值。

WHERE子句的条件表达式中也可以使用计算表达式

select product_name,sale_price,purchase_price from Product where sale_price-purchase_price>=500;

执行结果

对字符串使用不等号时的注意事项

对字符串使用大于等于或者小于等于不等号时会得到什么样的结果呢?

接下来我们使用Chars表来进行确认。虽然该表中存储的都是数字,但chr是字符串类型(CHAR类型)的列。

create table chars(chr char(3) not null, primary key (chr);

插入数据

insert into chars values('1');insert into chars values('2');insert into chars values('3');insert into chars values('1');insert into chars values('10');insert into chars values('11');insert into chars values('222');commit;

选取出大于’2’的数据的SELECT语句

select chr from chars where chr>'2';

执行结果

chr

--------

3

222

没想到吧?是不是觉得10和11比2大,所以也应该选取出来呢?大家之所以这样想,是因为混淆了数字和字符串,也就是说2和’2’并不一样

现在,chr列被定为字符串类型,并且在对字符串类型的数据进行大小比较时,使用的是和数字比较不同的规则。典型的规则就是按照字典顺序进行比较,也就是像姓名那样,按照条目在字典中出现的顺序来进行排序。该规则最重要的一点就是,以相同字符开头的单词比不同字符开头的单词更相近。

Chars表chr列中的数据按照字典顺序进行排序的结果如下所示。

1 10 11 2 222 3

'10’和’11’同样都是以’1’开头的字符串,首先判定为比’2’小。这就像在字典中“提问”“提议”和“问题”按照如下顺序排列一样。

提问

提议

问题

进行大小比较时,得到的结果是’1-3’比’2’小('1-3'<'2'), '3’大于’2-2'('3' > '2')。

比较字符串类型大小的规则今后还会经常使用,所以请大家牢记.

字符串类型的数据原则上按照字典顺序进行排序,不能与数字的大小顺序混淆。

不能对NULL使用比较运算符

关于比较运算符还有一点十分重要,那就是作为查询条件的列中含有NULL的情况。例如,我们把进货单价(purchase_price)作为查询条件。请注意,商品“叉子”和“圆珠笔”的进货单价是NULL。

我们先来选取进货单价为2800日元(purchase_price=2800)的记录。

select product_name,purchase_price from Product where purchase_price=2800;

执行结果

大家对这个结果应该都没有疑问吧?接下来我们再尝试选取出进货单价不是2800日元(purchase_price <> 2800)的记录.

select product_name,purchase_price from Product where purchase_price<>2800;

执行结果

执行结果中并没有“叉子”和“圆珠笔”。这两条记录由于进货单价不明(NULL),因此无法判定是不是2800日元。

那如果想选取进货单价为NULL的记录的话,条件表达式该怎么写呢?历经一番苦思冥想后,用“purchase_price=NULL”试了试,还是一条记录也取不出来。

即使使用<>运算符也还是无法选取出NULL的记录。因此,SQL提供了专门用来判断是否为NULL的IS NULL运算符。想要选取NULL的记录时,可以像这样来书写条件表达式。

select product_name,purchase_price from Product where purchase_price is null;

执行结果

反之,希望选取不是NULL的记录时,需要使用IS NOT NULL运算符.

select product_name,purchase_price from Product where purchase_price is not null;

执行结果

希望选取NULL记录时,需要在条件表达式中使用IS NULL运算符。希望选取不是NULL的记录时,需要在条件表达式中使用IS NOT NULL运算符。

逻辑运算符

● 通过使用逻辑运算符,可以将多个查询条件进行组合。

● 通过NOT运算符可以生成“不是~”这样的查询条件。

● 两边条件都成立时,使用AND运算符的查询条件才成立。

● 只要两边的条件中有一个成立,使用OR运算符的查询条件就可以成立。● 值可以归结为真(TRUE)和假(FALSE)其中之一的值称为真值。比较运算符在比较成立时返回真,不成立时返回假。但是,在SQL中还存在另外一个特定的真值——不确定(UNKNOWN)。

● 将根据逻辑运算符对真值进行的操作及其结果汇总成的表称为真值表。

● SQL中的逻辑运算是包含对真、假和不确定进行运算的三值逻辑。

NOT运算符

想要指定“不是~”这样的否定条件时,需要使用<>运算符。除此之外还存在另外一个表示否定,并且使用范围更广的运算符NOT

NOT不能单独使用,必须和其他查询条件组合起来使用。例如,选取出销售单价(sale_price)大于等于1000日元的记录的SELECT语句如下所示

seelct product_name,product_type,sale_price from Product where sale_price>=1000;

执行结果

查询条件中添加NOT运算符

select product_name,product_type,sale_price from Product wherenot sale_price>=1000;

执行结果

明白了吗?通过否定销售单价大于等于1000日元(sale_price>= 1000)这个查询条件,就可以选取出销售单价小于1000日元的商品。也就是说,WHERE子句指定的查询条件,与代码清单2-32中WHERE子句指定的查询条件(sale_price < 1000)是等价的.

select product_name,product_type from Product where sale_price<1000;

使用NOT运算符时查询条件的变化

通过以上的例子大家可以发现,不使用NOT运算符也可以编写出效果相同的查询条件。不仅如此,不使用NOT运算符的查询条件更容易让人理解。使用NOT运算符时,我们不得不每次都在脑海中进行“大于等于1000日元以上这个条件的否定就是小于1000日元”这样的转换。

虽然如此,但是也不能完全否定NOT运算符的作用。在编写复杂的SQL语句时,经常会看到NOT的身影。这里只是希望大家了解NOT运算符的书写方法和工作原理,同时提醒大家不要滥用该运算符。

NOT运算符用来否定某一条件,但是不能滥用。
AND运算符和OR运算符

到目前为止,我们看到的每条SQL语句中都只有一个查询条件。但在实际使用当中,往往都是同时指定多个查询条件对数据进行查询的。例如,想要查询“商品种类为厨房用具、销售单价大于等于3000日元”或“进货单价大于等于5000日元或小于1000日元”的商品等情况。

在WHERE子句中使用AND运算符或者OR运算符,可以对多个查询条件进行组合。

AND运算符在其两侧的查询条件都成立时整个查询条件才成立,其意思相当于“并且”。

OR运算符在其两侧的查询条件有一个成立时整个查询条件都成立,其意思相当于“或者”.

例如,从Product表中选取出“商品种类为厨房用具(product_type=’厨房用具’),并且销售单价大于等于3000日元(sale_price >= 3000)的商品”的查询条件中就使用了AND运算符.

seelct product_name,purchase_price from Product where product_type='厨房用具'and sale_price>=3000;

执行结果

左侧的圆圈代表符合查询条件“商品种类为厨房用具”的商品,右侧的圆圈代表符合查询条件“销售单价大于等于3000日元”的商品。两个圆重合的部分(同时满足两个查询条件的商品)就是通过AND运算符能够选取出的记录。

将集合(事物的聚集)的关系通过更加容易理解的图形进行可视化展示。

选取出“商品种类为厨房用具(product_type=’厨房用具’),或者销售单价大于等于3000日元(sale_price >=3000)的商品”的查询条件中使用了OR运算符.

select product_name,purchase_price from Product where product_type='厨房用具'or sale_price>=3000;

执行结果

还是让我们来看看查询条件的文氏图吧!包含在左侧的圆圈(商品种类为厨房用具的商品)或者右侧的圆圈(销售单价大于等于3000日元的商品)中的部分(两个查询条件中满足任何一个的商品)就是通过OR运算符能够取出的记录。

通过文氏图件,大家可以多多加以利用。可以方便地确认由多个条件组合而成的复杂的SQL语句的查询条.

多个查询条件进行组合时,需要使用AND运算符或者OR运算符。

文氏图很方便。

通过括号强化处理

接下来我们尝试书写稍微复杂一些的查询条件。例如,使用下面的查询条件对Product表进行查询的SELECT语句,其WHERE子句的条件表达式该怎么写呢?

商品种类为办公用品”并且“登记日期是2009年9月11日或者2009年9月20日”满足上述查询条件的商品(product_name)只有“打孔器”。

把上述查询条件原封不动地写入WHERE子句中,得到的SELECT语句似乎就可以满足需求了.

select product_name,product_type,regist_date from Product whereproduct_type='办公用品' and regist_date='2021-1-15' or regist_date='2021-10-11';

执行结果

不想要的T恤衫、菜刀和叉子也被选出来了,真是头疼呀。到底为什么会得到这样的结果呢?这是AND运算符优先于OR运算符所造成的。

这和想要指定的查询条件并不相符。想要优先执行OR运算符时,可以使用半角括号( )将OR运算符及其两侧的查询条件括起来。

select product_name,product_type,regst_date from Product whereproduct_type='办公用品' and (regist_date='2021-07-15' or regist_date='2021-09-13');

执行结果

这样就选取出了想要得到的“打孔器”。

AND运算符的优先级高于OR运算符。想要优先执行OR运算符时可以使用括号。

逻辑运算符和真值

逻辑运算符对比较运算符等返回的真值进行操作。AND运算符两侧的真值都为真时返回真,除此之外都返回假。OR运算符两侧的真值只要有一个不为假就返回真,只有当其两侧的真值都为假时才返回假。NOT运算符只是单纯的将真转换为假,将假转换为真。真值表(truth table)就是对这类操作及其结果进行的总结.

在SELECT语句的WHERE子句中,通过AND运算符将两个查询条件连接起来时,会查询出这两个查询条件都为真的记录。通过OR运算符将两个查询条件连接起来时,会查询出某一个查询条件为真或者两个查询条件都为真的记录。在条件表达式中使用NOT运算符时,会选取出查询条件为假的记录(反过来为真)。

真值表只是使用一个逻辑运算符时得到的结果,但即使使用两个以上的逻辑运算符连接三个以上的查询条件,通过反复进行逻辑运算求出真值,不论多复杂的条件也可以得到相应的结果。

根据之前例子中的查询条件“商品种类为办公用品”,并且“登记日期是2009年9月11日或者2009年9月20日”(product_type=’办公用品’ AND(regist_date='2009-09-11' OR regist_date='2009-09-20'))做成的真值表。

通过创建真值表,无论多复杂的条件,都会更容易理解。
逻辑积与逻辑和

真值表中的真变为1、假变为0,意外地得到了下述规则。

NOT运算符并没有什么特别的改变,但是AND运算的结果与乘法运算(积), OR运算的结果与加法运算(和)的结果却是一样的。因此,使用AND运算符进行的逻辑运算称为逻辑积,使用OR运算符进行的逻辑运算称为逻辑和。

含有NULL时的真值

我们来看一下Product(商品)表,商品“叉子”和“圆珠笔”的进货单价(purchase_price)为NULL。那么,对这两条记录使用查询条件purchase_price=2800(进货单价为2800日元)会得到什么样的真值呢?如果结果为真,则通过该条件表达式就可以选取出“叉子”和“圆珠笔”这两条记录。但是在之前介绍“不能对NULL使用比较运算符”.

那结果会为假吗?实际上结果也不是假。如果结果为假,那么对其进行否定的条件NOT purchase_price=2800(进货单价不是2800日元)的结果应该为真,也就能选取出这两条记录了(因为假的对立面为真),但实际结果却并不是这样。

既不是真也不是假,那结果到底是什么呢?其实这是SQL中特有的情况。这时真值是除真假之外的第三种值——不确定(UNKNOWN)。一般的逻辑运算并不存在这第三种值。SQL之外的语言也基本上只使用真和假这两种真值。与通常的逻辑运算被称为二值逻辑相对,只有SQL中的逻辑运算被称为三值逻辑。

Product表中设置NOT NULL约束的原因

原本只有4行的真值表,如果要考虑NULL的话就会像表2-6那样增加为3×3=9行,看起来也变得更加繁琐,考虑NULL时的条件判断也会变得异常复杂,这与我们希望的结果大相径庭。因此,数据库领域的有识之士们达成了“尽量不使用NULL”的共识。

这就是为什么在创建Product表时要给某些列设置NOT NULL约束(禁止录入NULL)的缘故。

练习题

编写一条SQL语句,从Product(商品)表中选取出“登记日期(regist_date)在2009年4月28日之后”的商品。查询结果要包含product_name和regist_date两列。

请说出对Product表执行如下3条SELECT语句时的返回结果。

select*from Product where purchase_price=null;
select*from Product where purchase_price<> null;
select*from Product where product_name>null;

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多