zoukankan      html  css  js  c++  java
  • 6 SQL 函数、谓词、CASE表达式

    6 函数、谓词、CASE表达式

    6-1 各种各样的函数

    /*

    所谓函数,就是输入某一值得到相应输出结果的功能。输入值称为参数(parameter),输出值称为返回值。

    函数大致可以分为以下几种 :

    算术函数 :用来进行数值计算的函数

    字符串函数 :用来进行字符串操作的函数

    日期函数 : 用来进行日期操作的函数

    转换函数 :用来转换数据类型和值的函数

    聚合函数 :用来进行数据聚合的函数

    */

    算术函数

    -- DDL :创建表

    CREATE TABLE sampleMath (

    m NUMERIC (10, 3),

    n INTEGER,

    p INTEGER

    );

    -- DML : 插入数据

    START TRANSACTION;

    INSERT INTO sampleMath(m, n, p) VALUES (500, 0, NULL);

    INSERT INTO sampleMath(m, n, p) VALUES (-180, 0, NULL);

    INSERT INTO sampleMath(m, n, p) VALUES (NULL, NULL, NULL);

    INSERT INTO sampleMath(m, n, p) VALUES (NULL, 7, 3);

    INSERT INTO sampleMath(m, n, p) VALUES (NULL, 5, 2);

    INSERT INTO sampleMath(m, n, p) VALUES (NULL, 4, NULL);

    INSERT INTO sampleMath(m, n, p) VALUES (8, NULL, 3);

    INSERT INTO sampleMath(m, n, p) VALUES (2.27, 1, NULL);

    INSERT INTO sampleMath(m, n, p) VALUES (5.555, 2, NULL);

    INSERT INTO sampleMath(m, n, p) VALUES (NULL, 1, NULL);

    INSERT INTO sampleMath(m, n, p) VALUES (8.67, NULL, NULL);

    COMMIT;

    SELECT * FROM sampleMath;

    ABS是计算绝对值的函数。绝对值(absolute value) 就是不考虑数值的符合,表示一个数到原点距离的数值。简单来讲,绝对值的计算方法就是:0和正数的绝对值就是其本身,负数的绝对值就是去掉符号后的结果。

    通过上述结果我们可以发现,ABS函数的参数为NULL时,结果也是NULL。并非只有ABS函数如此,其实绝大多数函数对于NULL的结果都是NULL。

    MOD是计算除法余数(剩余)的函数,是modulo的简称。例如,7/3的余数是1,因此MOD(7,3)的结果也是1.由于小数计算中并没有余数的概念,所以只能对整数类型的列使用MOD函数。

    这里有一点需要大家注意。主流DBMS都支持MOD函数,只有SQL Server不支持该函数。

    ROUND函数用来进行四舍五入操作。

    绝对值、余数、四舍五入、

    -- ABS(数值)

    SELECT m, ABS(m) AS abs_col FROM sampleMath;

    -- MOD(被除数,除数)      主流的DBMS都支持MOD函数,只有SQL Server不支持该函数。

    SELECT n, p, MOD(n, p) AS mod_col FROM sampleMath;

    -- SQL Server特殊处理方法

    SELECT n, p, n % p AS mod_col FROM sampleMath;

    -- ROUND(对象数值, 保留小数的位数)

    SELECT m , n, ROUND(m, n) AS round_col FROM sampleMath;

    字符串函数

    -- DDL :创建表

    CREATE TABLE sampleStr (

    str1 VARCHAR(40),

    str2 VARCHAR(40),

    str3 VARCHAR(40)

    );

    -- DML : 插入数据

    START TRANSACTION;

    INSERT INTO sampleStr(str1, str2, str3) VALUES ('opt', 'rt', NULL);

    INSERT INTO sampleStr(str1, str2, str3) VALUES ('abc', 'def', NULL);

    INSERT INTO sampleStr(str1, str2, str3) VALUES ('山田', '太郎', '是我');

    INSERT INTO sampleStr(str1, str2, str3) VALUES ('aaa', NULL, NULL);

    INSERT INTO sampleStr(str1, str2, str3) VALUES (NULL, 'xyz', NULL);

    INSERT INTO sampleStr(str1, str2, str3) VALUES ('@!#$%', NULL, NULL);

    INSERT INTO sampleStr(str1, str2, str3) VALUES ('ABC', NULL, NULL);

    INSERT INTO sampleStr(str1, str2, str3) VALUES ('aBC', NULL, NULL);

    INSERT INTO sampleStr(str1, str2, str3) VALUES ('abc太郎', 'abc', 'ABC');

    INSERT INTO sampleStr(str1, str2, str3) VALUES ('micmic', 'i', 'I');

    COMMIT;

    SELECT * FROM sampleStr;

    拼接(||)、字符串长度、小(大)写转换、字符串的替换、字符串截取

    -- oracle db2 postgresql

    SELECT str1, str2, str1 || str2 AS str_concat FROM sampleStr;

    SELECT str1, str2, str3, str1 || str2 || str3 AS str_concat FROM sampleStr;

    -- SQL SERVER

    SELECT str1, str2, str3, str1 + str2 + str3 AS str_concat FROM sampleStr;

    -- mysql

    SELECT str1, str2, str3, CONCAT(str1, str2, str3) AS str_concat FROM sampleStr;

    -- LENGTH(字符串)   该函数无法在SQL Server中使用

    SELECT str1, LENGTH(str1) AS len_str FROM sampleStr;

    -- SQL SERVER

    SELECT str1, LEN(str1) AS len_str FROM sampleStr;

    -- 对1个字节使用LENGTH函数有可能得到2字节以上的结果

    -- LOWER(字符串)    UPPER(字符串)

    SELECT str1, LOWER(str1) AS low_str FROM sampleStr WHERE str1 IN ('ABC', 'aBC', 'abc', '山田');

    -- REPLACE(对象字符串,替换前的字符串,替换后的字符串)

    SELECT str1, str2, str3, REPLACE(str1,str2,str3) AS rep_str FROM sampleStr;

    -- SUBSTRING(对象字符串 FROM 截取的起始位置 FOR 截取的字符数)   此函数为postgresql和mysql专用语法

    -- postgresql和mysql

    SELECT str1, SUBSTRING(str1 FROM 3 FOR 2) AS sub_str FROM sampleStr;

    -- 特定的sql

    -- SUBSTRING(对象字符串, 截取的起始位置, 截取的字符串)    sql SERVER专用

    -- SUBSTR(对象字符串, 截取的起始位置,截取的字符数)     oracle   db2专用

    SELECT str1 SUBSTRING(str1, 3, 2) AS sub_str FROM sampleStr;

    SELECT str1 SUBSTR(str1, 3, 2) AS sub_str FROM sampleStr;

    -- UPPER(字符串)

    SELECT str1, UPPER(str1) AS up_str FROM sampleStr WHERE str1 IN ('ABC', 'aBC', 'abc', '山田');

    -- UPPER(字符串)

    SELECT str1, UPPER(str1) AS up_str FROM sampleStr WHERE str1 IN ('ABC', 'aBC', 'abc', '山田');

    日期函数、当前日期、当前时间、当前日期和时间、截取日期元素

    -- 使用于postgresql和mysql      无法在sql server 中执行,此外Oracle和db2中的语法略有不同

    SELECT CURRENT_DATE;

    -- sql SERVER

    SELECT CAST(CURRENT_TIMESTAMP AS DATE) AS CUR_DATE;

    -- oracle

    SELECT CURRENT_DATE FROM dual;

    -- db2

    SELECT CURRENT_DATE FROM SYSIBM.SYSDUMMY1;

    -- 使用于postgresql和mysql      无法在sql server 中执行,此外Oracle和db2中的语法略有不同

    SELECT CURRENT_TIME;

    -- 使用于postgresql和mysql      无法在sql server 中执行,此外Oracle和db2中的语法略有不同

    SELECT CURRENT_TIMESTAMP;

    -- EXTRACT(日期元素 FROM 日期)   postgresql 和 mysql   sql server 也无法使用该函数

    SELECT CURRENT_TIMESTAMP,

    EXTRACT(YEAR FROM CURRENT_TIMESTAMP) AS year,

    EXTRACT(MONTH FROM CURRENT_TIMESTAMP) AS month,

    EXTRACT(DAY FROM CURRENT_TIMESTAMP) AS day,

    EXTRACT(HOUR FROM CURRENT_TIMESTAMP) AS hour,

    EXTRACT(MINUTE FROM CURRENT_TIMESTAMP) AS minute,

    EXTRACT(SECOND FROM CURRENT_TIMESTAMP) AS second;

    “转换”这个词的含义非常广泛,在SQL中主要有两层意思。一是数据类型的转换,简称为“类型转换”,在英语中称为cast。另一层意思是值的转换。

    转换函数

    -- CAST(转换前的值 AS 想要转换的数据类型)

    -- CAST(转换前的值 AS 想要转换的数据类型)

    -- sql server   postresql

    SELECT CAST('0001' AS INTEGER) AS int_col;

    -- mysql

    SELECT CAST('0001' AS SIGNED INTEGER) AS int_col;

    -- oracle

    SELECT CAST('0001' AS INTEGER) AS int_col FROM DUAL;

    -- db2

    SELECT CAST('0001' AS INTEGER) AS int_col FROM SYSIBM.SYSDUMMY1;

    -- SQL SERVER     POSTGRESQL   mysql

    SELECT CAST('2009-12-14' AS DATE) AS date_col;

    -- oracle

    SELECT CAST('2009-12-14' AS DATE) AS date_col FROM DUAL;

    -- db2

    SELECT CAST('2009-12-14' AS DATE) AS date_col FROM SYSIBM.SYSDUMMY1;

    -- COALESCE(数据1, 数据2, ...)

    -- sql server   postgresql  mysql

    SELECT COALESCE(NULL, 1) AS col_1,

    COALESCE(NULL, 'test', NULL) AS col_2,

    COALESCE(NULL, NULL, '2009-11-01') AS col_3;

    -- oracle

    SELECT COALESCE(NULL, 1) AS col_1,

    COALESCE(NULL, 'test', NULL) AS col_2,

    COALESCE(NULL, NULL, '2009-11-01') AS col_3 FROM DUAL;

    -- db2

    SELECT COALESCE(NULL, 1) AS col_1,

    COALESCE(NULL, 'test', NULL) AS col_2,

    COALESCE(NULL, NULL, '2009-11-01') AS col_3 FROM SYSIBM.SYSDUMMY1;

    -- 有疑问

    SELECT * FROM samplestr;

    SELECT COALESCE(str2, 'NULL') FROM samplestr;

    COALESCE是SQL特有的函数。该函数会返回可变参数中左侧开始第一个不是NULL的值。参数个数是可变的,因此可以根据需要无限增加。

    6-2 谓词

    本节将会和大家一起学习SQL的抽出条件中不可或缺的工具—谓词(predicate)。

    谓词,通俗来讲就是函数中的一种,是需要满足特定条件的函数。该条件就是“返回值是真值”。对通常函数来说,返回值有可能是数字、字符串或者日期等等,但是谓词的返回值全部是真值(TRUE/FALSE/UNKNOWN)。这也是谓词和函数的最大区别。

    LIKE/BETWEEN/IS NULL、IS NOT NULL/IN/EXISTS

    LIKE谓词更加模糊一些,当需要进行字符串的部分一致查询时需要使用该谓词。

    部分一致大体可以分为前方一致、中间一致和后方一致三种类型。

    像这样不适用“=”来指定条件字符串,而以字符串中是否包含该条件的规则为基础的查询称为“模式匹配”。其中的模式也就是前面提到的“规则”。

    其中“%”是代表“0字符以上的任意字符串”的特殊符号。

    此外,我们还可以使用 _ (下划线) 来代替“%”,与%不同的是其代表了“任意1个字符”。

    LIKE谓词-字符串的部分查询

    -- DDL :创建表

    CREATE TABLE sampleLike (

    strcol VARCHAR(6) NOT NULL,

    PRIMARY KEY (strcol)

    );

    -- DML :插入数据

    START TRANSACTION;

    INSERT INTO sampleLike (strcol) VALUES ('abcddd');

    INSERT INTO sampleLike (strcol) VALUES ('dddabc');

    INSERT INTO sampleLike (strcol) VALUES ('abdddc');

    INSERT INTO sampleLike (strcol) VALUES ('abcdd');

    INSERT INTO sampleLike (strcol) VALUES ('ddabc');

    INSERT INTO sampleLike (strcol) VALUES ('abcddd');

    INSERT INTO sampleLike (strcol) VALUES ('abddc');

    COMMIT;

    SELECT * FROM sampleLike WHERE strcol LIKE 'ddd%';

    SELECT * FROM sampleLike WHERE strcol LIKE '%ddd%';

    SELECT * FROM sampleLike WHERE strcol LIKE '%ddd';

    SELECT * FROM sampleLike WHERE strcol LIKE 'abc__';

    SELECT * FROM sampleLike WHERE strcol LIKE 'abc___';

    使用BETWEEN可以进行范围查询。

    BETWEEN的特点就是结果中会包含100和1000这两个临界值。如果不想让结果中包含临界值,那就必须使用<(小于)和>(大于)。

    BETWEEN谓词-范围查询

    SELECT shohin_mei, hanbai_tanka FROM shohin WHERE hanbai_tanka BETWEEN 100 AND 1000;

    SELECT shohin_mei, hanbai_tanka FROM shohin WHERE hanbai_tanka > 100 AND hanbai_tanka < 1000;

    为了选取出某些值为NULL的列的数据,不能使用=,而只能使用特定的谓词IS NULL。

    与之相反,想要选取NULL以外的数据时,需要使用IS NOT NULL。

    IS NULL、IS NOT NULL-判断是否为NULL

    SELECT shohin_mei, shiire_tanka FROM shohin WHERE shiire_tanka IS NULL;

    SELECT shohin_mei, shiire_tanka FROM shohin WHERE shiire_tanka IS NOT NULL;

    需要注意的是,在使用IN和NOT IN时是无法选取出NULL数据的。NULL终究还是需要使用IS NULL和IS NOT NULL来进行判断。

    IN谓词-OR的简便用法

    SELECT shohin_mei, shiire_tanka FROM shohin WHERE shiire_tanka = 300 OR shiire_tanka = 500 OR shiire_tanka = 5000;

    SELECT shohin_mei, shiire_tanka FROM shohin WHERE shiire_tanka IN (300, 500, 5000);

    SELECT shohin_mei, shiire_tanka FROM shohin WHERE shiire_tanka NOT IN (300, 500, 5000);

    IN谓词(NOT IN谓词)具有其他谓词所没有的使用方法。那就是可以使用子查询作为其参数来使用。子查询就是SQL内部生成的表。因此也可以说“能够将表作为IN的参数”。同理,我们还可以说“能够将视图作为IN的参数”。

    使用子查询作为IN谓词的参数

    CREATE TABLE tenpoShohin (

    tenpo_id CHAR(4) NOT NULL,

    ten_mei VARCHAR(200) NOT NULL,

    shohin_id CHAR(4) NOT NULL,

    suryo INTEGER NOT NULL,

    PRIMARY KEY (tenpo_id, shohin_id)

    );

    -- 该CREATE TABLE语句的特点是指定了2列作为主键(primary key)。这样做的目的当然还是为了区分表中每一行数据。

    START TRANSACTION;

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000A', '东京', '0001', 30);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000A', '东京', '0002', 50);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000A', '东京', '0003', 15);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000B', '名古屋', '0002', 30);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000B', '名古屋', '0003', 120);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000B', '名古屋', '0004', 20);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000B', '名古屋', '0006', 10);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000B', '名古屋', '0007', 40);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000C', '大阪', '0003', 20);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000C', '大阪', '0004', 50);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000C', '大阪', '0006', 90);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000C', '大阪', '0007', 70);

    INSERT INTO tenpoShohin (tenpo_id, ten_mei, shohin_id, suryo) VALUES ('000D', '福冈', '0001', 100);

    COMMIT;

    SELECT shohin_id FROM tenpoShohin WHERE tenpo_id = '000C';

    SELECT shohin_mei, hanbai_tanka FROM shohin WHERE shohin_id IN (SELECT shohin_id FROM tenpoShohin WHERE tenpo_id = '000C');

    SELECT shohin_mei, hanbai_tanka FROM shohin WHERE shohin_id NOT IN (SELECT shohin_id FROM tenpoShohin WHERE tenpo_id = '000A');

    实际上,由于各个商店销售的商品都在不断发生变化,所以tenpoShohin表内大阪店销售的商品也会发生变化。如果SELECT语句中没有使用子查询的话,一旦商品发生了改变,那么SELECT语句也不得不进行修改。而且这样的修改工作会变得没完没了。

    反之,如果在SELECT语句中使用了子查询,那么即使数据发生了变更,还可以继续使用同样的SELECT语句。这样也就减少了我们的常规作业(单纯的重复操作)。

    像这样可以完美应对数据变更的程序称为“易维护程序”,或者“免维护程序”。这也是系统开发中需要重点考虑的部分。希望大家在开始学习编程时,就能够有意识地编写易于维护的代码。

    IN的否定形式NOT IN同样可以使用子查询作为参数,其语法也和IN完全一样。

    EXIST谓词,难点,了解即可。

    一言以弊之,谓词的作用就是“判断是否存在满足某种条件的记录”。如果存在这样的记录就返回真(TRUE),如果不存在就返回假(FALSE)。EXIST(存在)谓词的主语是“记录”。

    EXIST谓词

    SELECT shohin_mei, hanbai_tanka FROM shohin AS S

       WHERE EXISTS (SELECT * FROM tenpoShohin AS TS WHERE TS.tenpo_id = '000C' AND TS.shohin_id = S.shohin_id);

    SELECT shohin_mei, hanbai_tanka FROM shohin AS S

       WHERE EXISTS (SELECT 1 FROM tenpoShohin AS TS WHERE TS.tenpo_id = '000C' AND TS.shohin_id = S.shohin_id);

    SELECT shohin_mei, hanbai_tanka FROM shohin AS S

       WHERE EXISTS (SELECT 2 FROM tenpoShohin AS TS WHERE TS.tenpo_id = '000C' AND TS.shohin_id = S.shohin_id);

    SELECT shohin_mei, hanbai_tanka FROM shohin AS S

       WHERE EXISTS (SELECT 3 FROM tenpoShohin AS TS WHERE TS.tenpo_id = '000C' AND TS.shohin_id = S.shohin_id);

    SELECT shohin_mei, hanbai_tanka FROM shohin AS S

       WHERE NOT EXISTS (SELECT * FROM tenpoShohin AS TS WHERE TS.tenpo_id = '000A' AND TS.shohin_id = S.shohin_id);

    法则6-1

    通常指定关联子查询作为EXIST的参数。

    法则6-2

    作为EXIST参数的子查询中经常会使用SELECT *。

    6-3 CASE表达式

    本节将要学习的CASE表达式,和“1+1”或者“120/4”这样的表达式一样,是一种进行运算的功能。这就意味着CASE表达式也是函数的一种。它是SQL中数一数二的重要功能,希望大家能够在这里好好学习掌握。

    CASE表达式,正如CASE(情况)这个词的含义所示,是在区分情况时使用的。这种情况的区分在程序中通常称为“(条件)分歧”。

    CASE表达式的语法分为简单CASE表达式和搜索CASE表达式两种。

    WHEN子句中的<判断表达式>就是类似“列=值”这样,返回值为真值(TRUE/FALSE/UNKNOWN)的表达式。我们可以将其看作使用=、!=或者LIKE、BETWEEN等谓词编写出来的表达式。

    CASE表达式会从对最初的WHEN子句中的<判断表达式>进行判断开始执行。所谓“判断”,就是要调查该表达式的真值是什么。如果结果为真(TRUE),那么就返回TRUE子句中的表达式,CASE表达式的执行到此为止。如果结果不为真,那么就跳转到下一条WHEN子句的判断之中。如果直到最后的WHEN子句为止返回结果都不为真,那么就会返回ELSE中的表达式,执行终止。

    从CASE表达式名称中的“表达式”我们也能看出来,上述这些整体构成了一个表达式。并且由于表达式最终会返回一个值,因此CASE表达式在SQL语句执行时,也会转化为一个值。

    ELSE子句也可以省略不写,这时会自动默认为“ELSE NULL”。但为了防止有人漏写,所以还是希望大家能够写明ELSE子句。

    此外,CASE表达式最后的“END”是不能省略的。

    CASE表达式的便利之处就在于它是一个表达式。之所以这么说,是因为表达式可以书写在任意位置。

    CASE表达式的使用方法

    /*

    CASE WHEN <判断表达式> THEN <表达式>

    WHEN <判断表达式> THEN <表达式>

    WHEN <判断表达式> THEN <表达式>

    ELSE <表达式>

    END

    */

    SELECT shohin_mei,

       CASE WHEN shohin_bunrui = '衣服' THEN 'A:' || shohin_bunrui

             WHEN shohin_bunrui = '办公用品' THEN 'B:' || shohin_bunrui

             WHEN shohin_bunrui = '厨房用具' THEN 'C:' || shohin_bunrui

             ELSE NULL

       END AS abc_shohin_bunrui FROM shohin;

    SELECT shohin_mei,

       CASE WHEN shohin_bunrui = '衣服' THEN CONCAT('A:', shohin_bunrui)

             WHEN shohin_bunrui = '办公用品' THEN CONCAT('B:', shohin_bunrui)

             WHEN shohin_bunrui = '厨房用具' THEN CONCAT('C:', shohin_bunrui)

             ELSE NULL

       END AS abc_shohin_bunrui FROM shohin;

    SELECT shohin_bunrui, SUM(hanbai_tanka) AS sum_tanka FROM shohin GROUP BY shohin_bunrui;

    SELECT SUM(CASE WHEN shohin_bunrui = '衣服' THEN hanbai_tanka ELSE 0 END) AS sum_tanka_ihuku,

       SUM(CASE WHEN shohin_bunrui = '厨房用具' THEN hanbai_tanka ELSE 0 END) AS sum_tanka_kitchen,

       SUM(CASE WHEN shohin_bunrui = '办公用品' THEN hanbai_tanka ELSE 0 END) AS sum_tanka_jimu FROM shohin;

    法则6-3

    虽然CASE表达式中的ELSE子句可以省略,但还是希望大家不要省略。

    法则6-4

    CASE表达式中的END不能省略。

  • 相关阅读:
    ppt中调整图片位置
    如何理解 Google Protocol Buffer
    g++: error: unrecognized command line option ‘-std=C++11’
    手把手教你如何加入到github的开源世界!
    redis
    maven
    Spring----注释----开启Annotation <context:annotation-config> 和 <context:component-scan>诠释及区别
    JMX学习笔记(一)-MBean
    Redis学习笔记2-redis管道(pipeline)
    Redis学习笔记1-java 使用Redis(jedis)
  • 原文地址:https://www.cnblogs.com/yly-blog/p/9820408.html
Copyright © 2011-2022 走看看