ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

SQL学习&实战笔记

2021-02-28 18:01:42  阅读:225  来源: 互联网

标签:实战 cust 笔记 vend SQL prod id SELECT name


前言

分享SQL学习过程,归纳重点,记录其在数据仓库(ETL)开发中的应用及本人所踩过的坑。

一、MySQL

(一)SQL必知必会

1. 了解SQL

(1)数据库(database), 数据库管理系统(DBMS)
(2)表(table),mysql中,表的含义是存储数据的结构化文件。
(3)列(column),列表示表中的一个字段。
(4)行(row),行表示表中的一条记录。
(5)主键(primary key),主键是一个字段或多个字段的组合(联合主键),用来唯一标识表中的一条记录。
(6)SQL语言分类,数据查询语言(DQL,如SELECT,FROM,WHERE);数据操纵语言(DML,如INSERT,UPDATE,DELETE);数据定义语言(DDL,如CREATE TABLE);数据控制语言(DCL,如GRANT)。

2. 检索数据

(1)DISTINCT,指示查询只返回不同的值。
注意点1:不能部分使用DISTINCT,DISTINCT关键字作用于所有的列,不仅仅是跟在其后面的那一列。例如,你指定如下查询,因为指定的两列不完全相同,所以所有列都会被检索出来。

SELECT DISTINCT
    vend_id
   ,prod_price
FROM Products;

注意点2:DISTINCT因为限制较多(不能和聚合函数并列使用)且性能较差,在数据仓库中Hive SQL通常不用DISTINCT,而用GROUP BY去重

(2)LIMIT指定返回的行数,LIMIT带的OFFSET指定从哪里开始。
注意点1:第0行,第一个被检索的行是第0行,而不是第1行。因此如下查询会检索第2行,而不是第1行。

SELECT
    prod_name
FROM Product
LIMIT 1 OFFSET 1;

3. 排序检索数据

(1)ORDER BY,默认是ASC升序排列,降序需要指定DESC关键字。
注意点1:如果想在多个列上进行降序排序,必须对每一列指定DESC关键字。

SELECT
    prod_id
   ,prod_price
   ,prod_name
FROM Products
# ORDER BY prod_price;
ORDER BY prod_price DESC, prod_name DESC;

4. 过滤数据

(1)WHERE子句操作符

操作符中文含义
=等于
<> / !=不等于
<小于
<=小于等于
!<不小于
>大于
>=大于等于
!>不大于
BETWEEN在两个指定值之间
NULL为NULL值

(2)NULL,过滤字段为NULL时用IS,不用等于号。

WHERE prod_price IS NULL

5. 高级数据过滤

(1)AND在求值过程中优先级更高,最好使用小括号对操作符进行明确分组,避免与OR等连用时执行顺序错误。

SELECT
    prod_name
   ,prod_price
FROM Products
WHERE (vend_id = 'DLL01' OR vend_id = 'BRS01') AND prod_price >= 10;
# 不加小括号会先执行 vend_id='BRS01' AND prod_price >= 10

(2)IN操作符,在WHERE子句中用来指定要匹配值得清单,功能与OR相当,但执行更快。

SELECT
    prod_name
   ,prod_price
FROM Products
WHERE vend_id IN ('DLL01', 'BRS01');
# WHERE (vend_id='DLL01' OR vend_id='BRS01')

6. 用通配符进行过滤(耗时长,需考虑性能问题)

(1)%匹配多个字符

SELECT
    prod_name
FROM Products
WHERE prod_name LIKE 'Fish%';

输出
prod_name
------------------------
Fish bean bag toy

(2)_匹配单个字符

SELECT
    prod_name
FROM Products
WHERE prod_name LIKE '__ inch teddy bear';

输出
prod_name
------------------------
12 inch teddy bear
18 inch teddy bear

(3)[]匹配指定位置的1个字符,如下匹配[JM]中J或者M

SELECT
    cust_contact
FROM Customers
WHERE cust_contact LIKE '[JM]%'
ORDER BY cust_contact;

输出
cust_contact
------------------------
Jim Jones
John Smith
Michelle Green

7. 创建计算字段

(1)常用操作符

操作符说明
+
-
*
/

