主键:一列(或一组列),其值可以唯一标识表中每一行。


用SELECT语句检索数据

SELECT prod_name FROM Products;

表示从Products表中检索一个名为prod_name的列,结果会返回prod_name列。

SELECT prod_id,prod_name,prod_price FROM Products;

表示从Products表中选三个列,结果会返回三个列。

SELECT * FROM Products;

表示检索表中的所有列。


SELECT语句返回所有匹配的行,如果不希望有重复的值,可以使用DISTINCT

SELECT DISTINCT vend_id FROM Products;

从表中返回值唯一的vend_id列。

SELECT DISTINCT vend_id,prod_price FROM Products;

DISTINCT关键字会滤除两列都相同的数据,只有一列一样的话不会被滤除。


限制返回结果长度

在SQL Server和Access中,用TOP关键字

SELECT TOP 5 prod_name FROM Products;

表示返回前五行。

在DB2中,方法不同。

SELECT prod_name FROM Products FETCH FIRST 5 ROWS ONLY;

也是返回前五行。

如果是Oracle,

SELECT prod_name FROM Products WHERE ROWNUM<=5;

如果用MySQL、MariaDB、PostgreSQL或者SQLite,用LIMIT子句。

SELECT prod_name FROM Products LIMIT5;

还可以通过offset指定开始返回的是第几行。

SELECT prod_name FROM Products LIMIT 5 OFFSET 5;

表示从第六行开始返回五行(行数是从0开始的,所以5表示第六行)。


使用注释

SQL必知必会学习笔记

"--"后面跟的就是注释。

SQL必知必会学习笔记

