SQL是Struct Query Language(结构化查询语言)的缩写,SQL是一种专门与数据库沟通的语言
例子:SELECT prod_name FROM Products;
上述语句利用SELECT语句从Products表中检索一个名为prod_name的列
-说明:
使用 DISTINCT关键字,指示数据库返回不同的值
说明:
必须放在列名的前面
不能部分使用 DISTINCT,DISTINCT关键字作用域所有的列
SELECT TOP n colomn FROM tables;
FETCH FIRST N ROWS ONLY;
WHERE ROWNUM ..
LIMIT N
LIMIT N OFFSET M
,从m+1 行开始找n行数据LIMIT M,N
代替上述语句-常见的三种注释形式 --
#
/* */
,--
和#
用于行内注释,/**/
用于多行注释
子句(clause):SQL语句是由子句构成的,有些是必需的,有些是可选的
使用ORDER BY子句,取一个或者多个列的名字,据此对输出进行排序
** 注意**:
1.ORDER BY 语句的位置必须是SELECT语句的最后一个子句
2.可以使用非选择列进行排序
使用多个列进行排序,依次比较,只有前面的列值相同才向后进行比较
OREDER BY NUM1.NUM2,NUM3
其中num1,num2,num3 都是已经选择的列的相对位置,没有选择的列不可以使用相对位置访问
数据的排序默认使用升序排列
在SELECT语句中,根据WHERE子句中指定的搜索条件进行过滤,WHERE子句在表名(FROM子句)之后给出
语法:WHERE NAME = VALUE
语法:WHERE NAME <> VALUE
或者WHERE NAME != VALUE
语法:BETWEEN LOW AND HIGH
WHERE IS NULL
语句检查具有NULL值的列操作符:用来联结或改变WHERE子句中的子句的关键字,也称逻辑操作符(logical operator)
IN:WHERE子句中用来指定要匹配值的清单的关键字,功能与OR相当
语法:`IN(VALUE1,VALUE2,… )
NOT:WHERE子句中用来否定其后条件的关键字
通配符(wildcard):用来匹配值的一部分的特殊字符
搜索模式(search pattern):由字面值,通配符或者两者组合构成的搜索条件
在搜索子句中使用通配符,必须使用LIKE操作符
最常使用的通配符是百分号%,在搜索串中,%表示任何字符出现任意次数。语法:LIKE 'word%'
或者 LIKE '%word%'
或者LIKE %word
(_)只匹配单个字符,而不是多个字符
方括号([ ])通配符用来指定一个字符集 它必须匹配指定位置
例如:[JM]%
[JM]匹配方括号中的任意一个字符,并且只能匹配单个字符
字段(field):基本上与列意思相同,经常互换使,不过数据库列一般称为列,而字段这个术语通常在提到计算字段使用
拼接(concatenate):将值联结到一起(将一个值附加到另一个值)构成单个值
+
例子:SELECT vend_name + '(' + vend_country + ')' FROM Vendors ORDER BY vend_name
||
例子: SELECT vend_name || '(' || vend_country || ')' FROM Vendors ORDER BY vend_name
SELECT Contact(vend_name ,'(' , vend_country ,')') FROM Vendors ORDER BY vend_name
TRIM函数:大多数DBMS都支持RTRIM()(去掉字符串右边的所有空格),和LTRIM()(去掉字符串左边的所有空格)
以及TRIM()(去掉两边所有的空格)
使用别名:别名是一个字段或者值的替换名,别名用AS关键字赋予,并且真实创建了别名列,也叫导出列(derived column)
大多数DBMS支持的函数:
Left()函数:返回string字符串左边n个字符
Right()函数:返回string字符串右边n个字符
Lower()函数:大写字符转化成小写的函数
Upper()函数:小写字符转化成大写的函数
Len()/Length()函数:返回文本字段中值的长度
Substr()/Substring()函数:截取字符串中的一部分字符
Charindex()函数:返回需要查询的字符串的位置
LTRIM()函数:删除数据中左边的空格
RTRIM()函数:删除数据中右边的空格
TRIM()函数:删除数据中的空格
REPLACE()函数:替换文本中特定的字符串
常用sql聚集函数:
AVG() :返回某列的平均值
COUNT(): 返回某列的行数
MAX():返回某列的最大值
MIN():返回某列的最小值
只能用于确定特定数值列的平均值,而且列名必须作为函数参数给出
对非数值数据使用MAX()或者MIN(),返回该列排序后的最后(前)一行
例子:SELECT vend_id,COUNT(*) AS num_prods FROM Products GROUP BY vend_id;
使用HAVING 进行过滤分组,在分组之后进行过滤,结合GROUP BY 使用
SELECT FROM WHERE GROUP BY HAVING ORDER BY
子查询 也就是嵌套在其他查询里面的查询
作为子查询的select语句只能查询单个列
例如:SELECT cust_name ,cust_state,(SELECT COUNT(*) FROM Orders WHERE Orders.cust_id = Customers.cust_id) AS orders FROM Customers ORDER BY cust_name
记住要完全限定列名当查询的多个表中有相同名字的列时。
联结是一种机制,用来在一条SELECT语句中关联表
指定要联结的所有表以及关联它们的方式即可 例子:SELECT vend_name,prod_name,prod_price FROM Vendors,Products WHERE Vendors.vend_id = Products.vend_id
笛卡尔积:由没有联结关系的表关系返回的结果是笛卡尔积,检索出的行的数目将是第一个表中的行数乘以第二个表中的行数(返回笛卡尔积的联结也叫做叉联结)
所以使用Where子句是十分必要的,不然就会返回笛卡尔积作为查询结果
目前使用的联结称为等值联结,它基于两个表之间的相等测试,这种联结也称作内联结。其实也可以用关键字INNER JOIN,联结条件用ON给出,而不是简单的Where子句,来表命联结的类型。
例子:SELECT vend_id ,prod_id,prod_price FROM Vendors INNER JOIN Products ON Vendors.vend_id = Products.vend_id;
例子:SELECT prod_name,vend_name,prod_price,quantity FROM OrderItems,Products,Vendors WHERE Products.vend_id= Vendors.vend_id AND OrderItems.prod_id =Vendors.vend_id AND Order_num =20007;
1.编写SQL语句,返回Customers表中的顾客名称(cust_name)和Orders表中的相关订单号(order_num),并按顾客名称再按订单号对结果进行排序,实际上是尝试两次,一次使用简单的等值连接语法
答案:
1.SELECT cust_name,order_num
FROM Customers,Orders
WHERE Customers.cust_id=Orders.cust_id
ORDER BY cust_name,order_num;
2.SELECT cust_name, order_num
FROM Customers
INNER JOIN Orders
ON Customers.cust_id = Orders.cust_id
ORDER BY cust_name, order_num;
2.在上一题的基础上添加第三列OrderTotal,其中包含每个订单的总价,可以使用OrderItem表的子查询创建OrderTotal列,或者将OrderItems表与现有表联结并使用聚合函数。
答案:
1.SELECT cust_name, order_num,
(SELECT Sum(item_price*quantity)
FROM OrderItems
WHERE Orders.order_num=OrderItems.order_num) AS OrderTotal
FROM Customers, Orders
WHERE Customers.cust_id = Orders.cust_id
ORDER BY cust_name, order_num;
2.SELECT cust_name, Orders.order_num, Sum(item_price*quantity) AS OrderTotal
FROM Customers, Orders, OrderItems
WHERE Customers.cust_id=Orders.cust_id AND Orders.order_num = OrderItems.order_num
GROUP BY cust_name, Orders.order_num
ORDER BY cust_name, order_num;
3.编写SQL语句,检索订购的产品BR01的日期,使用联结和简单的等值联结语法
答案:SELECT cust_id, order_date
FROM Orders, OrderItems
WHERE Orders.order_num = OrderItems.order_num
AND prod_id = 'BR01'
ORDER BY order_date;
4.返回购买prod_id为BR01的产品的所有顾客的电子邮件(Customers表中的cust_email)使用两个INNER JOIN语句,并且用WHERE子句进行过滤。
答案:SELECT cust_email
FROM Customers
INNER JOIN Orders ON Customers.cust_id = Orders.cust_id
INNER JOIN OrderItems ON Orders.order_num = OrderItems.order_num
WHERE prod_id = 'BR01';
5.使用联结从Customers表返回顾客名称(cust_name),并从OrderItems表中返回所有订单的总价
答案:
1.SELECT cust_name, SUM(item_price*quantity) AS total_price
FROM Customers, Orders, OrderItems
WHERE Customers.cust_id = Orders.cust_id
AND Orders.order_num = OrderItems.order_num
GROUP BY cust_name HAVING SUM(item_price*quantity) >= 1000
ORDER BY cust_name;
2.SELECT cust_name, SUM(item_price*quantity) AS total_price
FROM Customers
INNER JOIN Orders ON Customers.cust_id = Orders.cust_id
INNER JOIN OrderItems ON Orders.order_num = OrderItems.order_num
GROUP BY cust_name
HAVING SUM(item_price*quantity) >= 1000
ORDER BY cust_name;
使用表别名的好处:
1.缩短SQL语句
2.允许在一条SQL语句中多次使用相同的表
例子:.SELECT cust_name, order_num
FROM Customers AS C,Orders AS O
WHERE C.cust_id = O.cust_id
ORDER BY cust_name, order_num;
查询和Jim Jones一个公司的所有员工
使用子查询:
例子:SELECT cust_id,cust_name,cust_contact
FROM Customers
WHERE cust_name = ( SELECT cust_name
FROM Customers
WHERE cust_contact = 'Jim Jones');
使用自联结
SELECT c1.cust_id,c1.cust_name,c1.cust_contact
FROM Customers AS c1,Customers AS c2
WHERE c1.cust_name=c2.cust_name AND c2.cust_contact ='Jim Jones';
自然联结排除多次出现,使每一列只返回一次。
SELECT C.*,Order.order_num,O.order_date,
OI.prod_id,OI.quantity,OI.item.price
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'
外联结有三种基本类型:左外联结(LEFT OUTER JOIN)和右外联结(RIGHT OUTER JOIN),全外联结(FULL OUTER JOIN) 。
左外联结和右外联结分别包含左表(右表)的不关联行,全外联结包含两个表不关联的行。
例子:SELECT Customers.cust_id,
COUNT(Orders.prder_num) AS num_ord
FROM Customers
INNER JOIN Orders ON Customers.cust_id = Orders.cust_id
GROUP BY Customers.cust_id
SQL允许执行多个查询,并将结果作为一个查询结果集返回,这些组合查询通常称为union(并)查询或者复合查询(compound query)
使用UNION操作符来组合数条SQL查询,将结果组合成一个结果集。
在每条SELECT语句之间放上关键字UNION
例子: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'
UNION语句必须由两条或者两条以上的SELECT语句组成,语句之间用关键字UNION分隔
UNION中的查询必须包含相同的列,表达式或聚集函数
列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含转换的类型
UNION的列名:
如果遇到不一样的名字,默认返回第一个名字,第二个名字可以是第一个列的别名,查询结果中只有(返回)第一个名字
union默认去除重复的行,如果想返回所有的行,可以使用UNION ALL
ORDER BY 子句必须在最后面,也就是说只允许一种排序方式
其他类型的UNION:EXCEPT可以用于检索只存在于第一个表的数据,INTERSECT可以检索两个表中都存在的数据
使用INSERT插入数据,可以分为三种,插入完整的行,插入行的一部分,插入某些查询的结果
例子:
INSERT INTO Customers
VALUES(100000006
'Toy Land',
'123 Any Street',
'New York',
'NY',
'1111',
'USA',
NULL,
NULL
)
这种插入方式的赋值是按列的固定顺序来进行的,并不安全
推荐使用另一种方式(如下)
INSERT INTO Customers(
cust_id,
cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country,
cust_contact,
cust_email
)
VALUES(100000006
'Toy Land',
'123 Any Street',
'New York',
'NY',
'1111',
'USA',
NULL,
NULL
)
省略列:在使用Insert插入时可以允许部分列省略,那些列允许NULL值(无值或者空值)或者在表中定义中给出默认值
使用INSERT SELECT
例子:
INSERT INTO Customers(
cust_id,
cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country,
cust_contact,
cust_email
)
SELECT
cust_id,
cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country,
cust_contact,
cust_email
FROM CustNew;
使用CREATE SELECT语句将一个表的内容复制到另一个表中。
CREATE TABLE CustCopy AS SELECT * FROM Customers;
使用SQLServer:
SELECT * INTO CustCopy FROM Customers;
select into 使用时:
使用update语句更新(修改)表中的数据:
例子:
UPDATE Customers
SET cust_email = '[email protected]'
WHERE cust_id = 1000000005;
更新更多列的操作:
例子:UPDATE Customers
SET cust_email = '[email protected]',
cust_email = Sam Roberts
WHERE cust_id = 1000000005;
UPDATE语句可以使用子查询
要删除某一列的值,你可以设置它为NULL
DELETE 语句:
删除一行数据
例子:DELETE FROM Customers
WHERE cust_id = 1000000006;
如果有外键的存在,delete语句会抛出错误并终止
FROM关键字是可选的,但是为了可移植性,我们通常保留
一般创建的方式有两种:
使用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 DECIMAL(8,2) NOT NULL,
prod_desc VARCHAR(1000) NULL
);
在创建新的表时,指定的表必须不存在,否则会出错。
每个表要么是NULL值要么是非NULL值,根据创建时表的定义决定。
ALTER TABLE 语句,虽然所有的DBMS都支持ALTER TABLE,但它们所允许更新的内容差别很大。
给已有表增加列时所有DBMS都支持的唯一操作,
例子:ALTER TABLE Vendors
ADD vend_phone CHAR(20);
复杂的表结构更改一般需要手动删除过程:
DROP TABLE 语句
DROP TABLE CustCopy;
每个DBMS对表重命名的支持有所不同 ,DB2,MariaDB,MySQL,Oracle,PostgreSQL使用RENAME语句,SQL server使用sp_rename存储过程,SQLite使用ALTER TABLE语句。
视图是虚拟的表,只包含动态检索数据的查询
例子: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';
常见应用:
常见的限制:
CREATE VIEW 语句来创建,与CREATE TABLE语句一样,CREATE VIEW只能用于创建不存在的视图
视图最常见的应用就是隐藏复杂的SQL,这通常涉及联结
例子:
CREATE VIEW
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';
例子:SELECT RTRIM(vend_name)+'('+RTRIM(vend_country)+')'
AS vend_title
FROM Vendors
ORDER BY vend_name
CREATE VIEW
SELECT RTRIM(vend_name)+'('+RTRIM(vend_country)+')'
AS vend_title
FROM Vendors
SELECT * FROM VendorLocations;
例子:CREATE VIEW CustomerEMailList AS
SELECT cust_id,cust_name,cust_email
FROM Customers
WHERE cust_email IS NOT NULL;
例子:CREATE VIEW OrderItemExpanded AS
SELECT prod_id,
quantity,
item_price
quantity * item_price AS expanded_price
FROM OrderItems
创建存储过程,简单的来讲就是,为以后使用保存的一条或者多条SQL语句,可以讲其视为批文件。
使用EXCUTE关键字,EXCUTE接收存储过程名和需要传递给它的任何参数。
例子:EXCUTE AddNewProduct('JTS01',
'Stuffed Effiel Tower',
'6.49',
'Plush stuffed toy with the text Tour Eiffel in red white and blue' );
Orcle 版本:
CREATE PROCEDURE MailingListCount (
ListCount OUT INTEGER)
IS
v_rows INTERGER;
BEGIN
SELECT COUNT(*) INTO v_rows
FROM Customers
WHERE NOT cust_email IS NULL;
ListCount := v_rows;
ENDS;
该存储过程有一个参数ListCount,此参数从存储过程返回一个值而不是传递一个值给存储过程。OUT用来指示这种行为。
Oracle 支持IN(传递值给存储过程),OUT(从存储过程返回值,如这里),INOUT(既传递值给存储过程也从存储过程返回值)三个参数。
调用(Oracle)例子:
var ReturnValue NUMBER
EXEC MailingListCount(:ReturnValue);
SELECT ReturnValue;
声明ReturnValue 保存存储过程返回的所有值,然后执行过程,最后使用SELECT语句显示返回值
SQL Server版本
CREATE PROCEDURE MailingListCount
AS
DECLARE @cnt INTEGER
SELECT @cnt = COUNT(*)
FROM Customers
WHERE NOT cust_email IS NULL;
RETURN @ cnt;
@cnt是一个局部变量,然后再SELECT语句中使用这个变量,让它包含COUNT()函数返回的值,最后RETURN @cnt 语句计数返回给调用程序。
调用:
DECLARE @ReturnValue INT
EXECUTE @ReturnValue=MailingListCount;
SELECT @ReturnValue;
例子:CREATE PROCEDURE NewOrder @cust_id CHAR(10)
AS
--为这个订单号声明一个变量
SELECT @order_num = MAX(order_num)
FROM Orders
--决定下一个订单号
SELECT @order_num =@order_num+1
--插入新订单
INSERT INTO Orders(order_num,order_date,cust_id)
VALUES(@order_num,GETDATE(),@cust_id)
--返回订单号
RETURN @order_num;
为Orders表创建一个新订单,只有一个参数,下一个顾客的ID,订单号和日期自动生成。
CREATE PROCEDURE NewOrder @cust_id CHAR(10)
AS
--插入新订单
INSERT INTO Orders(cust_id)
VALUES(@cust_id)
--返回订单号
SELECT order_num = @@IDENTITY;
借助SQLSever 的自动增量列,生成order_num,并使用@@IDENTITY获取
事务处理(transaction processing):确保成批的操作要么完全执行,要么完全不执行
事务(transaction):指一组SQL语句
回退(rollback):撤销指定SQL语句的过程
提交(commit):指将未存储的SQL语句结果写入数据库表;
保留点(savepoint):指事务处理中设置的临时占位符(placeholder),可以对它发布回退
SQL Server:
BEGIN TRANSACTION
....
COMMIT TRANSACTION
MariaDB MYSQL:
START TRANSACTION
....
Oracle:
START TRASACTION
...
PostgreSQL
BEGIN
...
DELETE FROM Orders;
ROLLBACK;
SQL Server:
BEGIN TRANSACTION
DELETE OrderItems WHERE order_num =12345
DELETE Orders WHERE order_num = 12345
COMMIT TANSACTION
Oracle:
SET TANSACTION
DELETE OrderItems WHERE order_num =12345;
DELETE Order_num=12345
COMMIT;
MariaDB,MySQL,Oracle中创建占位符:
SAVEPOINT xxxx
ROLLBACK TO delete1
SQL Server中:
SAVE TRANSACTION delete1;
ROLLBACK TRANSACTION delete1
定义保留点,配合rollback语句回退到该点
游标(cursor)是一个存储在DBMS服务器上的数据库查询,它不是一条SELECT语句,而是被该语句检索出来结果集。
游标的常见特性:
MariaDB,MySQL,DB2,SQL Server版本
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 CustCursor
使用FETCH从游标中检索第一行(Oracle)
DECLARE TYPE CustCursor IS REF CURSOR
RETURN Customers%ROWTYPE;
DECLARE CustRecord Customers%ROWTYPE
BEGIN
OPEN CustCursor
FETCH CustCursor INTO CustRecord;
CLOSE CustCursor;
END;
检索所有行
DECLARE TYPE CustCursor IS REF CURSOR
RETURN Customers%ROWTYPE;
DECLARE CustRecord Customers%ROWTYPE
BEGIN
OPEN CustCursor
LOOP
FETCH CustCursor INTO CustRecord;
EXIT WHEN CustCursor%NOTFOUND;
END LOOP
CLOSE CustCursor;
END;
CLOSE CustCursor
Microsoft SQL Server:
CLOSE CustCursor
DEALLOCATE CURSOR CustCursor
约束(constraint):管理如何插入数据或处理数据库的规则
主键是一种特殊的约束,保证一列的值唯一且永不改动
使用PRIMARY KEY关键字,定义主键:
CREATE TABLE Products
(
prod_id CHAR(10) NOT NULL PRIMARY KEY,
vend_id CHAR(10) NOT NULL,
prod_name CHAR(254) NOT NULL,
prod_price DECIMAL(8,2) NOT NULL,
prod_desc VARCHAR(1000) NULL
);
或者:
ALTER TABLE Porducts
ADD CONTRAINT PRIMARY KEY (vend_id);
外键是表中的一列,其值必须在另一个表的主键中。外键是保证引用完整性的极其重要的部分。
例子:
CREATE TABLE Orders( order_num INTERGER NOT NULL PRIMARY KEY, order_date DATETIME NOT NULL, cust_id CHAR(10) NOT NULL REFERENCES Customers(cust_id))
同样可以使用CONSTRAINT语法来完成
ALTER TABLE Orders
ADD CONSTRAINT
FOREIGN KEY (cust_id)REFERENCE Customers(cust_id);
唯一约束用来保证表中的数据是唯一的,类似于主键
区别:
可以使用UNIQUE关键字来定义唯一约束
检查约束用来保证一列或者(一组列中的数据满足一组指定的条件)
常见用途:
在创建表时 CHECK
CREATE TABLE Products
(
prod_id CHAR(10) NOT NULL PRIMARY KEY,
vend_id CHAR(10) NOT NULL CHECK(...),
prod_name CHAR(254) NOT NULL,
prod_price DECIMAL(8,2) NOT NULL,
prod_desc VARCHAR(1000) NULL
);
使用constraint语法
ADD CONSTRAINT CHECK (gender LIKE ‘[MF]’);
索引用来排序数据以加快搜索和排序操作的速度
索引的特性:
使用CREATE INDEX创建
例子:
CREATE INDEX prod_name_ind
ON Porducts (prod_name);
触发器是特殊的存储过程,它在特定的数据库活动发生时自动执行,触发器可以和特定表上的INSERT,UPDATE,DELETE(或组合)相关联。
触发器内的代码有以下数据的访问权:
CREATE TRIGGER customer_state
ON Customers
FOR INSERT,UPDATE
AS
UPDATE Customers
SET cust_state = upper(cust_state)
WHERE Customers.cust_id = inserted.cust_id;
未完待续…