(2)执行算术计算,汇总订单物品总价。

SELECT
    prod_id
   ,quantity
   ,item_price
   ,quantity * item_price    AS expanded_price
FROM OrderItems
WHERE order_num = 20008;

8. 使用函数处理数据

(1)常用文本处理函数

函数说明
LEFT() (或使用子字符串函数)返回字符串左边的字符
RIGHT()(或使用子字符串函数)返回字符串右边的字符
LENGTH()(也使用DATALENGTH()或LEN())返回字符串长度
LOWER()(Access使用LCASE())将字符串转为小写
UPPER()(Access使用UCASE())将字符串转为大写
LTRIM()去左边空格(比如:字段首)
RTRIM()去右边空格(比如:字段末)

(2)常用数值处理函数

函数说明
ABS()返回一个数的绝对值
PI()返回圆周率
SQRT()返回平方根

9. 汇总数据

(1)SQL聚集函数

函数说明
AVG()返回某列的平均值
COUNT()返回某列的行数
MAX()返回某列的最大值
MIN()返回某列的最小值
SUM()返回某列之和

注意点1:AVG(),MAX(),MIN()和SUM()函数会忽略列值为NULL的行。
注意点2:使用COUNT(1)和COUNT(*)对表中的数据进行计算,不管表中列包含的是空值(NULL)还是非空值,都会计算进来。使用COUNT(column)进行计算时,会忽略NULL值。

# COUNT(*)
SELECT
    COUNT(*)    AS num_cust
FROM Customers;

输出
num_cust
------------------------
5

# COUNT(column)
SELECT
    COUNT(cust_email)    AS num_cust
FROM Customers;

输出
num_cust
------------------------
3

10. 分组数据

(1)HAVING和WHERE的区别。WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。WHERE排除的行不包括在分组中,这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。

SELECT
    vend_id
   ,COUNT(*)    AS num_prods
FROM Products
WHERE prod_price >= 4
GROUP BY vend_id
HAVING COUNT(*) >= 2;

(2)SELECT子句顺序,在写SELECT语句时必须遵循如下次序。

子句说明
SELECT要返回的列或表达式
FROM从中检索数据的表
WHERE行级过滤
GROUP BY分组说明
HAVING组级过滤
ORDER BY输出排序顺序

11. 使用子查询(需根据实际情况采用,使用联结通常性能更好)

(1)如下,把第一个查询变为子查询。

# 第一个查询
SELECT
    order_num
FROM OrderItems
WHERE prod_id = 'RGAN01';

输出
order_num
------------------------
20007
20008

# 第二个查询
SELECT
    cust_id
FROM Orders
WHERE order_num IN (20007, 20008);

输出
cust_id
------------------------
1000000004
1000000005

# 把第一个查询变为子查询
SELECT
    cust_id
FROM Order_num IN
(
    SELECT
        order_num
    FROM OrderItems
    WHERE prod_id = 'RGAN01'
);

输出
cust_id
------------------------
1000000004
1000000005

12. 联结表

(1)WHERE关联

SELECT
    vend_name
   ,prod_name
   ,prod_price
FROM Vendors, Products
WHERE Vendors.vend_id = Products.vend_id;

(2)笛卡尔积,由没有联结条件的表关系返回的结果为笛卡尔积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。

SELECT
    vend_name
   ,prod_name
   ,prod_price
FROM Vendors, Products;

(3)内联结(取交集)

SELECT
    vend_name
   ,prod_name
   ,prod_price
FROM Vendors
INNER JOIN Products
ON Vendors.vend_id = Products.vend_id;

13. 创建高级联结

(1)外联结 LEFT OUTER JOIN,左表所有行匹配右表。
(2)全联结 FULL OUTER JOIN,取全部,包含不关联的行。

14. 组合查询

(1)UNION和UNION ALL,UNION会自动去除重复的行,UNION ALL不去除重复的行。

15. 插入数据

(1)插入检索出的数据

INSERT INTO Customers (cust_id, cust_name, cust_address)
VALUES ('1006', 'Toy Land', '123 Any Street');

(2)从一个表复制到另一个表

CREATE TABLE CustCopy AS
SELECT
*
FROM Customers;