还有一种注释方法是用两个/*将注释围起来。


排序数据

SELECT prod_name FROM Products ORDER BY prod_name;

从表中选出指定列后对它进行排序。

ORDER BY子句一定要放在查询语句的最后,否则会报错,另外,也可以用非检索列进行排序。

SELECT prod_id,prod_price,prod_name FROM Products ORDER BY prod_price,prod_name

对多个列进行排序。如果prod_price中所有值都是唯一的,则不会按prod_name排序。

ORDER BY子句中,可以通过数字代表列名

SELECT prod_id,prod_price,prod_name FROM Products ORDER BY 2,3;

表示根据检索的第二第三列进行排序。

可以指定排序方向,默认是升序,通过DESC关键字可以调整为降序。

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

按prod_price降序进行排序。

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

按照prod_price降序排序,再按prod_name进行升序排序。

所以如果想对多个列进行降序排序,必须对每一列指定DESC关键字。


使用WHERE子句进行过滤数据。

SELECT prod_name,prod_price FROM Products WHERE prod_price = 3.49;

表示选取指定列,并筛选出prod_price等于3.49的数据。

WHERE子句操作符列表

SQL必知必会学习笔记

SELECT prod_name,prod_price FROM Products WHERE prod_price < 10;

选择prod_price小于10的数据。

SELECT vend_id,prod_name FROM Products WHERE vend_id <> 'DLL01';

从表中匹配指定列,并返回vend_id不等于DLL01的数据。

通过BETWEEN子句选择返回范围

SELECT prod_name,prod_price FROM Products WHERE prod_price BETWEEN 5 AND 10;

匹配指定列,并返回prod_price在5~10间的值。


NULL表示无值,与0,空字符串或空格不同。

SELECT prod_name FROM Products WHERE prod_price IS NULL;

返回prod_price为无的指定列。


组合WHERER子句

SELECT prod_id,prod_price,prod_name FROM Products

WHERE vend_id = 'DLL01' AND prod_price <= 4;

从表中选择指定的列并返回vend_id等于DLL01且prod_price小于等于4的数据。

SELECT pord_name,prod_price FROM Products WHERE vend_id = 'DLL01' OR vend_id = 'BRS01';

从表中选择指定的列并返回vend_id等于DLL01或BRS01的数据。

当查询语句中同时有AND和OR语句时,有优先顺序的区别。

SELECT prod_name,prod_price FROM Products

WHERE vend_id = 'DLL01' OR vend_id = 'BRS01' AND prod_price >= 10;

表示从表中选择指定列,并且满足vend_id为DLL01或(vend_id为BRS01并且prod_price大于等于10)的数据。

优先处理AND操作符。

SELECT prod_name, prod_price FROM Products

WHERE (vend_id = 'DLL01' OR vend_id = 'BRS01') AND prod_price >= 10;

用括号将OR语句包起来,则会优先处理OR语句。


IN操作符用来指定条件范围。

SELECT prod_name.prod_price FROM Products 

WHERE vend_id IN ('DLL01','BRS01') ORDER BY prod_name;

从表中选择指定的列,并返回vend_id等于DLL01或BRS01的数据,还要对prod_name进行排序。

IN操作符完成了与OR相同的功能,比一组OR操作符执行的更快,另外IN里面可以包含其他SELECT语句。


NOT操作符,用来否定后面跟的条件。

SELECT prod_name FROM Products WHERE NOT vend_id = 'DLL01' ORDER BY prod_name;

从表中选择指定列,并选择vend_id不等于DLL01的数据,并根据prod_name进行排序。这个例子也可以用<>操作符完成。


通配符,用来匹配值的一部分的特殊字符。

%表示任何字符出现任意次数。

LIKE操作符

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

从表中选择指定列,返回prod_name列中字符串开头为Fish的数。

SELECT prod_id, prod_name FROM Products WHERE prod_name LIKE '%bean bag%';

'%bean bag%'表示匹配任何位置上包含文本bean bag的值,不论它之前或之后出现什么字符。

SELECT prod_name FROM Products WHERE prod_name LIKE 'F%y';

找出以F开头,以y结尾的字符串。


另一个通配符"_",用途与%一样,但它只匹配单个字符。

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

匹配前面两个为任意字符,后面为' inch teddy bear'的字符串。


方括号[]通配符。(只有Access和SQL Server支持集合)

举个例子

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

匹配开头为J或者M的字符串。

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

匹配非J和非M起头的字符串。


通配符搜索要耗费更长的时间,所以不要过度使用,确实需要用到时,尽量不要在搜索模式的开始处使用。


创建计算字段

拼接,将值联接到一起构成单个值。

Access 和 SQL Server 使用+号。DB2、Oracle、PostgreSQL、SQLite 和Open Office Base 使用||。

SELECT vend_name + '(' + vend_country + ')'

FROM Vendors ORDER BY vend_name;

将vend_name列和vend_country列合成一列。

SQL必知必会学习笔记

使用'||'语法:

SELECT vend_name || '(' || vend_country || ')'

FROM Vendors ORDER BY vend_name;

MySQL 或 MariaDB 时使用concat语句:

SELECT Concat(vend_name,'(',vend_country,')')

FROM Vendors ORDER BY vend_name;

返回的结果中有很多空格,可以通过RTRIM()函数去除。

SELECT RTRIM(vend_name) + '(' + RTRIM(vend_country) + ')'

FROM Vendors ORDER BY vend_name;

SQL必知必会学习笔记

RTRIM()表示去掉值右边的所有空格。


使用别名

像上面那个由两个列拼接出来的列没有列名,可以新命名一个。

SELECT RTRIM(vend_name) + '(' + RTRIM(vend_country) + ')' AS vend_title

FROM Vendors ORDER BY vend_name;

SQL必知必会学习笔记

输出的和并列就有了列名。


对检索结果进行算术计算

SELECT prod_id,quantity,item_price,quantity*item_price AS expanded_price

FROM OrderItems WHERE order_num = 20008;

SQL必知必会学习笔记

返回结果中不但有检索列,还有算术计算建立的新列。


使用函数

SELECT vend_name,UPPER(vend_name) AS vend_name_upcase

FROM Vendors ORDER BY vend_name;

从表中选择vend_name列,复制一个同样的列并通过UPPER函数将这个列变成大写。

SQL必知必会学习笔记

常用的文本处理函数

SQL必知必会学习笔记


日期和时间处理函数

SELECT order_num FROM Orders WHERE DATEPART(yy,order_date) = 2012;

从表中检索日期为2012年的order_num列。(SQL Server 中)

SQL必知必会学习笔记

Access版本:

SELECT order_num FROM Orders WHERE DATEPART('yyyy',order_date) = 2012;

MySQL 和 MariaDB 具有各种日期处理函数,但没有 DATEPART(),可以使用名为YEAR()的函数从日期中提取年份

SELECT order_num FROM Orders WHERE YEAR(order_date) = 2012;


数值处理函数

SQL必知必会学习笔记


汇总数据

聚集函数

SQL必知必会学习笔记

SELECT AVG(prod_price) AS avg_price FROM Products;

选中表中的prod_price列并求平均值,将结果命名为avg_price列。

SQL必知必会学习笔记

SELECT AVG(prod_price) AS avg_price FROM Products WHERE vend_id = 'DLL01';

将指定列中vend_id等于DLL01的列求平均值。

SQL必知必会学习笔记

SELECT COUNT(*) AS num_cust FROM Customers;

计算表中有多少行。COUNT()函数用于计算指定列有多少行(NULL不计入)

SQL必知必会学习笔记

SELECT COUNT(cust_email) AS num_cust FROM Customers;

计算指定列有多少行,NULL会被忽略。

SQL必知必会学习笔记

和上面的总行数为5比较可以得出,有两行cust_email是无值的。

MAX()函数用于返回指定列中的最大值。

SELECT MAX(prod_price) AS max_price FROM Products;

SQL必知必会学习笔记

如果指定列是非数值列,比如文本列,MAX()会返回文本列升序排序后的最后一列。

MIN()函数和MAX()函数相反。

SUM()函数返回指定列的和。

SELECT SUM(quantity) AS items_ordered FROM OrderItems WHERE order_num = 20005;

返回order_num为20005的quantity列的和。

SQL必知必会学习笔记

也可以对算术计算所得列进行求和。

SELECT SUM(item_price*quantity) AS total_price

FROM OrderItems WHERE order_num = 20005;

SQL必知必会学习笔记


默认情况下,聚集函数会计算指定列的除NULL外的所有值,如果一列中有很多重复值不希望被计算进去,需要使用DISTINCT参数,默认是ALL参数。

SELECT AVG(DISTINCT prod_price) AS avg_price

FROM Products WHERE vend_id = 'DLL01';

表示计算prod_price列的非重复值的平均值,同时vend_id等于DLL01。

SQL必知必会学习笔记

和之前全部数据计算的平均值相比较高,因为该列有很多重复的低价。

DISTINCE不能用于COUNT(*),DISTINCT必须使用列名,不能用于计算或表达式。


组合聚集函数

SELECT COUNT(*) AS num_items,MIN(prod_price) AS price_min,MAX(prod_price) AS price_max,

AVG(prod_price) AS price_avg FROM Products;

返回表中有多少非NULL行,计算prod_price的最大值,最小值和平均值。


数据分组

创建分组

SELECT vend_id,COUNT(*) AS num_prods

FROM Products 

GROUP BY vend_id;

根据vend_id分组,并计算各分组的非NULL个数。

SQL必知必会学习笔记

用HAVING来过滤分组,不能用WHERE

SELECT cust_id,COUNT(*) AS orders

FROM Orders

GROUP BY cust_id

HAVING COUNT(*) >= 2;

对cust_id进行分组,并计算每个分组的行数,返回其中行数大于等于2的结果。

SQL必知必会学习笔记

SELECT vend_id,COUNT(*) AS num_prods

FROM Products

WHERE prod_price >= 4

GROUP BY vend_id

HAVING COUNT(*) >= 2;

选择prod_price大于等于4的vend_id并分组,然后统计每个分组的行数,最后返回行数大于等于2的结果。

SQL必知必会学习笔记

SELECT order_num,COUNT(*) AS items

FROM OrderItems

GROUP BY order_num

HAVING COUNT(*) >= 3

ORDER BY items,order_num;

表示将order_num列分组,并统计每组的行数,返回其中行数大于3的数据,并对items和order_num进行排序。

SQL必知必会学习笔记

SQL必知必会学习笔记


使用子查询

从订单表中查找商品名为RGAN01的订单编号。

SELECT order_num

FROM OrderItems

WHERE prod_id = 'RGAN01';

SQL必知必会学习笔记

根据得到的订单编号,在Orders表中查询下订单的客户ID

SELECT cust_id

FROM Orders

WHERE order_num IN(20007,20008);

SQL必知必会学习笔记

结合这两个查询,可以查找购买某商品的用户有哪些。

如果使用子查询,可以将上面两个查询结合起来。

SELECT cust_id

FROM Orders

WHERE order_num IN (SELECT order_num

                                       FROM OrderItems

                                       WHERE prod_id = 'RGAN01');

SQL必知必会学习笔记

得到订购商品RGAN01商品的顾客ID后,根据ID到顾客列表检索顾客信息。

SELECT cust_name,cust_contact

FROM Customers

WHERE cust_id IN('1000000004,'1000000005')

可以把WHERE子句转为子查询

SELECT cust_name, cust_contact

FROM Customers

WHERE cust_id IN (SELECT cust_id 

                               FROM Orders 

                               WHERE order_num IN (SELECT order_num 

                                                                     FROM OrderItems 

                                                                     WHERE prod_id = 'RGAN01'));

SQL必知必会学习笔记

作为子查询的SELECT语句只能查询单个列。

假设需要获取每个顾客的订单总数。首先从顾客列表获取每个顾客的顾客ID,再到Orders表中根据顾客ID统计每个顾客的订单进行计数。

SELECT cust_name,

             cust_state,

             (SELECT COUNT(*) FROM Orders

             WHERE Orders.cust_id = Customers.cust_id) AS orders

FROM Customers

ORDER BY cust_name;

SQL必知必会学习笔记

SQL必知必会学习笔记


联接表

SELECT vend_name,prod_name,prod_price

FROM Vendors,Products

WHERE Vendors.vend_id = Products.vend_id;

从供应商表和产品表取指定的三列,前提是两个表的供应商id相同。

如果没有WHERE子句,第一个表中的每一行将会与第二个表中的每一行配对。


內联接inner join

SELECT vend_name,prod_name,prod_price

FROM Vendors INNER JOIN Products

ON Vendors.vend_id = Products.vend_id;

结果和上面的使用WHERE子句的结果一样。


可以联接多个表

SELECT prod_name,vend_name,prod_price,quantity

FROM OrderItems,Products,Vendors

WHERE Products.vend_id = Vendors.vend_id

AND OrderItems.prod_id = Products.prod_id

AND order_num = 20007;

返回订单20007的产品名,供应商名,产品价格和数量。

上面有个例子是要返回订购产品RGAN01的顾客列表,可以通过联接重写一个看起来简单的。

SELECT cust_name,cust_contact

FROM Customers,Orders,OrderItems

WHERE OrderItems.order_num=Orders.order_num

AND Orders.cust_id = Customers.cust_id

AND prod_id = 'RGAN01'


创建高级联接

使用表别名

SELECT cust_name, cust_contact

FROM Customers AS C, Orders AS O, OrderItems AS OI

WHERE C.cust_id = O.cust_id 

AND OI.order_num = O.order_num 

AND prod_id = 'RGAN01';

别名不但可以缩短SQL语句,还允许在一条SELECT语句中多次使用相同的表。


自联接,一次查询中多次使用相同的表。

例子,在Customers表中找出所有与某顾客同公司的顾客。

使用子查询的话做法是先从表中找出该顾客所在的公司名,再在表中找出所有根据公司名找出所有人。

SELECT cust_id, cust_name, cust_contact

FROM Customers

WHERE cust_name = (SELECT cust_name 

                                    FROM Customers 

                                    WHERE cust_contact = 'Jim Jones');

因为操作都是在同一个表中进行的,所以还有另一种做法是用自联接和表别名。

SELECT a.cust_id,a.cust_name,a.cust_contact

FROM Customers AS a,Customers AS b

WEHERE a.cust_name = b.cust_name

AND a.cust_contact = 'Jim Jones';


自然联接,有时候,有些列可能出现在多个表中,选择数据时要注意在列名前加上表名,如果直接返回,可能会导致相同的列多次出现。


外联接

举个例子

SELECT Customers.cust_id,Orders.order_num

FROM Customers LEFT OUTER JOIN Orders

ON Customers.cust_id = Orders.cust_id;

意思是通过左联接联接Customers表和Orders表,返回俩表cust_id相同的数据,因为是左联接,所以即使没有匹配到,Customers表的数据也会全部出现。

SQL必知必会学习笔记

SQL必知必会学习笔记

如果是RIGHT OUTER JOIN的话,order_num整列都会出现,即使cust_id为NULL。

还有一种全外联接,包含两个表的不关联的行,FULL OUTER JOIN。


带聚集函数的联接

比如要检索每个顾客的下单数

SELECT Customers.cust_id,

             Count(Orders.order_num) AS num_ord

FROM Customers INNER JOIN Orders

ON Customers.cust_id = Orders.cust_id

GROUP BY Customers.cust_id;

根据cust_id联接两张表,根据Customers表的cust_id进行分组,并统计每个id的下单数。


使用UNION操作符来组合几条SQL查询。

SELECT cust_name,cust_contact,cust_email

FROM Customers

WHERE cust_state IN ('IL','IN','MI')

UNION

SELECT cust_name,cust_contact,cust_email

FROM Customers

WHERE cust_name = 'Fun4All';

将指定州的列和指定名的列合并起来。

SELECT cust_name, cust_contact, cust_email

FROM Customers

WHERE cust_state IN ('IL','IN','MI') 

OR cust_name = 'Fun4All';

这条查询语句和上面结果一样。

UNION中的每个查询必须包含相同的列,表达式或聚集函数,不过列的次序可以不同。


重复行

UNION会自动除去重复的行,如果用的是UNION ALL则会返回所有结果,包括重复的。

SELECT cust_name, cust_contact, cust_email

FROM Customers

WHERE cust_state IN ('IL','IN','MI')

UNION ALL

SELECT cust_name, cust_contact, cust_email

FROM Customers

WHERE cust_name = 'Fun4All';

SQL必知必会学习笔记


在UNION组合查询最后加上ORDERE BY语句,会对返回结果进行排序。


插入数据

插入完整的行

INSERT INTO Customers

VALUES('10000006',

              'Toy Land',

              '123 Any Street',

              'New York',

              'NY',

              '11111',

              'USA',

              NULL,

              NULL);

将一个新顾客数据插入到表中,每一列数据都要写上,包括NULL值。高度依赖于表中列的定义次序,不安全。

更安全的方法是插入数据时写上对应的列名,即使不同次序也能准确填入。

SQL必知必会学习笔记

数据会插入到指定的列中。

提供列名的情况下,也可以仅插入部分列的数据。

SQL必知必会学习笔记

比如这里仅插入了7列的数据。


插入检索出的值

SQL必知必会学习笔记


从一个表复制到另一个表

SELECT * 

INTO CustCopy

FROM Customers;

如果只想复制部分列,则用列名代替*

MariaDB、MySQL、Oracle、PostgreSQL 和 SQLite 使用的语法稍有不同:

CREATE TABLE CustCopy AS

SELECT * FROM Customers;

使用SELECT INTO时,任何SELECT选项和子句都可以使用,可以利用联结从多个表插入数据,不管从多少个表中检索数据,只能插到一个表中。


使用UPDATE和DELETE对数据进行更新和删除。

UPDATE Customers

SET cust_email = '[email protected]'

WHERE cust_id = '1000000005';

更新Custonmers表,将cust_id等于指定值的cust_email列设为指定值。

更新多个列

UPDATE Customers

SET cust_contact = 'Sam Roberts', 

       cust_email = '[email protected]'

WHERE cust_id = '1000000006';


要删除某个值,可以通过UPDATE将它设为NULL

UPDATE Customers

SET cust_email = NULL

WHERE cust_id = '10000000005';

如果去掉WHERE子句,表示删除cust_email列的所有数据。


用DELETE语句删除数据

DELETE FROM Customers

WHERE cust_id = '100000006';

删除表中符合条件的行。如果省略了WHERE子句,会将表中所有数据删除,不过表还是存在的

如果想删除表中所有行,使用TRUNCATE TABLE语句速度更快。

注意,更新和删除数据时要绝对小心。


创建表

SQL必知必会学习笔记

第一列是列名,第二列是类型,第三列是是否接受NULL。第三列允许NULL值的话可以省略。

还可以设定默认值,直接加在NULL值设定后面。

SQL必知必会学习笔记


通过ALTER TABLE对表进行修改

ALTER TABLE Vendors

ADD vend_phone CHAR(20);

给指定表新增一列,并设定数据类型。

ALTER TABLE Vendors

DROP COLUMN vend_phone;

删除列vend_phone(此语句并非所有数据库都适用)

小心使用ALTER TABLE。


删除表

DROP TABLE CustCopy;

谨慎使用。


使用视图

视图是虚拟的表,只包含使用时动态检索数据的查询。

举个例子,现在从三个表中检索数据

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 = 'RGAN01';

这个查询用来检索订购了某种商品的顾客。如果将查询包装起来,那么即使不知道表结构也能检索出数据。

SELECT cust_name, cust_contact

FROM ProductCustomers

WHERE prod_id = 'RGAN01';

即将中间那块包装成ProductCustomers进行引用,这就是视图的作用,ProductCustomers是一个视图,里面包含一个查询。

使用视图可以对SQL语句进行重用,简化复杂的SQL操作。

利用视图简化复杂的联接

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;

此语句创建了一个视图,联结三个表,返回已订购了任意产品的所有顾客的列表。如果执行SELECT*FROM ProductCustomers将列出订购了任意产品的顾客。

如果想要检索订购了产品RGAN01的顾客

SELECT cust_name,cust_contact

FROM ProductCustomers

WHERE prod_id = 'RGAN01';


视图的另一常见用途是重新格式化检索出的数据。

有时可能会经常使用某个格式的结果

CREATE VIEW VendorLocations AS

SELECT RTRIM(vend_name) + '(' + RTRIM(vend_country) +')' AS vend_title

FROM Vendors;

要检索数据时

SELECT *

FROM VendorLocations;

SQL必知必会学习笔记


用视图过滤不想要的数据

CREATE VIEW CustomerEMailList AS

SELECT cust_id,cust_name,cust_email

FROM Customers

WHERE cust_email IS NOT NULL;

选择email非NULL的指定数据,创建视图。

SELECT *

FROM CustomerEMailList

返回email非NULL的指定数据。


使用视图与计算字段

CREATE VIEW OrderItemsExpanded AS

SELECT prod_id,quantity,item_price,quantity*item_price AS expanded_price

FROM OrderItems;

检索订单20008的详细内容

SELECT *

FROM OrderItemsExpanded

WHERE order_num = 20008;


使用存储过程


相关文章: