SQL操作方式: 创建 ,删除 , 修改
1.模式: 创建CREATE SCHEMA 删除 DROPSCHEMA
2.表 :创建CREATE TABLE 删除DROP TABLE 修改 ALTER TABLE
3.视图 : 创建CREATE VIEW 删除DROP VIEW
4.索引 :创建CREATE INDEX 删除DROP INDEX
sql语句不区分大小写
1.检索单个列
SQL SELECT
SELECT列名 FROM 表名;
SELECT prod_name
FROM products;
2.多个检索列
SELECT列名1,列名2,列名3 FROM 表名;
SELECT prod_name, prod_name,prod_price
FROM products;
3.检索所有列
SELECT *
FROM表名;
SELECT * FROM products;
排序检索数据
1.排序数据
SELECT列名
FROM表名
ORDER BY列名;
SELECT prod_name FROM products order by prod_name;
按多列排序
SELECT列名1,列名2,列名3
FROM表名
ORDER BY列名2,列名1;
SELECT prod_id,prod_price,prod_name
FROM products
order by prod_price,prod_name;
按列位置排序
SELECT列名1,列名2,列名3
FROM表名
ORDER BY 2,3;
SELECT prod_id,prod_price,prod_name
FROM products
order by 2, 3;
指定排序方向
SELECT列名1,列名2,列名3
FROM表名
ORDER BY列名2 DESC;降序排序
SELECT prod_id,prod_price,prod_name
FROM products
order byprod_price DESC;
SELECT列名1,列名2,列名3
FROM表名
ORDER BY列名2 DESC,列名1;
SELECT prod_id,prod_price,prod_name
FROM products
order by prod_price DESC, prod_name;
过滤数据(搜索条件)
SELECT列名1,列名2,列名3
FROM表名
Where列名=数值(或其他条件);
SELECT prod_id,prod_price,prod_name
FROM products
WHERE prod_price=3.95;
WHERE子句操作符
=!<不小于IS NULL为NULL值
< >不等于>
!=不等于>=
<!>不大于
<=BETWEEN两值之间
检查单个值
SELECT列名1,列名2,列名3
FROM表名
Where列名<数值(或其他条件);
SELECT prod_id,prod_price,prod_name
FROM products
WHERE prod_price<10;
不匹配检查
SELECT列名1,列名2,列名3
FROM表名
Where列名< >数值(或其他条件);
SELECT prod_id,prod_price,prod_name
FROM products
WHERE vend_id=’DLL01’;
范围值检查
SELECT列名1,列名2,列名3
FROM表名
Where列名 BETWEEN 数值(或其他条件) AND 数值(或其他条件);
SELECT prod_id,prod_price,prod_name
FROM products
WHERE prod_price BETWEEN 5 AND 10;
空值检查
SELECT列名1,列名2,列名3
FROM表名
Where列名 IS NULL;
SELECT prod_id,prod_price,prod_name
FROM products
WHERE prod_price IS NULL;
高级数据过滤
组合WHERE子句
AND操作
SELECT列名1,列名2,列名3
FROM表名
WHERE列名=数值(或其他条件)AND 列名=数值(或其他条件);
SELECT prod_id,prod_price,prod_name
FROM products
WHERE vend_id=’DLL01’ AND prod_price<=4;
OR操作符
SELECT列名1,列名2,列名3
FROM表名
WHERE列名=数值(或其他条件)OR 列名=数值(或其他条件);
SELECT prod_id,prod_price,prod_name
FROM products
WHERE vend_id=’DLL01’ OR vend_id=’BRS01’;
计算次序
SELECT列名1,列名2,列名3
FROM表名
WHERE(列名=数值(或其他条件)OR 列名=数值(或其他条件))AND 列名=数值(其他条件);
SELECT prod_id,prod_price,prod_name
FROM products
WHERE (vend_id=’DLL01’ OR vend_id=’BRS01’)AND prod_price>=10;
IN操作符:指定范围
SELECT列名1,列名2,列名3
FROM表名
WHERE列名 IN (条件1,条件2)
ORDER BY列名;
SELECT prod_id,prod_price,prod_name
FROM products
WHERE vend_id IN (‘DLL01’,‘BRS01’)
ORDER BY prod_name;
NOT操作符:用来否定后面的条件
SELECT列名
FROM表名
WHERE NOT列名=(条件1,条件2)
ORDER BY列名;
SELECT prod_name
FROM products
WHERE NOT vend_id=‘DLL01’
ORDER BY prod_name;
用通配符进行过滤
LIKE操作符
百分号(%)通配符:只任意字符出现任意次数
SELECT列名1,列名2,列名3
FROM表名
WHERE列名 LIKE ‘寻找的字段%’;
SELECT prod_id,prod_price,prod_name
FROM products
WHERE prod_price LIKE ‘fish%’;
SELECT列名1,列名2,列名3
FROM表名
WHERE列名 LIKE ‘%寻找的字段%’;
SELECT prod_id,prod_price,prod_name
FROM products
WHERE prod_price LIKE ‘%fish%’;还有文本的值,不论之前之后出现什么字符。
SELECT列名1
FROM表名
WHERE列名 LIKE ‘首字母%首字母’;
SELECT prod_name
FROM products
WHERE prod_name LIKE ‘F%Y’;寻找F起头Y结尾的产品名。
除了一个或多个字符,%还能匹配0个字符。
下划线(_)通配符:与%相同,但只匹配单个字符。
SELECT列名
FROM表名
WHERE列名 LIKE ‘_’;
SELECT prod_name
FROM products
WHERE prod_price LIKE ‘_inch teddy bear ’;
SELECT列名
FROM表名
WHERE列名 LIKE ‘%’;
SELECT prod_name
FROM products
WHERE prod_price LIKE ‘% inch teddy bear ’;
方括号([ ])通配符
SELECT列名
FROM表名
WHERE列名 LIKE’[姓名的首字母]%’
ORDER BY列名
SELECT cust_contact
FROM Customers
WHERE cust_contact LIKE’[JM]%’
ORDER BY cust_contact查询以J或M首字母开头的人名
SELECT列名
FROM表名
WHERE列名 LIKE ’[^姓名的首字母]%’
ORDER BY列名
SELECT cust_contact
FROM Customers
WHERE cust_contact LIKE’[^JM]%’
ORDER BY cust_contact查询以除了J或M首字母开头的其他人名
SELECT列名
FROM表名
WHERE NOT列名 LIKE ’[姓名的首字母]%’
ORDER BY列名
SELECT cust_contact
FROM Customers
WHERE NOT cust_contact LIKE’[JM]%’
ORDER BY cust_contact查询以除了J或M首字母开头的其他人名
使用通用配符技巧
创建计算字段
拼接字段
SELECT列名 + ‘(‘+列名 +’)’
FROM表名
ORDER BY列名;
SELECT vend_name + ‘(‘+ vend_country +’)’
FROM Vendors
ORDER BY vend_name;
SELECT列名 || ‘(‘||列名 ||’)’
FROM表名
ORDER BY列名;
SELECT vend_name || ‘(‘|| vend_country ||’)’
FROM Vendors
ORDER BY vend_name;
去掉空格
SELECT RTRTM(列名)+’(‘+RTRIM(列名)+’)’
FROM表名
ORDER BY列名;
SELECT RTRTM(vend_name)+’(‘+RTRIM(vend_country)+’)’
FROM Vendors
ORDER BY vend_name;
SELECT RTRIM(列名) || ‘(‘||RTRIM(列名) ||’)’
FROM表名
ORDER BY列名;
SELECT RTRIM(vend_name) || ‘(‘||RTRIM( vend_country) ||’)’
FROM Vendors
ORDER BY vend_name;
RTRIM()函数去掉右边的所有空格。LTRIM()函数去掉左边的空格
使用别名:新查询新命名
SELECT RTRTM(列名)+’(‘+RTRIM(列名)+’)’AS别名
FROM表名
ORDER BY列名;
SELECT RTRTM(vend_name)+’(‘+RTRIM(vend_country)+’)’ AS vend_title
FROM Vendors
ORDER BY vend_name;
SELECT RTRIM(列名) || ‘(‘||RTRIM(列名) ||’)’AS新别名
FROM表名
ORDER BY列名;
SELECT RTRIM(vend_name) || ‘(‘||RTRIM( vend_country) ||’)’ AS vend_title
FROM Vendors
ORDER BY vend_name;
执行算术计算
SELECT列名1,列名2,列名3
FROM表名
WHERE条件;
SELECT prod_id,quantity,item_price
FROM OrderItems
WHERE order_num=20008;检索订单号20008中得所有物品
SELECT
列名1,
列名2,
列名3,
列名2*列名3 AS 作为新列名
FROM表名
WHERE条件;
SELECT
prod_id,
quantity,
item_price,
quantity*item_price AS expanded_price
FROM OrderItems
WHERE order_num=20008;
文本处理函数
SELECT列名1,UPPER(列名2) AS
新列名
FROM表名
ORDER BY列名;
SELECT vend_name,UPPER(vend_name) AS
Vend_name_upcase
FROM Vendors
ORDER BY vend_name; UPPER将文本转为大写
常用的文本处理函数
LEFT返回串左边的字符RIGTH返回串右边的空格
LENGTH返回串的长度RTRIM去掉穿右边的空格
LOWER将串转换为小写SOUNDEX返回串的SOUNDEX值
LTRIM去掉串左边的空格UPPER将串转换为大写
SOUNDEX()函数将任何文本串转换为描述其语音表示的字母数字模式的算法。能对串进行发音比较。
SELECT列名1,列名2
FROM表名WHE
RE列名=’正确搜索条件’;
SELECT cust_name,cust_contact
FROM Customers
WHERE cust_contact=’Michael Green’;
SELECT列名1,列名2
FROM表名
WHERE SOUNDEX(列名2)=SOUNDEX(‘所有发言匹配条件’);
SELECT cust_name,cust_contact
FROM Customers
WHERE SOUNDEX(cust_contact)=SOUNDEX(‘Michael Green’);
日期和时间处理函数
SELECT列名1
FROM表名
WHERE DATEPART(yy,列名2)=2004;
SELECT order_num
FROM Orders
WHERE DATEPART(yy,order_date)=2004;
DATE_PART()函数
SELECT列名1
FROM表名
WHERE DATE_PART(‘year’,列名2)=2004;
SELECT order_num
FROM Orders
WHERE DATE_PART(‘year’,order_date)=2004;
YEAR()函数
SELECT列名1
FROM表名
WHERE YEAR(列名2)=2004;
SELECT order_num
FROM Orders
WHERE YEAR(order_date)=2004;
Oracle软件日期
SELECT列名1
FROM表名
WHERE to_number(to_char(order_date列名2,’YY’))=数值;
SELECT order_num
FROM Oeders
WHERE to_number(to_char(order_date,’YY’))=2004;to_number将提取成分转换为数值,to_char()函数用来提取日期成分。
BETWEEN()操作符
SELECT列名1
FROM表名
WHERE列名2 BETWEEN to_date(‘日期’)
AND to_date(‘日期’);
SELECT order_num
FROM Orders
WHERE order_date BETWEEN to_date(‘01-JAN-2004’)
AND to_date(‘31-DEC-2004); to_date()函数用来将两个串转换为日期。
常用数值处理函数
ABS()返回一个数的绝对值SIN()返回一个角的正弦
COS()返回一个角的余弦SQRT()返回一个数的平方根
EXP()返回一个数的指数值TAN()返回一个角的正切
PI()返回圆周率
汇总数据
SQL聚集函数
AVG()返回某列平均值MIN()返回某列最小值
COUNT()返回某列行数SUM()返回某列值之和
MAX()返回某列最大值
AVG()函数
SELECT AVG(列名) AS新列名
FROM表名;
SELECT AVG(prod_price) AS avg_price
FROM Products;
确定特定列和行的均值
SELECT AVG(列名1) AS 新列名
FROM表名
WHERE列名2=条件;
SELECT AVG(prod_price) AS avg_price
FROM Products
WHERE vend_id=’DLL01’;
COUNT()函数
COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值。
COUNT(column)对特定列中具有值的行进行计数,忽略NULL值。
SELECT COUNT(*) AS 新列名
FROM表名;
SELECT COUNT(*) AS num_cust
FROM Customers;
SELECT COUNT(列名) AS 新列名
FROM表名;
SELECT COUNT(cust_email) AS num_cust
FROM Customers;
MAX()函数
SELECT MAX(列名) AS 新列名
FROM表名;
SELECT MAX(prod_price) AS max_price
FROM Customers;
MIN()函数
SELECT MIN(列名) AS 新列名
FROM表名;
SELECT MIN(prod_price) AS max_price
FROM Customers;
SUM()函数
SELECT SUM(列名) AS 新列名
FROM表名;
WHERE列名2=条件
SELECT SUM(quantity) AS items_ordered
FROM OrderItems;
WHERE order_num=20005;
SELECT SUM(列名) AS 新列名
FROM表名;
WHERE列名2=条件
SELECT SUM(item_price*quantity) AS total_price
FROM OrderItems;
WHERE order_num=20005;
聚集不同值
DISTINCT():只考虑各个不同的价格
SELECT AVG(DISTINCT列名1) AS 新列名
FROM表名
WHERE列名2=条件;
DISTINCT():只考虑各个不同的价格
SELECT AVG(DISTINCT prod_price) AS avg_price
FROM Products
WHERE vend_id=’DLL01’;
组合聚集函数
SELECT COUNT(*) AS新列名1,
MIN(列名) AS 新列名2,
MAX(列名) AS 新列名3,
AVG(列名)AS 新列名4
FROM表名;
SELECT COUNT(*) AS num_items,
MIN(prod_price) AS price_min,
MAX(prod_price) AS price_max,
AVG(prod_price) AS price_avg
FROM Product;
分组数据
数据分组
SELECT COUNT(*) AS新列名
FROM表名
WHERE列名=条件;
SELECT COUNT(*) AS num_prods
FROM Products
WHERE vend_id=’DLL01’;
GROUP BY()函数创建分组
SELECT列名1,COUNT(*) AS 新列名
FROM表名
GROUP BY列名2;
SELECT vend_id,COUNT(*) AS num_prods
FROM Products
GROUP BY vend_id;
过滤分组
SELECT列名,COUNT(*) AS 新列名
FROM表名
GROUP BY列名
HAVING COUNT(*)>=2;
SELECT cust_id,COUNT(*) AS orders
FROM Orders
GROUP BY cust_id
HAVING COUNT(*)>=2;过滤掉大于等于2的分组。
SELECT列名,COUNT(*) AS 新列名
FROM表名
WHERE列名>=4
GRUUP BY列名
HAVING COUNT(*)>=2;
SELECT vend_id,COUNT(*) AS num_prods
FROM Products
WHERE prod_price>=4
GRUUP BY vend_id
HAVING COUNT(*)>=2;
分组和排序
SELECT列名,COUNT(*) AS 新列名
FROM表名
GROUP BY列名
HAVING COUNT(*)>=3;
SELECT order_num,COUNT(*) AS items
FROM OrderItems
GROUP BY order_num
HAVING COUNT(*)>=3;
SELECT列名,COUNT(*) AS 新列名
FROM表名
GROUP BY列名
HAVING COUNT(*)>=3
ORDER BY items,order_num;
SELECT order_num,COUNT(*) AS items
FROM OrderItems
GROUP BY order_num
HAVING COUNT(*)>=3
ORDER BY items, order_num;
SELECT子句顺序
使用子句查询
①SELECT列名1
FROM表名
WHERE列名2=条件;
SELECT order_num
FROM OrderItems
WHERE prod_id=’RGAN01’;
②SELECT列名1
FROM表名
WHERE列名2 IN(设置区间);
SELECT cust_id
FROM Orders
WHERE order_num IN(20007,20008);
将第一个查询变为子查询组合两个查询
SELECT列名1
FROM表名1
WHERE列名2IN (SELECT 列名2
FROM表名2
WHERE列名3=条件);
SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
FROM OrderItems
WHERE prod_id=’RGAN01’);
首先,
在SELEC下语句中,子查询总是从内向外处理;在处理上面的SELECT语句时,DAMS实际上执行了两个操作。
首先,它执行下面的查询:
SELECT order_num FROM orderitems WHERE prod_ id=’RGAN01’
此查询返回两个订单号:20007和20008。然后,这两个值以工IN操作符要求的逗号分隔的格式传递给外部查询的WHERE子句。
外部查询变成;
SELECT cust id FROM orders WHERE order num TN (20007,20008)
可以看到,输出是正确的并且与前面硬编码WHEi}E子句所返回的值相同。
检索查询
SELECT列名1,列名2
FROM表名
WHERE列名3 IN(搜索区间);
SELECT cust_name,cust_contact
FROM Customers
WHERE cust_id IN(‘1000004’,’10000005’);
将WHERE子句转换为查询
SELECT列名1,列名2
FROM表名1
WHERE列名3 IN(SELECT 列名3
FROM表名2
WHERE列名4 IN(SELECT 列名4
FROM表名3
WHERE列名5=条件));
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’));
为了执行上述SELECT语句,DBMS实际上必须执行3条SELECT语句。最里边的子查询返回订单号列表,此列表用于其外面的子查询的WHERE子句。外面的子查询返回客户ID列表,此客户ID列表用于最外层查询的WHERE子句。最外层查询确实返回所需的数据。
作为计算字段使用子查询
使用SELECT(COUNT*)对表中的行进行计数,并且通过提供一条WHERE了句来过滤某个特定的客户ID,可仅对该客户的订单进行计数。
SELECT COUNT(*)AS新列名
FROM表名
WHERE列名=条件;
SELECT COUNT(*)AS orders
FROM Orders
WHERE cust id=’1000000001‘;
SELECT列名1,
列名2,
(SELECT COUNT(*)
FROM表名1
WHERE条件=条件) AS
新列名
FROM表名
OROER BY列名1;
SELECT cust_ name,
cust_ state,
(SELECT COUNT(*)
FROM Orders
WHERE Orders.cust_ id=Customers.cust_ id) AS
orders
FROM Gustomers
OROER BY cust_ name;
联结表
创建联结
SELECT列名1,列名2,列名3
FROM表名1,表名2
WHERE表1中的关联条件=表2中的关联条件;
SELECT vend_name,prod_name,prod_price
FROM Vendors,Products
WHERE Vendors.vend_id=Products.vend_id;
笛卡儿积:检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。
SELECT列名1,列名2,列名3
FROM表名1,表名2;
SELECT vend_name,prod_name,prod_price
FROM Vendors,Products;
从上面的输出中可以看到,相应的笛卡儿积不是我们所想要的。这里返回的数据用每个供应商匹配了每个产品,它包括了供应商不正确的产品。实际上有的供应商根本就没有产品。
内部联结:目前为止所用的联结称为等值联结,它基于两个表之间的相等测试。
SELECT列名1,,列名2,列名3
FROM表名1 INNER JOIN表名2
ON表1关联条件=表2关联条件;
SELECT vend_name,,prod_ name,prod_price
FROM Vendors INNER JOIN Products
ON Vendors.vend_ id=Products.vend_ id;
这里两个表之间的关系是FROM子句的组成部分,以INNERJOIN指定。在使用这种语法时,联结条件用特定的ON子句而不是WHERE子句给出。传递给ON的实际条件与传递给WHERE的相同。
联结多个表
SELECT列名1, 列名2, 列名3, 列名4
FROM表名1,表名2,表名3
WHERE表1条件=表1条件
AND表3条件=表1条件
AND筛选条件;
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;
SEiECT列名1,列名2
FRDM Customers表1,表2,表3
WHERE表1条件=表2条件
ANO表3条件=表1条件
AND筛选条件;
SEiECT cost name,cust_contact
FRDM Customers,Orders,OrderItems
WHERE Customers.cost_id =Orders.cust _id
ANO OrderItems.order_ nom=Orders.Order_nom
AND prod_id=’RGAN01’;
创建高级联结
请看下而的SELECT语句。它与之前所用的语句基本相同,但改成了使用别名:
SELECT列名1,列名2
FROM表名1AS别名1,表2AS别名2, 表3 AS别名3
WHERE表1=条件
AND表2=条件
AND表3=条件;
SELECT cust_ name,cust_ contact
FROM Customers AS C, Orders AS 0, OrderItems AS OI
WHERE C.cust_id=0.cust_id
AND OI.order_ num=O.order_ num
AND prod_id=’RGAN01’;
应该注意,表别名只在查询执行中使用。与列别名不一样,表别名不返回到客户机。
使用不同类型的联结
自联结
SELECT列名1,列名2, 列名3
FROM表
WHERE列名2=(SELECT列名2
FRDM表
WHERE列名3=条件);
SELECT cust_ id,cust_name, cust_contact
FROM Customers
WHERE cust_ name=(SELECT oust_ name
FRDM Customers
WHERE oust_ contact=’Jim Jones’);
SELECT列别名1,列别名2,列别名3
FROM表AS别名,表 AS别名
WHERE列别名1=列别名4
AND列别名5=条件;
SELECT c1.cust_ id,c1.cust_ name,c1 .cuss_ contact
FROM Customers AS c1,Customers ASc2
WHERE c1 .cust_name=c2.cust_ name
AND c2.cust _contact=’Jim Jones’;
用自联结而不用子查询自联结通常作为外部语句用来替代从相同表中检索数据的使用子查询语句。虽然最终的结果是相同的,但许多DBMS处理联结远比处理子查询快得多。应该试
一下两种方法,以确定哪一种的性能更好。
自然联结:只能选择那些唯一的列。这一般是通过对表使用通配符(SELECT*),对所有其他表的列使用明确的子集来完成的。
SELECT C.*,列别名1, 列别名2,列别名3,
列别名4,列别名5
FROM表1 AS 表别名1,表2AS表别名2,表3 AS 表别名3
WHERE列别名3=列别名6
AND列别名1=列别名7
AND列别名3=条件;
SELECT C.*,0.order_ num, 0.order_date,OI .prod_id,
OI.quantity,OI .item_ price
FROM Customers AS C,Orders AS 0,OrderItems AS OI
WHERE C.cust_id=O.cust_id
AND OI .order_num=0.order_num
AND prod _id=’RGANOi’;
外部联结:许多联结将一个表中的行与另一个表中的行相关联。
SELECT列别名1,列别名2
FROM表1 LEFT OUTER JOIN 表2
ON列别名1=列别名3;
SELECT Customers.cost_ id,Orders.order_nom
FROM Customers LEFT OUTER JOIN orders
ON Customers.cost_ id=orders.Cust_id;
这条SELECT语句使用了关键字OUTER JOIN来指定联结的类型(而不是在WHERE子句中
指定)。但是与内部联结关联两个表中的行不同的是,外部联结还包括没有关联行的行。在使用OUTER JOIN语法时,必须使用RTGHT或LEFT关键字指定包括其所有行的表(RTGHT指出的是OUTER JOIN右边的表,而LEFT指出的是OUTER JOIN左边的表)。上面的例子使用LEFT OUTER JOIN从FROM子句的左边表(Customers表)中选择所有行。
SELECT列别名1,列别名2
FROM表1 RIGHT OUTER JOIN 表2
ON列别名3=列别名1;
SELECT Customers.cust_id,Orders.order_num
FROM Customers RIGHT OUTER JOIN Orders
ON Orders.cust_ id=Customers.oust _id;为了从右边的表中选择所有行,应该使用RIGHT OUTER JOIN。
SQL服务器额外支持一种简化的外部联结语法。
SELECT列别名1 ,列别名2
FROM表1,表2
WHERE列别名1*=列别名3;
SELECT Customers.cust_id ,Orders.order_num
FROM Customers,Orders
WHERE Customers.cust_id*=Orders.cust_ id;
这里的联结条件是在WHERE子句中规定的。与使用=号的相等测试不一样,*=操作符用来指定应该包括Customers表中的每一行。*=为左外部联结操作符。它从左边表中检索所有行。与左外部联结相对的是右外部联结,由=*指定。可用它来返回列在操作符右边的表中所有行。
全外部联结语法:全外部联结包含来自两个表的不关联的行。
SELECT列别名1,列别名2
FROM表1 FULL OUTER JOIN表2
ON列别名3=列别名1;
SELECT Customers .cust_ id,Orders.order_ num
FROM Orders FULL OUTER JOIN Customers
ON Ordars.cust_id=Customers.Cust_id;
使用带聚集函数的联结
SELECT列别名1,COUNT(列别名2) AS 列别名3
FROM表1 INNER JOIN 表2
ON列别名1=列别名4
GROUP BY列别名1;
SELECT Customers.cust_id,COUNT(Orders.order_num) AS num_ord
FROM Customers INNER JOIN Ordors
ON Customers.cust_ id=Orders.cust_id
GROUP BY Customers.cust_id;
此SELECT语句使用INNER JO工闪将Customers和Orders表互
相关联。GROUP日Y子句按客户分组数据,因此,函数调用
COUN丁(Orders.order_ num)对娜个客户的订单计数,将它作为
num ord返回。
SELECT列别名1,COUNT(列别名2) AS 新列别名
FROM表1 LEFT OUTER JOIN 表2
ON列别名1=列别名3
GROUP BY列别名1;
SELECT Customers.cust_ id,COUNT(Orders.order_num) AS num_ord
FROM Customers LEFT OUTER JOIN Orders
ON Customers.Cust_id=Orders.cust_ id
GROUP BY Customers cust_ id;
组合查询
SQL也允许执行多个查询(多条SELECT语句),并将结果作为单个查询结果集返回。这些组合查询通常称为并或复合查询。
有两种基本情况,其中需要使用组合查询:1在单个查询中从不同的表类似返同结构数据。
2对单个表执行多个查询,按单个查询返问数据。
创建组合查询
使用UNION
单句1
SELECT列名1,列名2 ,列名3
FROM表
WHERE列名4 IN(‘IL’,’IN’,’MI’);
单句2
SELECT列名1,列名2,列名3
FROM表
WHERE列名1=条件;
组合句
SELECT列名1,列名2 ,列名3
FROM表
WHERE列名4 IN(‘IL’,’IN’,’MI’);UNION
SELECT列名1,列名2,列名3
FROM表
WHERE列名1=条件;
单句1
SELECT cust_name,cust _contact ,cust_ email
FROM Customers
WHERE cust _state IN(‘IL’,’IN’,’MI’);
单句2
SELECT cost_ name,cost contact .cost email
FROM Customers
WHERE cost_ name=’Fun4All’;
组合句
SELECT cost_ name,cost contact.cost email
FROM Customers
WHERE cost _state IN(‘IL’,’IN’,’MI’)
UNION
SELECT cost_ name,cost_ contact,cost_ email
FROM Customers
WHERE cust_name=’Fun4All’;
1.UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNTON分隔(因此,如果组合4条SELECT语句,将要使用3个UNTON关键字)。
2.UNION中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)。
3.列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含地转换的类型(例如,不同的数值类型或不同的日期类型)。
包含或取消重复的行
UNION从查询结果集中自动去除了重复的行(换句话说,它的行为与单条SELECT语句中使用多个WHERE子句条件一样)。这是UNION的默认行为,但是如果愿意,可以改变它。事实上,如果想返回所有匹配行,可使用UNION ALL而不是UNION。
SELECT列名1,列名2,列名3
FROM表
WHERE列名4 IN(‘IL’,’IN’,’MI’)
UNION ALL
SELECT列名1,列名2,列名3
FROM表
WHERE列名5=条件;
对组合查询结果排序群
SELECT语句的输出用ORDER BY子句排序。在用UNION组合查询时,只能使用一条ORDER BY子句,它必须出现在最后一条 SELECT语句之后。对于结果集,不存在用一种方式排序一部分,而又用另一种方式排序另一部分的情况,因此不允许使用多条ORDER BY子句。
下面的例子排序前面UNION返回的结果:
SELECT列名1, 列名2,列名3
FROM表
WHERE列名1 IN(‘IL’,'IN',’MI’)
ONION
SELECT列名1, 列名2,列名3
FROM表
WHERE列名1=条件
ORDER BY列名1,列名2;
SELECT cust_ name, cust_ contact,cust_email
FROM Customers
WHERE cust_ state IN(‘IL’,'IN',’MI’)
ONION
SELECT cust_ name,cust_ contact,cust_email
FROM Customers
WHERE cust _name=’Fun4Al1’
ORDER BY cust _name,cust_ contact;
插入数据
插入完整的行
INSERT语法:把数据插入表中的最简单的方法是使用基本的INSERT语法,它要求指定表名和被插入到新行中的值。
INSERT INTO表
VALUES(插入的变量‘’,‘’,‘’,
NULL,
NULL);
INSERT INTO Customers
VALUES(‘1000000006’,
‘Toy Land’
‘123 Any Street’
'New York’,
‘NY’,
‘11111’,
‘USA’,
NULL,
NULL);
此例子插入一个新客户到Customers表。存储到每个表列中的数据在VALUES子句中给出,对每个列必须提供一个值。如果某个列没有值,应该使用NULL值(假定表允许对该列指定空值)。各个列必须以它们在表定义中出现的次序填充。
编写INSERT语句的更安全〔不过更烦琐)的方法如下:
INSERT INTO表(列名1,
列名2,
列名3,
列名4,
列名5,
VALUES(加入新变量‘’,
NULL空值,
NULL);
INSERT INTO Customers(cust_ id,
cust_ name,
cust_ address,
cust_city,
cust_ state,
cust_ zip,
oust-country,
cust_ contact,
cust_ email)
VALUES('1000000006’,
‘Toy Land’,
‘123 Any Street’,
‘New York’
‘NY’.
‘1111’,
‘USA’,
NULL,
NULL);
插入部分行
INSERT INTO表(列名1,
列名2,
列名3,
列名4,
列名5,
VALUES(加入新变量‘’);
INSERT INTO Customers(cust_ id,
cust_ name,
cust_ address,
cust_city,
cust_ state,
cust_ zip,
oust-country)
VALUES('1000000006’,
‘Toy Land’,
‘123 Any Street’,
‘New York’
‘NY’.
‘1111’,
‘USA’);
省略的列必须满足以下某个条件:
1.该列定义为允许NULL值(无值或空值)。
2.在表定义中给出默认值。这表示如果不给出值,将使用默认值。
如果对表中不允许NULL值且没有默认值的列不给出值,则DBMS将产生一条错误消息,并且相应的行插入不成功。
插入检索出的数据
INSERT一般用来给表插入一个指定列值的行。但是, INSERT还存在另一种形式,可以利用它将一条SELEC下语句的结果插入表中。这就是所谓的INSERT SELECT顾名思义,它是由一条 INSERT语句和一条SELECT语句组成的。
INSERT INTO表1(表1中的列名)
SELECT表1中的列名
EROM表2;
INSERT INTO Customers(cust_ id,
cust_ contact,
cust_ email,
cust_ name,
cust_ address,
cust_ city,
cust_ state,
cust_zip,
cust_country)
SELECT cust_ id,
cust_ contact,
cust_ email,
cust_ name,
cust_ address,
cust_ city,
cust_ state,
cust_zip,
cust_country
EROM CustNew;
这个例了使用INSERT SELECT从CustNew中将所有数据导入Customers。 SELECT语句从CustNew检索出要插入的值,而不是列出它们。SELECT中列出的每个列对应于Customers表名后所跟的列表中的每个列。这条语句将插入多少行有赖于CustNew表中有多少行。如果这个表为空,则没有行被插入(也不产生错误,因为操作仍然是合法的)。如果这个表确实含有数据,则所有数据将被插入到Customers。
从一个表复制到另一个表
SELECT INTO语句:
SELECT *
INTO新表
FROM表;
SELECT
SELECT *
INTO CustCopy
FROM Customers;
SELECT
这条SELECT语句创建一个名为CustCopy的新表,并把Customers表的整个内容复制到新表中。因为这里使用的是*,所以将在CustCopy表中创建(并填充)与Customers表中得个列相同的列。要想只复制列的子集,可明确地给出列名而不是使用*通配符。
更新和删除数据
UPDATE语句更新数据
1.更新表中特定行;
2.更新表中所有行。
UPDATE表
SET列名=新值
WHERE列名2=过滤条件;
UPDATE Customers
SET cust email=’kim@thetoystore.com’
WHERE cust_id=’1000000005’;
UPDATE表
SET列名1=更新条件,
列名2=更新条件
WHERE列名3=过滤条件;
UPDATE Customers
SET cust _contact=’Sam Roberts’,
Cust_ email=’sam@toyland.com’
WHERE cust id=’1000000006’;
在更新多个列时,只需要使用单个SET命令,每个“列=值”对之间用逗号分隔(最后一列之后不用逗号)二在此例子中,更新客户1000000006的cust contact和Gust email列。
为了册(除某个列的值,可设置它为NULL(假如表定义允许NULL值)。
UPDATE表
SET c列名1=空值
WHERE列名2=过滤条件;
UPDATE Customers
SET cust_ email=NULL
WHERE cust_ id=’000000005’;
删除数据
DELETE语句
1.从表中删除特定的行:
2.从表中删除所有行。
DELETE FROM表
WHERE列名 =删除条件;
DELETE FROM Customers
WHERE cust_id =’1000000006’;
DELETE不需要列名或通配符。DELETE删除整行而不是删除列。为了删除指定的列,请使用UPDATE语句。
如果想从表中删除所有行,不要使用DELETEo
可使用TRUNCATE TABLE语句,它完成相同的工作,但速度更快(因为不记录数据的变动)。
创建和操纵表
创建表
1.多数DBMS都具有交互式创建和管理表的工具;
2.表也可以直接用SQL语句操纵。
表创建基础
CREATE TABLE表
(变量);
CREATE TABLE Products
(
prod_ id CHAR(10) NOT NULL,
vend_ id CHAR(10) NOT NULL,
Prod_name CHAR(254) NOT NULL
prod_ price DECIMALS,2) NOT NULL
prod_ desc VARCHAR(1000) NULL
);
创建混合了NULL和NOT NULL列的表:
CREATE TABLE表
(列名 字段 是否空值);
CREATE TABLE Vendors
(
vend _id CHAR(10) NOT NULL
vend _name CHAR(50) NOT NULL
Vend_ address CHAR(50),
vend_ city CHAR(50),
vend_ state CHAR(5),
vend_ zip CHAR(10),
vend_ country CHAR(50)
);
制定默认值:在CREATE TABLE语句的列定义中用关键字DEFAULT指定。
CREATE TABLE表
(列名 字段 是否空值 指定默认值);
CREATE TABLE OrderItems
(
order _num INTEGER NOT NULL,
Order_ item INTEGER NOT NULL,
prod_id CHAR(10) NOT NULL,
quantity INTEGER NOT NULL DEFAULT 1,
Item_price DECTMAL(8,2) NOT NULL,
);
系统数据 函数变量
Access NEW()PostgreSQL CURRENT_DATE
DB2 CURRENT_DATESQL Server GETDATE()
MySQL CURRENT_DATE()Sybase GETDATE()
Oracle SYSDATE
更新表:使用ALTER TABLE语句
给已有表增加列
ALTER TABLE表
ADD增加列 字段;
ALTER TABLE Vendors
ADD vend _phone CHAR(20);
删除过程
ALTER TABLE表
DROP COLUMN删除列名;
ALTER TABLE Vendors
DROP COLUMN vend_phone;
删除表
DROP TABLE表名;
重命名表
使用RENAME语句
使用视图
SELECT列名1,列名2
FROM视图名
WHERE列名3=条件;
SELECT cost _name,oust _contact
FROM ProductCustomers
WHERE prod_id=’RGAN01’;
ProductCustomers是一个视图,作为视图,它不包含任何列或数据,它包含的是一个查询。视图不包含数据,所以每次使用视图时,都必须处理查询执行时所需的任一个检索。
创建视图
CREATE VIEW viewname;
用DROP删除视图:其语法为DROP VIEW viewname;
覆盖(或更新)视图必须先DROP它,然后再重新创建它。
利用视图简化复杂的联结
CREATE VIEW视图 AS
SELECT列名1,列名2,列名3
FROM表1,表2,表3
WHERE联结1=联结2
AND联结3=联结4;
CREATE VIEW ProductCustomers AS
SELECT cust_ name,cust_contact,prod_id
FROM Customers,Orders, Orderltems
WHERE Customers.cust_id=Orders.cost_ id
AND OrderItems.order_ nom=Orders.order_ nom;
用视图重新格式化检索的数据
CREATE VIEW视图 AS
SELECT RTRIM(列名1)+’(‘+RTRIM(列名2)+’)’AS别名
FROM表;
CREATE VIEW VendorLocations AS
SELECT RTRIM(vend_ name)+’(‘+RTRIM(vend_ country)+’)’ AS vend_ title
FROM Vendors;
下面是使用||语法的相同语句:
CREATE VIEW视图 AS
SELECT RTRIM(列名1)||’(‘|| RTRIM(列名2)||’)’AS别名
FROM表;
CREATE VIEW VendorLocations AS
SELECT RTRIM(vend_ name)||’(‘|| RTRIM(vend_country)||’)’ AS vend_title
FROM Vendors;
检索出以创建所有邮件标签的数据
SELECT*
FROM视图;
用视图过滤不想要的数据
CREATE VIEW视图 AS
SELECT列名1,列名2,列名3
FRDM表
WHERE列名3 IS NOT NULL;
CREATE VIEW CustomerEMailList AS
SELECT cust_ id,cust_ name,cust_ email
FRDM Customers
WHERE cust_ email IS NOT NULL;
检索出以创建所有邮件标签的数据
SELECT*
FROM视图名
使用视图与计算字段
CREATE VIEW视图
SELECT列名
乘积AS别名
FROM表;
CREATE VIEW OrderItemsExpanded
SELECT order_ num,
prod_id,
quantity,
item_price,
quantity*item_price AS expanded_price
FROM OrderItems;
检索出以创建所有邮件标签的数据
SELECF*
FROM视图
WHERE过滤条件;
SELECF*
FROM OrderItemsExpanded
WHERE order_ num=20008;
使用存储过程
EXECUTE执行存储过程的语句
EXECUTE储存新产品到表中(参数1,参数2,参数3,参数4)
EXECUTE AddNewProduct(‘JTS01’,
’Stuffed Eiffel Tower’,
6.49,
‘Plush stuffed toy with the text La Tour Eiffrl
in red white and blue’)
这里执行一个名为AddNewProduct的存储过程;它将一个新产品添加到Products表。AddNewProduct有4个参数,分别是:供应商ID (Vendors表的主键)、产品名、价格和描述。这4个参数匹配存储过程中4个预期的变量(定义为存储过程自身的组成部分)。此存储过程添加新行到Products表并将传入的属性赋给相应的列。
创建存储过程
下面是该过程的Oracle版本:
CREATE PROCECURE参数
(参数 OUT NUMBER)
IS
BEGIN
SELEGT*FROM表
WHERE NOT列名 IS NULL;
参数:=SQL%ROWCOUNT;
END;
CREATE PROCECURE MailingListCount
(ListCount OUT NUMBER)
IS
BEGIN
SELEGT*FROM Customers
WHERE NOT cust_ email IS NULL;
ListCount:=SQL%ROWCOUNT;
END;
此存储过程有一个名为ListCount的参数。此参数从存储过程
返回一个值而不是传递一个值给存储过程。关键字OUT用来指
示这种行为。Oracle支持IN(传递值给存储过程)、OUT(从存储过程返
回值,如这里所示)、INOUT(既传递值给存储过程也从存储过程传回值)
类型的参数。存储过程的代码括在BEGIN和END语句中,这里的执行一条
简单的SELECT语句,它检索具有邮件地址的客户。然后用检索出的行数
设置ListCount(要传递的输出参数)。
下面是Microsoft SQL Server版本:
CREATE PROCEDURE MailingListCount
AS
DECLARE @cnt INTEGER
SELECT @cnt=COUNT(*)
FROM Customers
WHERE NOT cust_ email IS NULL;
RETURN @cnt;
下面是另一个例子,这次在Orders表中插入一个新订单。此程序仅
适用于SQL Server但它说明了存储过程的某些用途和技术:
CREATE PROCEDiJRE NewOrder @cust_ id CHAR(10)
AS
Declare variable for order number
DECLARE @order_ num INTEGER
Get current highest order number
SELECT @order_num=MAX(order_num)
FROM Orders
Determine next order number
SELECT @order_num=@order_num+1
Insert new order
INSERT INTO Orders(order_num, order_ date,cust_id)
VALUES(@order_ num,GETDATE(),@cust_id)
Return order number
RETURN @order _num;
下面是相同SQL Server代码的相当不同的版本:
CREATE PROCEDURE NewOrder @cust_ id CHAR(10)
AS
Insert new order
INSERT INTO Orders(cust_id)
VALUES(@cust_ id)
Return order number
SELECT order _num=@@IDENTITY;
管理事务处理
事务处理术语
1.事务(transaction)指一组SQL语句;
2.回退(rollback)’指撤销指定SQL语句的过程;
3.提交(commit)指将未存储的SQL语句结果写入数据库表;
4.保留点(savepoint)指事务处理中设置的临时占位符( placeholder ),你可以对它发布回退(与回退整个事务处理不同)。
可以回退哪些语句?事务处理用来管理INSERT,UPDATE和CELETE语句。不能回退SELECT语句(回退SELECT语句也没有多少必要),也不能回退CREATE或DROP操作。事务处理中可以使用这些语句,但进行回退时,它们不被撤销。
管理事务处理
在SQL Server:
BEGIN TRANSACTION
COMMIT TRANSACTION
使用ROLLBACK撤回语句
DELETE FROG Orders;
ROLLBACK;
使用COMMIT提交语句
在SQL Server:
BEGIN TRANSACTION
DELETE OrderItems WHERL order _num=12345
DELETE Orders WHERE order_ num=12345
COMMIT TRANSACTION
为在Oracle完成相同的工作,可如下进行;
DELETE OrderItems WHERE order_ num=12345;
DELETE Orders WHERE order _num=12345;
COMMIT;
使用保留点
在SQL中,这些占位符称为保留点。为了在MySQL和Oracle中创建占立符,可如下使用SAVEPOINT语句:
SAVEPOINT delete1;
使用游标
创建游标:游标用DECLARE语句创建
下面是创建此游标的DB2, SQL Server和Sybase版本:
DECLARE CustCursor CURSOR
FOR
SELECT*FROM Customers
WHERE cust _email IS NULL
下面是Oracle和PostgreSQL版本:
DECLARE CURSOR CustCursor
IS
SELECT*FROM Customers
WHERE cust_ email IS NULL
使用游标
游标用OPEN CURSOR语句来打开:
OPEN CURSOR CustGursor
用FETCH语句访问游标数据
DECLARE TYPE CustCursor IS REF CURSOR
RETURN Customers%ROWTYPE;
DECLARE CustRecord Customers%ROWTYPE
BEGIN
OPEN CustCursor;
FETCH CustCursor INTO CustRecord;
CLOSE CustCursor;
END;
在这个例子中,FETCH用来检索当前行(自动从第一行开始)到声明的变量CustRecord中。刘于检索出来的数据没做任何其他处理。
DECLARE TYPE CustCursor IS REF CURSOR
RETURN Gustomers%ROWTYPE;
DECLARE CustRecord Customers%ROWTYPE
BEGIN
OPEN CustCursor;
LOOP
FETCH CustCursor INTO CustRecord;
LXIT WHEN CustCursor%NOTFOUND;
END LOOP;
CLOSE CustCursor;
END;
为CustRecord的变量中。但与前一个例子不一样,这里的FETCH位于LOOP内,因此它反复执行。代码EXIT WHEN CustCursor%NOTFOUN使处理在取不出更多的行时终止(退出循环)。这个例子也没有做实际的处理;在实际的例子中可用具体的处理代码替换占位符…。
关闭游标
CLOSE CustCursor
约束:管理如何插入或处理数据库数据的规则。
创建触发器:用CREATE TRIGGER语。
CREATE TRIGGER newproduct AFTER INSERT ON products
FOR EACH ROW SELECT’Product added’;
CREATE TRIGGER用来创建名为newproduct的新触发器。触发器可在一个操作发生之前或之后执行,这里给出了AFTER INSERT,所以此触发器将在INSERT语句成功执行后执行。这个触发器还指定FOR EACH ROW,因此代码对每个插入行执行。在这个例子中,文本Product added将对每个插入的行显示一次。
触发器只支持表,视图不支持(临时表也不支持)
每个表每个事件每次只允许一个触发器。因此,每个表最多支持6个触发器(每条INSERT、UPDATE和DELETE的之前和之后)。单一触发器不能与多个事件或多个表关联,所以,如果你需要一个对INSERT和UPDATE操作执行的触发器,则应该定义两个触发器。
删除触发器
DROP TRIGGER newproduct;
INSERT触发器
1.在INSER下触发器代码内,可引用一个名为NEW的虚拟表,访问被插入的行;
2.在BEFORE INSERT触发器中,NEW中的值也可以被更新(允许更改被插入的值);
3.对于AUTO INCREMENT列,NEW在INSERT执行之前包含0,在INSERT执行之后包含新的自动生成值。
新生成值
CREATE TRIGGER neworder AFTER INSERT ON orders
FOR EACH ROW SELECT NEW.order_num;
INSERT INTO orders(order_date,cust_id)
VALUES(Now(),10001);
DELETE触发器
1.在DELETE触发器代码内,你可以引用一个名为OLD的虚拟表,访问被删除的行;
2.OLD中的值全都是只读的,不能更新。
CREATE TRIGGER deleteorder BEFORE DELETE ON orders
FOR EACH ROW
BEGIN
INSERT INTO archive_orders(order_num,order_ date, cust_ id)
VALUES(OLD.order_num, OLD.order_date,OLD.cust_ id);
END;
UPDATE触发器
1.在UPDATE触发器代码中,你可以引用一个名为OLD的虚拟表访问 以前(U P DAT E语句前)的值,引用一个名为NEW的虚拟表访问新更新的值;
2.在BEFORE UPDATE触发器中,NEW中的值可能也被更新(允许更改将要用于UPDATE语句中的值);
3. OLD中的值全都是只读的,不能更新。
CREATE TRIGGER updatevendor BEFORE UPDATE ON vendors
FOR EACH ROW SET NEW.vend_ state=Upper(NEW:vend_state);
SELECT列名1,列名2,列名3
FROM表名
Where列名=数值(或其他条件);
SELECT prod_id,prod_price,prod_name
FROM products
WHERE prod_price=3.95;
网友评论