16. 更新删除数据

(1)更新数据,SET命令用来将新值赋给被更新的列。

UPDATE Customers
SET cust_email = 'kim@thetoystore.com'
WHERE cust_id = '1005';

(2)删除数据,如下操作为删除cust_id = '1006’的行。DELETE不删除表结构,如果需要删除表中的所有行,使用TRUNCATE TABLE速度更快(因为不记录数据的变动)。

DELETE FROM Customers
WHERE cust_id = '1006';

TRUNCATE TABLE Customers;

(3)删除表

# 删除数据同时删除表结构
DROP TABLE Customers;

17. 创建和操纵表

(1)创建表

CREATE TABLE Products
(
    prod_id       CHAR(10)         NOT NULL
   ,vend_id       CHAR(10)         NOT NULL
   ,prod_name     CHAR(254)        NOT NULL
   ,prod_price    DECIMAL(8, 2)    NOT NULL
   ,prod_desc     VARCHAR(1000)    NULL
);

(2)更新表

ALTER TABLE Vendors ADD vend_phone CHAR(20);
ALTER TABLE Vendors DROP COLUMN vend_phone;

18. 使用视图

(1)原理,视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询。
(2)缺点,因为视图不包含数据,所以每次使用视图时,都必须处理查询执行需要的所有检索,如果用多个联结和过滤创建了复杂的视图或者嵌套了视图,性能可能下降得很厉害。
(3)作用,视图提供了一种封装SELECT语句的层次,可用来简化数据处理提高复用率,重新格式化或保护基础数据。

# 查询订购了产品'RCAN01'的顾客
SELECT
    cust_name
   ,cust_contact
FROM Customers, Orders, OrderItems
WHERE Customers.cust_id = Orders.cust_id
AND OrderItems.order_num = Orders.order_num;
AND prod_id = 'RCAN01';

# 把上述查询封装成视图(虚拟表)以便复用
CREATE VIEW ProductCustomers AS
SELECT
    cust_name
   ,cust_contact
   ,prod_id
FROM Customers, Orders, OrderItems
WHERE Customers.cust_id = Orders.cust_id
AND OrderItems.order_num = Orders.order_num;

# 利用视图查询订购了产品'RCAN01'的顾客
SELECT
    cust_name
   ,cust_contact
FROM ProductCustomers
WHERE prod_id = 'RCAN01';
# 增加一个'()'的格式效果
SELECT
    RTRIM(vend_name) + '(' + RTRIM(vend_country) + ')'    AS vend_title
FROM Vendors
ORDER BY vend_name;

输出
vend_title
------------------------
Bear Emporium (USA)
Bears R US (USA)
Fun and Games (England)

# 如果经常需要这个格式效果,可以创建视图来使用
CREATE VIEW VendorLocations AS
SELECT
    RTRIM(vend_name) + '(' + RTRIM(vend_country) + ')'    AS vend_title
FROM Vendors;

# 查询增加'()'的格式效果的视图
SELECT
    vend_title
FROM VendorLocations;

19. 使用存储过程

(1)存储过程就是为以后使用而保存的一条或多条SQL语句。可将其视为批文件,虽然其作用不仅限于批处理。
(2)执行存储过程

# 将一个新产品添加到Producs表中,如下存储过程有四个参数:供应商ID,产品名,价格和描述
EXECUTE AddNewProduct
(
    'JTS01'
   ,'Stuffed Eiffel Tower'
   ,6.49
   ,'Plush stuffed toy with the text La Tour Eiffel in red' 
);

(3)创建存储过程

# Oracle版本,对邮件发送清单中具有邮件地址的顾客进行计算
CREATE PROCEDURE MailingListCount
(
    ListCount OUT INTEGER
)
IS v_rows INTEGER;

BEGIN
    SELECT
        COUNT(*) INTO v_rows
    FROM Customers
    WHERE NOT cust_email IS NULL;
    ListCount := v_rows;
END;

# 调用
var ReturnValue NUMBER
EXEC MailingListCount(:ReturnValue);
SELECT ReturnValue;

20. 管理事务处理

(1)使用事务处理,通过确保成批的SQL操作要么完全执行,要么完全不执行,来维护数据库的完整性。

21. 使用游标

(1)游标(sursor)是一个存储在DBMS服务器上的数据库查询,它不是一条SELECT语句,而是被该语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。
(2)创建游标

# 创建游标来检索没有电子邮件地址的所有顾客
DECLARE CustCursor CURSOR
FOR
SELECT
    cust_name
FROM Customers
WHERE cust_email IS NULL;

# Oracle版本
DECLARE CustCursor CURSOR
IS
SELECT
    cust_name
FROM Customers
WHERE cust_email IS NULL;

(3)使用游标

OPEN CURSOR CustCursor

# Oracle版本,从游标中检索第一行
DECLARE TYPE CustCursor IS REF CURSOR
    RETURN Customers%ROWTYPE;
DECLARE CustRecord Customers%ROWTYPE
BEGIN
    OPEN CustCursor;
    FETCH CustCursor INTO CustRecord;
    CLOSE CustCursor;
END;

22. 高级SQL特征

(1)主键,主键是一种特殊的约束,用来保证一列(或者一组列)中的值是唯一的,而且永不改动,主键不能为空且不能重复。如果没有主键,要安全地UPDATE或DELETE特定行而不影响其他行会非常困难。

# 建表时直接设置主键
CREATE TABLE Vendors
(
    vend_id         CHAR(10)    NOT NULL PRIMARY KEY
   ,vend_name       CHAR(10)    NOT NULL
   ,vend_address    CHAR(50)    NULL
   ,vend_city       CHAR(50)    NULL
   ,vend_state      CHAR(5)     NULL
   ,vend_zip        CHAR(10)    NULL
   ,vend_country    CHAR(50)    NULL
);

# 给现有表添加主键
ALTER TABLE Vendors
ADD CONSTRAINT PRIMARY KEY (vend_id);

(2)外键,外键是表中的一列,其值必须列在另一表的主键中,外键是保证引用完整性极其重要的部分。如下:通过Customers表中cust_id,关联Orders表中的cust_id,来获取顾客的订单情况。

# 建表时直接设置外键
CREATE TABLE Orders
(
    order_num    INTEGER    NOT NULL PRIMARY KEY
   ,order_data   DATETIME   NOT NULL
   ,cust_id      CHAR(10)   NOT NULL REFERENCES
);

# # 给现有表添加外键
ALTER TABLE Orders
ADD CONSTRAINT FOREIGN KEY (cust_id) REFERENCES Customers (cust_id);

(二)上述样例表表结构

1. Vendors表

说明
vend_id唯一供应商ID
vend_name供应商名
vend_address供应商地址
vend_city供应商所在城市
vend_state供应商所在州
vend_zip供应商地址邮编
vend_country供应商所在国家

2. Products表

说明
prod_id唯一产品ID
vend_id唯一供应商ID(关联到Vendor表的vend_id)
prod_name产品名
prod_price产品价格
prod_desc产品描述

3. Customers表

说明
cust_id唯一顾客ID
cust_name顾客名
cust_address顾客地址
cust_city顾客所在城市
cust_state顾客所在州
cust_zip顾客地址邮编
cust_country顾客所在国家
cust_contact顾客联系名
cust_email顾客电子邮件地址

4. Orders表

说明
order_num唯一订单号
order_data订单日期
cust_id唯一顾客ID(关联到Customers表的cust_id)

5. OrderItems表

说明
order_num唯一订单号(关联到Orders表的order_num)
order_item订单物品号(订单内的顺序)
prod_id产品ID(关联到Products表的Prod_id)
quantity物品数量
item_price物品价格

(三)数据类型

1. 字符串数据类型

(1)定长字符串和变长字符串,DBMS处理定长列远比处理变长列快得多
注意点1:字符串值都必须括在引号内。

数据类型说明
CHAR1~255个字符的定长字符串,长度必须在创建时规定
NCHARCHAR的特殊形式,用来支持多字节或Unicode字符
NVARCHARTEXT的特殊形式,用来支持多字节或Unicode字符
TEXT(也称LONG、MEMO或VARCHAR)变长文本

2. 数值数据类型

注意点1:数值不应该括在引号内。

