• SQL必知必会


    SELECT DISTINCT vend_id FROM Products; 

    注意:不能部分使用 DISTINCT DISTINCT 关键字作用于所有的列,不仅仅是跟在其后的那一列。例 如,你指定 SELECT DISTINCT vend_id, prod_price,除非指定的 两列完全相同,否则所有的行都会被检索出来。 

    SELECT prod_name FROM Products LIMIT 5; 

    上述代码使用SELECT语句来检索单独的一列数据。LIMIT 5指示MySQL 等 DBMS返回不超过 5行的数据.

    SELECT prod_name FROM Products LIMIT 5 OFFSET 5; 

    LIMIT 5 OFFSET 5 指示 MySQL等 DBMS返回从第 5行起的 5行数据。 第一个数字是指从哪儿开始,第二个数字是检索的行数。

    【排序】

    SELECT prod_name FROM Products ORDER BY prod_name;  

    除了指示 DBMS软件对 prod_name 列以字母顺序排序数据的 ORDER BY 子句外,这条语句与前面的语句相同。

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

    检索 3 个列,并按其中两个列对结果进行排序——首先按价 格,然后按名称排序。

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

    除了能用列名指出排序顺序外,ORDER BY 还支持按相对列位置进行排 序。

    这里的输出与上面的查询相同,不同之处在于 ORDER BY 子 句。SELECT 清单中指定的是选择列的相对位置而不是列名。ORDER BY 2 表示按 SELECT 清单中的第二个列 prod_name 进行排序。ORDER BY 2, 3 表示先按 prod_price,再按 prod_name 进行排序。 

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

    以价格降序来排序产品(最贵的排在最前面): 

    数据排序不限于升序排序(从 A到 Z),这只是默认的排序顺序。还可以 使用 ORDER BY 子句进行降序(从 Z到 A)排序。为了进行降序排序, 必须指定 DESC 关键字。 

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

    警告:在多个列上降序排序 如果想在多个列上进行降序排序,必须对每一列指定 DESC 关键字。 

    DESC关键字只应用到直接位于其前面的列名。在上例中,只对prod_price 列指定 DESC,对 prod_name 列不指定。因此,prod_price 列以降序排 序,而 prod_name 列(在每个价格内)仍然按标准的升序排序。 

    区分大小写和排序顺序 

    在字典(dictionary)排序顺序中,A 被视为与 a 相同,这是大多数数 据库管理系统的默认行为。但是,许多 DBMS允许数据库管理员在需 要时改变这种行为(如果你的数据库包含大量外语字符,可能必须这 样做)。

    这里的关键问题是,如果确实需要改变这种排序顺序,用简单的 ORDER BY 子句可能做不到。你必须请求数据库管理员的帮助。 

    【过滤】

    SELECT prod_name, prod_price FROM Products WHERE prod_price = 3.49; 

    这个示例使用了简单的相等检验:检查这一列的值是否为指定值,据此 过滤数据。

    提示:SQL 过滤与应用过滤 

      数据也可以在应用层过滤。为此,SQL的 SELECT 语句为客户端应用 检索出超过实际所需的数据,然后客户端代码对返回数据进行循环, 提取出需要的行。

      通常,这种做法极其不妥。优化数据库后可以更快速有效地对数据进 行过滤。而让客户端应用(或开发语言)处理数据库的工作将会极大 地影响应用的性能,并且使所创建的应用完全不具备可伸缩性。此外, 如果在客户端过滤数据,服务器不得不通过网络发送多余的数据,这 将导致网络带宽的浪费。

    注意:WHERE 子句的位置 

    在同时使用 ORDER BY 和 WHERE 子句时,应该让 ORDER BY 位于 WHERE 之后,否则将会产生错误。

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

    提示:何时使用引号 如果仔细观察上述 WHERE 子句中的条件,会看到有的值括在单引号内, 而有的值未括起来。单引号用来限定字符串。如果将值与字符串类型的 列进行比较,就需要限定引号。用来与数值列进行比较的值不用引号。

    SELECT vend_id, prod_name FROM Products WHERE vend_id != 'DLL01'; 

    注意:是!=还是<>? !=和<>通常可以互换。但是,并非所有 DBMS都支持这两种不等于操 作符。

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

    从这个例子可以看到,在使用 BETWEEN 时,必须指定两个值——所需范 围的低端值和高端值。这两个值必须用 AND 关键字分隔。BETWEEN 匹配 范围中所有的值,包括指定的开始值和结束值。 

    SELECT prod_name FROM Products WHERE prod_price IS NULL; 

    NULL 无值(no value),它与字段包含 0、空字符串或仅仅包含空格不同。 

    确定值是否为 NULL,不能简单地检查是否= NULL。SELECT 语句有一个 特殊的 WHERE 子句,可用来检查具有 NULL 值的列。这个 WHERE 子句就 是 IS NULL 子句。

    过滤数据时,一定要验证被过滤列中含 NULL 的行确实出现在返回的 数据中。 

    【高级过滤】

    SELECT prod_id, prod_price, prod_name FROM Products WHERE vend_id = 'DLL01' AND prod_price = 4

    不只可以增加一个AND

    SELECT prod_name, prod_price FROM Products WHERE vend_id = 'DLL01' OR vend_id = ‘BRS01’; 

    OR 是 WHERE 子句中使用的关键字,用来表示检索匹配任一给定条件的行。 

    SELECT prod_name, prod_price FROM Products WHERE (vend_id = 'DLL01' OR vend_id = 'BRS01')       AND prod_price >= 10; 

    因为圆括号具有比 AND 或 OR 操作符更高的求值顺序,AND比OR操作符优先级高,所以 DBMS 首先过滤圆括号内的OR条件。这时,SQL语句变成了选择由供应商DLL01 或 BRS01 制造的且价格在 10 美元及以上的所有产品,这正是我们希望 的结果。 

    提示:在 WHERE 子句中使用圆括号 任何时候使用具有 AND 和 OR 操作符的 WHERE 子句,都应该使用圆括 号明确地分组操作符。不要过分依赖默认求值顺序,即使它确实如你 希望的那样。使用圆括号没有什么坏处,它能消除歧义。 

    SELECT prod_name, prod_price FROM Products WHERE vend_id IN ( 'DLL01', 'BRS01' ) ORDER BY prod_name; 

    此 SELECT 语句检索由供应商 DLL01 和 BRS01 制造的所有产品。IN 操作 符后跟由逗号分隔的合法值,这些值必须括在圆括号中。 

    你可能会猜测 IN 操作符完成了与 OR 相同的功能,恭喜你猜对了!下面 的 SQL语句完成与上面的例子相同的工作。 

    SELECT prod_name, prod_price FROM Products WHERE vend_id = 'DLL01' OR vend_id = 'BRS01' ORDER BY prod_name; 

    为什么要使用IN

      在有很多合法选项时,IN 操作符的语法更清楚,更直观。 

      在与其他 AND 和 OR 操作符组合使用 IN 时,求值顺序更容易管理。 

      IN 操作符一般比一组 OR 操作符执行得更快(在上面这个合法选项很 少的例子中,你看不出性能差异)。 

      IN 的最大优点是可以包含其他 SELECT 语句,能够更动态地建立 WHERE 子句。

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

    这里的 NOT 否定跟在其后的条件,因此,DBMS 不是匹配 vend_id 为 DLL01,而是匹配非 DLL01 之外的所有东西。
    上面的例子也可以使用<>操作符来完成,如下所示。

    SELECT prod_name FROM Products WHERE vend_id <> 'DLL01' ORDER BY prod_name; 

    为什么使用 NOT?对于这里的这种简单的 WHERE 子句,使用 NOT 确实 没有什么优势。但在更复杂的子句中,NOT 是非常有用的。例如,在 与 IN 操作符联合使用时,NOT 可以非常简单地找出与条件列表不匹配 的行。

    【用通配符进行过滤】

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

    此例子使用了搜索模式'Fish%'。在执行这条子句时,将检索任意以Fish 起头的词。%告诉 DBMS接受 Fish 之后的任意字符,不管它有多 少字符。

    说明:区分大小写 根据 DBMS的不同及其配置,搜索可以是区分大小写的。如果区分大 小写,则'fish%'与 Fish bean bag toy 就不匹配。 

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

    说明:请注意后面所跟的空格,更好的解决办法是用函数去掉空格。

    通配符%看起来像是可以匹配任何东西,但有个例外,这就是 NULL。 子句 WHERE prod_name LIKE '%'不会匹配产品名称为 NULL 的行。

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

    与%能匹配 0个字符不同,_总是刚好匹配一个字符,不能多也不能少。 

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

    找出所有名字以 J 或 M 起头的联系人;此语句的 WHERE 子句中的模式为'[JM]%'。这一搜索模式使用了两个不 同的通配符。[JM]匹配方括号中任意一个字符,它也只能匹配单个字符。 因此,任何多于一个字符的名字都不匹配。[JM]之后的%通配符匹配第 一个字符之后的任意数目的字符,返回所需结果。 

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

    此通配符可以用前缀字符^(脱字号)来否定。下面同样效果。

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

    不要过度使用通配符。如果其他操作符能达到相同的目的,应该使用 其他操作符。 

    在确实需要使用通配符时,也尽量不要把它们用在搜索模式的开始 处。把通配符置于开始处,搜索起来是最慢的。 

    仔细注意通配符的位置。如果放错地方,可能不会返回想要的数据。 

    【创建计算字段】

    SELECT Concat(vend_name, ' (', vend_country, ')') FROM Vendors ORDER BY vend_name; 

    拼接字符串

    SELECT RTRIM(vend_name) + ' (' + RTRIM(vend_country) + ')' FROM Vendors ORDER BY vend_name; 

    RTRIM()函数去掉值右边的所有空格。通过使用 RTRIM(),各个列都进 行了整理。 

    SELECT Concat(vend_name, ' (', vend_country, ')')        AS vend_title FROM Vendors ORDER BY vend_name; 

    SELECT 语句本身与以前使用的相同,只不过这里的计算字段之后跟了文 本 AS vend_title。它指示 SQL 创建一个包含指定计算结果的名为 vend_title 的计算字段。从输出可以看到,结果与以前的相同,但现 在列名为 vend_title,任何客户端应用都可以按名称引用这个列,就像 它是一个实际的表列一样。 

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

    输出中显示的 expanded_price 列是一个计算字段,此计算为 quantity* item_price。客户端应用现在可以使用这个新计算列,就像使用其他列 一样。 

    【使用函数处理数据】

    下面给出一个使用 SOUNDEX()函数的例子。Customers 表中有一个顾客 Kids Place,其联系名为 Michelle Green。但如果这是错误的输入, 此联系名实际上应该是 Michael Green,该怎么办呢?显然,按正确的 联系名搜索不会返回数据,如下所示: 

    SELECT cust_name, cust_contact FROM Customers WHERE cust_contact = 'Michael Green'; 

    没有记录

    SELECT cust_name, cust_contact FROM Customers WHERE SOUNDEX(cust_contact) = SOUNDEX('Michael Green'); 

    Kids Place                     Michelle Green 

    【汇总数据】

     

    SELECT AVG(prod_price) AS avg_price FROM Products; 

    子使用 AVG()返回 Products 表中所有产品的平均价格。

    注意:只用于单个列 AVG()只能用来确定特定数值列的平均值,而且列名必须作为函数参 数给出。为了获得多个列的平均值,必须使用多个 AVG()函数。 

    说明:NULL 值 AVG()函数忽略列值为 NULL 的行。 

    SELECT COUNT(*) AS num_cust FROM Customers; 
    

    在此例子中,利用 COUNT(*)对所有行计数,不管行中各列有什么值。计 数值在 num_cust 中返回。 就是返回这个表有多少条记录。

    SELECT COUNT(cust_email) AS num_cust FROM Customers;

    这条 SELECT 语句使用 COUNT(cust_email)对 cust_email 列中有值的 行进行计数。

    说明:NULL 值 如果指定列名,则 COUNT()函数会忽略指定列的值为空的行,但如果 COUNT()函数中用的是星号(*),则不忽略。 

    SELECT MAX(prod_price) AS max_price FROM Products; 

    这里,MAX()返回 Products 表中最贵物品的价格。 

    提示:对非数值数据使用 MAX() 虽然 MAX()一般用来找出最大的数值或日期值,但许多(并非所有) DBMS 允许将它用来返回任意列中的最大值,包括返回文本列中的最 大值。在用于文本数据时,MAX()返回按该列排序后的最后一行。 

    说明:NULL 值 MAX()函数忽略列值为 NULL 的行。 

    SELECT MIN(prod_price) AS min_price FROM Products; 

    其中 MIN()返回 Products 表中最便宜物品的价格。 

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

    提示:在多个列上进行计算 如本例所示,利用标准的算术操作符,所有聚集函数都可用来执行多 个列上的计算。 

    说明:NULL 值 SUM()函数忽略列值为 NULL 的行。 

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

    在使用了 DISTINCT 后,此例子中的 avg_price 比较高,因 为有多个物品具有相同的较低价格。排除它们提升了平均价格。 

    注意:DISTINCT 不能用于 COUNT(*) 如果指定列名,则 DISTINCT 只能用于 COUNT()。DISTINCT 不能用 于 COUNT(*)。类似地,DISTINCT 必须使用列名,不能用于计算或表 达式。

    提示:将 DISTINCT 用于 MIN()和 MAX() 虽然 DISTINCT 从技术上可用于 MIN()和 MAX(),但这样做实际上没 有价值。一个列中的最小值和最大值不管是否只考虑不同值,结果都 是相同的。

    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; 

    这里用单条 SELECT 语句执行了 4个聚集计算,返回 4个值(Products 表中物品的数目,产品价格的最高值、最低值以及平均值)。 

    【分组数据】

    SELECT vend_id, COUNT(*) AS num_prods FROM Products GROUP BY vend_id; 

    上面的 SELECT 语句指定了两个列:vend_id 包含产品供应商的 ID, num_prods 为计算字段(用 COUNT(*)函数建立)。GROUP BY 子句指示 DBMS按 vend_id 排序并分组数据。这就会对每个 vend_id 而不是整个 表计算 num_prods 一次。从输出中可以看到,供应商 BRS01 有 3 个产 品,供应商 DLL01 有 4 个产品,而供应商 FNG01 有 2 个产品。 因为使用了 GROUP BY,就不必指定要计算和估值的每个组了。系统会自 动完成。GROUP BY 子句指示 DBMS 分组数据,然后对每个组而不是整 个结果集进行聚集。 

    SELECT cust_id, COUNT(*) AS orders FROM Orders GROUP BY cust_id HAVING COUNT(*) >= 2; 

    这条 SELECT 语句的前三行类似于上面的语句。后一行增加了 HAVING 子句,它过滤 COUNT(*) >= 2(两个以上订单)的那些分组。 

    可以看到,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; 

    它列出具有两个以上产品且其价格 大于等于 4 的供应商

    这条语句中,第一行是使用了聚集函数的基本 SELECT 语句,很像前面的 例子。WHERE 子句过滤所有 prod_price 至少为 4 的行,然后按 vend_id 分组数据,HAVING 子句过滤计数为 2或 2以上的分组。

    SELECT order_num, COUNT(*) AS items FROM OrderItems GROUP BY order_num HAVING COUNT(*) >= 3 ORDER BY items, order_num; 

    在这个例子中,使用 GROUP BY 子句按订单号(order_num 列)分组数 据,以便 COUNT(*)函数能够返回每个订单中的物品数目。HAVING 子句 过滤数据,使得只返回包含三个或更多物品的订单。后,用 ORDER BY 子句排序输出。 

    一般在使用 GROUP BY 子句时,应该也给出 ORDER BY 子句。这是保 证数据正确排序的唯一方法。千万不要仅依赖 GROUP BY 排序数据。

    【使用子查询】

    订单存储在两个表中。每个订单包含订单编号、客户 ID、订单日期,在 Orders 表中存储为一行。各订单的物品存储在相关的 OrderItems 表中。Orders 表不存储顾客信息,只存储顾客 ID。顾客的 实际信息存储在 Customers 表中。 

    现在,假如需要列出订购物品 RGAN01 的所有顾客,应该怎样检索?下面列出具体的步骤。 

    (1) 检索包含物品 RGAN01 的所有订单的编号。 

    (2) 检索具有前一步骤列出的订单编号的所有顾客的 ID。 

    (3) 检索前一步骤返回的所有顾客 ID的顾客信息。 

    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 语句只能查询单个列。企图检索多个列将返回 错误。 

    注意:子查询和性能 这里给出的代码有效,并且获得了所需的结果。但是,使用子查询并 不总是执行这类数据检索的最有效方法。

    使用子查询的另一方法是创建计算字段。假如需要显示 Customers 表中 每个顾客的订单总数。订单与相应的顾客 ID存储在 Orders 表中。 

    (1) 从 Customers 表中检索顾客列表。

    (2) 对于检索出的每个顾客,统计其在 Orders 表中的订单数目。

    SELECT cust_name, cust_state, (SELECT COUNT(*) FROM Orders WHERE Orders.cust_id = Customers.cust_id) AS orders FROM Customers  ORDER BY cust_name; 

    【联结表】

    建立两个表:一个存储供应商信息,另一个存储产品信 息。Vendors 表包含所有供应商信息,每个供应商占一行,具有唯一的 标识。此标识称为主键(primary key),可以是供应商 ID 或任何其他唯 一值。

    Products 表只存储产品信息,除了存储供应商 ID(Vendors 表的主键) 外,它不存储其他有关供应商的信息。Vendors 表的主键将 Vendors 表 与 Products 表关联,利用供应商 ID能从 Vendors 表中找出相应供应 商的详细信息。 

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

    where创建联结

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

    此语句中的 SELECT 与前面的 SELECT 语句相同,但 FROM 子句不同。这 里,两个表之间的关系是以 INNER JOIN 指定的部分 FROM 子句。在使用 这种语法时,联结条件用特定的 ON 子句而不是 WHERE 子句给出。传递 给 ON 的实际条件与传递给 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; 

    DBMS 在运行时关联指定的每个表,以处理联结。这种处理可能非常 耗费资源,因此应该注意,不要联结不必要的表。联结的表越多,性 能下降越厉害。 

    【创建高级联结】

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

    可以看到,FROM 子句中的三个表全都有别名。Customers AS C 使用 C 作为 Customers 的别名,如此等等。这样,就可以使用省略的 C 而不用 全名 Customers。在这个例子中,表别名只用于 WHERE 子句。其实它不 仅能用于 WHERE 子句,还可以用于 SELECT 的列表、ORDER BY 子句以及 其他语句部分。 

    自联结

    SELECT cust_id, cust_name, cust_contact 
    FROM Customers
    WHERE cust_name = (SELECT cust_name FROM Customers WHERE cust_contact = 'Jim Jones');

    这是第一种解决方案,使用了子查询。内部的 SELECT 语句做了一个简 单检索,返回Jim Jones工作公司的 cust_name。

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

    此查询中需要的两个表实际上是相同的表,因此 Customers 表在 FROM 子句中出现了两次。虽然这是完全合法的,但对 Customers 的引用具有 歧义性,因为 DBMS不知道你引用的是哪个 Customers 表。 解决此问题,需要使用表别名。Customers 第一次出现用了别名 C1,第 二次出现用了别名 C2。

    SELECT Customers.cust_id, Orders.order_num FROM Customers INNER JOIN Orders  ON Customers.cust_id = Orders.cust_id; 

    内联结,检索所有顾客及其订单。

    SELECT Customers.cust_id, Orders.order_num FROM Customers LEFT OUTER JOIN Orders  ON Customers.cust_id = Orders.cust_id; 

    要记住,总是有两种基本的外联结形式:左外联结和右外联结。它们 之间的唯一差别是所关联的表的顺序。换句话说,调整 FROM 或 WHERE 子句中表的顺序,左外联结可以转换为右外联结。因此,这两种外联 结可以互换使用,哪个方便就用哪个。 

    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; 

    对每个顾客的订单计数,将它作为 num_ord 返回。 

    【组合查询】

    SELECT cust_name, cust_contact, cust_email FROM Customers WHERE cust_state IN ('IL','IN','MI'); 

    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') 
    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 可能比使用 WHERE 子句更为复杂。但 对于较复杂的过滤条件,或者从多个表(而不是一个表)中检索数据的 情形,使用 UNION 可能会使处理更简单。 

    1.UNION 必须由两条或两条以上的 SELECT 语句组成,语句之间用关键 字UNION分隔(因此,如果组合四条SELECT语句,将要使用三个UNION 关键字)。 

    2.UNION 中的每个查询必须包含相同的列、表达式或聚集函数(不过, 各个列不需要以相同的次序列出)。 

    3.列数据类型必须兼容:类型不必完全相同,但必须是 DBMS可以隐含 转换的类型(例如,不同的数值类型或不同的日期类型)。 

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

    使用 UNION ALL,DBMS不取消重复的行。

    UNION 几乎总是完成与多个 WHERE 条件相同 的工作。UNION ALL 为 UNION 的一种形式,它完成 WHERE 子句完成 不了的工作。如果确实需要每个条件的匹配行全部出现(包括重复行), 就必须使用 UNION ALL,而不是 WHERE。 

    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' ORDER BY cust_name, cust_contact;

    SELECT 语句的输出用 ORDER BY 子句排序。在用 UNION 组合查询时,只 能使用一条 ORDER BY 子句,它必须位于最后一条 SELECT 语句之后。

    虽然ORDER BY 子句似乎只是最后一条 SELECT 语句的组成部分,但实际上 DBMS将 用它来排序所有 SELECT 语句返回的所有结果。

    【数据插入】

    INSERT INTO Customers VALUES('1000000006',        'Toy Land',        '123 Any Street',        'New York',        'NY',        '11111',        'USA',        NULL,        NULL); 

    把数据插入表中的最简单方法是使用基本的 INSERT 语法,它要求指定 表名和插入到新行中的值。

    这个例子将一个新顾客插入到 Customers 表中。存储到表中每一列的数 据在 VALUES 子句中给出,必须给每一列提供一个值。如果某列没有值, 如上面的 cust_contact 和 cust_email 列,则应该使用 NULL 值(假定 表允许对该列指定空值)。各列必须以它们在表定义中出现的次序填充。

    虽然这种语法很简单,但并不安全,应该尽量避免使用。

    列名value对应

    这个例子与前一个 INSERT 语句的工作完全相同,但在表名后的括号里 明确给出了列名。在插入行时,DBMS 将用 VALUES 列表中的相应值填 入列表中的对应项。

    其优点是,即使表的结构改变,这条 INSERT 语句仍然能正确工作。

    没有给 cust_contact 和 cust_email 这两列提 供值。这表示没必要在 INSERT 语句中包含它们。因此,这里的 INSERT 语句省略了这两列及其对应的值。
    如果表的定义允许,则可以在 INSERT 操作中省略某些列。省略的列 必须满足以下某个条件。 

      该列定义为允许 NULL 值(无值或空值)。 

      在表定义中给出默认值。这表示如果不给出值,将使用默认值。 

    这个例子使用 INSERT SELECT 从 CustNew 中将所有数据导入 Customers。

    INSERT 通常只插入一行。要插入多行,必须执行多个 INSERT 语句。 INSERT SELECT是个例外,它可以用一条INSERT插入多行,不管SELECT 语句返回多少行,都将被 INSERT 插入。  

     

    CREATE TABLE CustCopy AS SELECT * FROM Customers; 

    这条 SELECT 语句创建一个名为 CustCopy 的新表,并把 Customers 表 的整个内容复制到新表中。因为这里使用的是 SELECT *,所以将在 CustCopy 表中创建(并填充)与 Customers 表的每一列相同的列。要 想只复制部分的列,可以明确给出列名,而不是使用*通配符。 

    【更新删除数据】

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

    客户 1000000005 现在有了电子邮件地址,因此他的 记录需要更新

    UPDATE Customers SET cust_contact = 'Sam Roberts',     cust_email = 'sam@toyland.com' WHERE cust_id = '1000000006'; 

    在更新多个列时,只需要使用一条 SET 命令。

    UPDATE Customers SET cust_email = NULL WHERE cust_id = '1000000005'; 

    其中NULL用来去除cust_email列中的值。这与保存空字符串很不同(空 字符串用''表示,是一个值),而 NULL 表示没有值。 

    DELETE FROM Customers WHERE cust_id = '1000000006'; 

    DELETE FROM 要求指定从中删除数据的表名, WHERE 子句过滤要删除的行。在这个例子中,只删除顾客 1000000006。 如果省略 WHERE 子句,它将删除表中每个顾客。 

    DELETE 语句从表中删除行,甚至是删除表中所有行。但是,DELETE 不删除表本身。 

    如果想从表中删除所有行,不要使用 DELETE。可使用 TRUNCATE TABLE 语句,它完成相同的工作,而速度更快(因为不记录数据的变动)。 

    【创建操纵表】

    创建

    CREATE TABLE Vendors (     vend_id          
    CHAR(10)     NOT NULL,     
    vend_name        CHAR(50)     NOT NULL,     
    vend_address     CHAR(50)     ,     
    vend_city        CHAR(50)     DEFAULT ‘China’,     
    vend_state       CHAR(5)      ,     
    vend_zip         CHAR(10)     ,     
    vend_country     CHAR(50) ); 

    这条语句创建本书中使用的 Vendors 表。供应商 ID 和供应商名字列是必 需的,因此指定为 NOT NULL。其余五列全都允许 NULL 值,所以不指定 NOT NULL。NULL 为默认设置,如果不指定 NOT NULL,就认为指定的是 NULL。

    主键是其值唯一标识表中每一行的列。只有不允许NULL 值的列可作为主键,允许 NULL 值的列不能作为唯一标识。 

    不要把 NULL 值与空字符串相混淆。NULL 值是没有值,不是空字符串。

    默认值经常用于日期或时间戳列。例如,通过指定引用系统日期的函数 或变量,将系统日期用作默认日期。

    ALTER TABLE Vendors ADD vend_phone CHAR(20); 

    这条语句给 Vendors 表增加一个名为 vend_phone 的列,其数据类型 为 CHAR。 

    ALTER TABLE Vendors DROP COLUMN vend_phone; 

    更改或删除列、增加约束或增加键,这些操作也使用类似的语法

    DROP TABLE CustCopy; 

    这条语句删除 CustCopy 表,删除表没有确认,也 不能撤销,执行这条语句将永久删除该表。 

    【使用视图】

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

    创建视图

    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;

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

    SELECT cust_name, cust_contact FROM ProductCustomers WHERE prod_id = 'RGAN01'; 

    检索订购了产品 RGAN01 的顾客。

    这条语句通过 WHERE 子句从视图中检索特定数据。当 DBMS处理此查询 时,它将指定的 WHERE 子句添加到视图查询中已有的 WHERE 子句中,以 便正确过滤数据。 

    CREATE VIEW VendorLocations AS SELECT RTRIM(vend_name) + ' (' + RTRIM(vend_country) + ')'        AS vend_title FROM Vendors; 

    格式化查询

    SELECT * FROM VendorLocations; 

    视图为虚拟的表。它们包含的不是数据而是根据需要检索数据的查询。 视图提供了一种封装 SELECT 语句的层次,可用来简化数据处理,重新 格式化或保护基础数据。 

    【存储过程】

    存储过程就是一个操作的组合单元化。

    【事务管理】

    事务(transaction)指一组 SQL语句; 

    回退(rollback)指撤销指定 SQL语句的过程; 

    提交(commit)指将未存储的 SQL语句结果写入数据库表; 
    保留点(savepoint)指事务处理中设置的临时占位符(placeholder), 可以对它发布回退(与回退整个事务处理不同)。 

    事务处理用来管理 INSERT、UPDATE 和 DELETE 语句。不能回退 SELECT 语句(回退 SELECT 语句也没有必要),也不能回退 CREATE 或 DROP 操 作。事务处理中可以使用这些语句,但进行回退时,这些操作也不撤销。

    提示:保留点越多越好 可以在 SQL代码中设置任意多的保留点,越多越好。为什么呢?因为 保留点越多,你就越能灵活地进行回退。 

    事务是必须完整执行的 SQL语句块。我们学习了如何使用 COMMIT 和 ROLLBACK 语句对何时写数据、何时撤销进行明确的管理;还 学习了如何使用保留点,更好地控制回退操作。

    【约束,索引,触发器等】

    此处不做介绍,会额外写。

    一个没有高级趣味的人。 email:hushui502@gmail.com
  • 相关阅读:
    Ajax
    Guitar and Music Theory
    leetcode62 不同路径(Medium)
    leetcode49 字母异位词分组(Medium)
    leetcode3 无重复的最长子串(Medium)
    leetcode69 x的平方根(Easy)
    leetcode300 最长上升子序列(Medium)
    leetcode240 搜索二维矩阵II (Medium)
    leetcode34 在排序数组中查找元素的第一个和最后一个位置(Medium)
    leetcode31 下一个排列(Medium)
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12105926.html
Copyright © 2020-2023  润新知