数据类型说明
BIT单个二进制位值,或者为0或者为1,主要用于开/关标志
DECIMAL(或NUMRIC)定点或精度可变的浮点值
FLOAT(或NUMBER)浮点值
INT(或INTEGER)4字节整数值,支持-2147483648~2147483647的数
REAL4字节浮点值
SMALLINT2字节整数值,支持-32768~32767的数
TINYINT1字节整数值,支持0~255的数

3. 日期和时间数据类型

数据类型说明
DATE日期值
DATETIME(或TIMESTAMP)日期时间值
SMALLDATETIME日期时间值,精确到分(无秒或毫秒)
TIME时间值

4. 二进制数据类型

(1)二进制数据类型可包含任何数据,甚至包含二进制信息,如图像、多媒体、字处理文档等。

数据类型说明
BINARY(或VARBINARY)定长二进制数据(最大长度从255B到8000B)
LONG RAW变长二进制数据,最长2GB
RAW定长二进制数据,最多255B

(四)注意点整理

1. 引擎InnoDB和MyISAM的选择

(1)考虑是否要支持事务,如果要选择InnoDB,如果不需要可以考虑MyISAM。
(2)如果日常绝大多数都只是查询,可以考虑MyISAM,如果既有读写也挺频繁,使用InnoDB。
(3)系统奔溃后,MyISAM恢复起来更困难。
(4)MySQL5.5版本开始InnoDB已经成为默认引擎。

2. Hive2mysql时遇到的特殊字段类型

(1)字段长度过长时建议使用TEXT(同样会很占用空间),不用过长的VARCHAR(比如:VARCHAR(5000))
(2)含有错别字、特殊字符或者表情包类的字段可以使用BLOB字段类型(比如:用户评论字段的字段类型可以使用BLOB,防止出现表情包类的信息时,字段格式为VARCHAR会插入报错),BLOB最大字符约为65KB,TINYBLOB最大字符为255B。

3. mysql表结构设计

(1)设计mysql表结构的时候,应考虑后续查询的性能问题,字段长度设置的时候不应过长,够用就好,否则会占用过多空间,查询时增加IO负担。
(2)用作计算或者排序的字段应使用int等数值数据类型,不使用VARCHAR等字符串数据类型,避免计算或者排序时出错。
(3)小数类字段类型使用DECIMAL(比如:金额字段用DECIMAL(12, 2))

4. mysql新增字段

(1)当表数据量为千万级以下时,加多个字段用一条语句完成。因为当有复杂SQL运行时,加字段时会导致锁表,假设一条加字段语句执行需要20min,用n条语句加n个字段则执行时间变为20min * n,所以建议用一条语句完成。

二、HiveSQL

(一)常用函数

函数说明
SUM()求和
COUNT()求数量
SUBSTR()截取字符串
MAX()取最大
MIN()取最小
ROW_NUMBER()排序取最新值
LOWER()转小写
UPPER()转大写
RLIKE/NOT RLIKEB是否在A里(支持正则)
LIKE/NOT LIKEB是否在A里(不支持正则)
COALESCE(参数1, 参数2, 参数n)依次查各参数,遇到非NULL值即停止并返回该值
CASE WHEN当XX时返回XXX
FROM_UNIXTIME(UNIX_TIMESTAMP(xxx), ‘yyyy-mm-dd hh:mm:ss’)时间戳
TO_DATE()转yyyy-mm-dd的时间格式
DATE_FORMAT()转自定义时间格式
CONCAT(参数1, 参数2)拼接参数
REPLACE()替换
GET_JSON_OBJECT解析json

(二)注意点整理

注意点1:表JOIN前先过滤数据,减少JOIN的数据量。
注意点2:多次用到同一个查询,使用临时表以便复用。

三、参考书籍

(一)《SQL必知必会(第4版)》 【美】Ben Forta 著 钟鸣 刘晓霞 译
(二)《Hive编程指南》 【美】Edward Capriolo Dean Wampler Json Rutberglen 著 曹坤 译

标签:实战,cust,笔记,vend,SQL,prod,id,SELECT,name
来源: https://blog.csdn.net/zhangliushi/article/details/113466231

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有