<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      mysql必會必知

      目錄

      了解SQL

      什么是數(shù)據(jù)庫

      數(shù)據(jù)庫是一個以某種有組織的方式存儲的數(shù)據(jù)集合。理解數(shù)據(jù)庫的一種最簡單的辦法是將其想象為一個文件柜。此文件柜是一個存放數(shù)據(jù)的物理位置,不管數(shù)據(jù)是什么以及如何組織的。

      數(shù)據(jù)庫(database): 保存有組織的數(shù)據(jù)的容器(通常是一個文件或一組文件)。

      注意:人們通常用數(shù)據(jù)庫這個術語來代表他們使用的數(shù)據(jù)庫軟件。這是不正確的,它是引起混淆的根源。確切地說,數(shù)據(jù)庫軟件應稱為DBMS(數(shù)據(jù)庫管理系統(tǒng))。數(shù)據(jù)庫是通過DBMS創(chuàng)建和操縱的容器。數(shù)據(jù)庫可以是保存在硬設備上的文件,但也可以不是。在很大程度上說,數(shù)據(jù)庫究竟是文件還是別的什么東西并不重要,因為你并不直接訪問數(shù)據(jù)庫;你使用的是DBMS,它替你訪問數(shù)據(jù)庫。

      表是一種結構化的文件,可用來存儲某種特定類型的數(shù)據(jù)。

      表(table): 某種特定類型數(shù)據(jù)的結構化清單。

      數(shù)據(jù)庫中的每個表都有一個名字,用來標識自己。此名字是唯一的,這表示數(shù)據(jù)庫中沒有其他表具有相同的名字。

      表名的唯一性取決于多個因素,如數(shù)據(jù)庫名和表名等的結合。這表示,雖然在相同數(shù)據(jù)庫中不能兩次使用相同的表名,但在不同的數(shù)據(jù)庫中卻可以使用相同的表名。

      表具有一些特性,這些特性定義了數(shù)據(jù)在表中如何存儲,如可以存儲什么樣的數(shù)據(jù),數(shù)據(jù)如何分解,各部分信息如何命名,等等。描述表的這組信息就是所謂的模式,模式可以用來描述數(shù)據(jù)庫中特定的表以及整個數(shù)據(jù)庫(和其中表的關系)

      模式(schema) :關于數(shù)據(jù)庫和表的布局及特性的信息。

      列和數(shù)據(jù)類型

      表由列組成。列中存儲著表中某部分的信息。

      列(column): 表中的一個字段。所有表都是由一個或多個列組成的。

      數(shù)據(jù)庫中每個列都有相應的數(shù)據(jù)類型。數(shù)據(jù)類型定義列可以存儲的數(shù)據(jù)種類。例如,如果列中存儲的為數(shù)字(或許是訂單中的物品數(shù)),則相應的數(shù)據(jù)類型應該為數(shù)值類型。如果列中存儲的是日期、文本、注釋、金額等,則應該用恰當?shù)臄?shù)據(jù)類型規(guī)定出來。

      數(shù)據(jù)類型(datatype): 所容許的數(shù)據(jù)的類型。每個表列都有相應的數(shù)據(jù)類型,它限制(或容許)該列中存儲的數(shù)據(jù)。

      數(shù)據(jù)類型限制可存儲在列中的數(shù)據(jù)種類(例如,防止在數(shù)值字段中錄入字符值)。數(shù)據(jù)類型還幫助正確地排序數(shù)據(jù),并在優(yōu)化磁盤使用方面起重要的作用。因此,在創(chuàng)建表時必須對數(shù)據(jù)類型給予特別的關注。

      行(row): 表中的一個記錄。

      你可能聽到用戶在提到行( row)時稱其為數(shù)據(jù)庫記錄( record)。在很大程度上,這兩個術語是可以互相替代的,但從技術上說,行才是正確的術語。

      主鍵

      表中每一行都應該有可以唯一標識自己的一列(或一組列)。

      主鍵(primary key): 一列(或一組列),其值能夠唯一區(qū)分表中每個行。

      唯一標識表中每行的這個列(或這組列)稱為主鍵。主鍵用來表示一個特定的行。沒有主鍵,更新或刪除表中特定行很困難,因為沒有安全的方法保證只涉及相關的行。

      表中的任何列都可以作為主鍵,只要它滿足以下條件:

      • 任意兩行都不具有相同的主鍵值;
      • 每個行都必須具有一個主鍵值(主鍵列不允許NULL值)。

      主鍵通常定義在表的一列上,但這并不是必需的,也可以一起使用多個列作為主鍵。在使用多列作為主鍵時,上述條件必須應用到構成主鍵的所有列,所有列值的組合必須是唯一的(但單個列的值可以不唯一)。

      什么是SQL

      SQL是結構化查詢語言(Structured Query Language)的縮寫。 SQL是一種專門用來與數(shù)據(jù)庫通信的語言

      SQL有如下的優(yōu)點 :

      • SQL不是某個特定數(shù)據(jù)庫供應商專有的語言。幾乎所有重要的DBMS都支持SQL,所以,學習此語言使你幾乎能與所有數(shù)據(jù)庫打交道。
      • SQL簡單易學。它的語句全都是由描述性很強的英語單詞組成,而且這些單詞的數(shù)目不多。
      • SQL盡管看上去很簡單,但它實際上是一種強有力的語言,靈活使用其語言元素,可以進行非常復雜和高級的數(shù)據(jù)庫操作。

      DBMS專用的SQL:SQL不是一種專利語言,而且存在一個標準委員會,他們試圖定義可供所有DBMS使用的SQL語法,但事實上任意兩個DBMS實現(xiàn)的SQL都不完全相同

      本書講授的SQL是專門針對MySQL的,雖然書中所講授的多數(shù)語法也適用于其他DBMS,但不要認為這些SQL語法是完全可移植的。

      MySQL簡介

      什么是MySQL

      正如所述,數(shù)據(jù)的所有存儲、檢索、管理和處理實際上是由數(shù)據(jù)庫軟件——DBMS( 數(shù)據(jù)庫管理系統(tǒng))完成的。 MySQL是一種DBMS,即它是一種數(shù)據(jù)庫軟件。

      客戶機—服務器軟件

      DBMS可分為兩類:一類為基于共享文件系統(tǒng)的DBMS,另一類為基于客戶機—服務器的DBMS

      前者(包括諸如Microsoft Access和FileMaker) 用于桌面用途,通常不用于高端或更關鍵的應用。

      MySQL、 Oracle以及Microsoft SQL Server等數(shù)據(jù)庫是基于客戶機—服務器的數(shù)據(jù)庫。客戶機—服務器應用分為兩個不同的部分。 服務器部分是負責所有數(shù)據(jù)訪問和處理的一個軟件。這個軟件運行在稱為數(shù)據(jù)庫服務器的計算機上。

      與數(shù)據(jù)文件打交道的只有服務器軟件。關于數(shù)據(jù)、數(shù)據(jù)添加、刪除和數(shù)據(jù)更新的所有請求都由服務器軟件完成。這些請求或更改來自運行客戶機軟件的計算機

      客戶機是與用戶打交道的軟件。例如,如果你請求一個按字母順序列出的產(chǎn)品表,則客戶機軟件通過網(wǎng)絡提交該請求給服務器軟件。服務器軟件處理這個請求,根據(jù)需要過濾、丟棄和排序數(shù)據(jù);然后把結果送回到你的客戶機軟件。

      因為為了使用MySQL,你需要訪問運行MySQL服務器軟件的計算機和發(fā)布命令到MySQL的客戶機軟件的計算機。

      • 服務器軟件為MySQL DBMS。
      • 客戶機可以是MySQL提供的工具、腳本語言(如Perl)、 Web應用開發(fā)語言(如ASP、 ColdFusion、 JSP和PHP)、程序設計語言(如C、 C++、 Java)等。

      MySQL工具

      MySQL是一個客戶機—服務器DBMS,因此,為了使用MySQL,需要有一個客戶機,即你需要用來與MySQL打交道(給MySQL提供要執(zhí)行的命令)的一個應用。

      mysql命令行實用程序

      每個MySQL安裝都有一個名為mysql的簡單命令行實用程序。

      熟悉mysql命令行實用程序:即使你選擇使用后面描述的某個圖形工具,也應該保證熟悉mysql命令行實用程序,因為它是你可以安全地依靠的一個總是會被給出的客戶機(因為它是核心MySQL安裝的一部分)。

      MySQL Administrator

      MySQL Administrator( MySQL管理器)是一個圖形交互客戶機,用來簡化MySQL服務器的管理。

      MySQL Query Browser

      MySQL Query Browser為一個圖形交互客戶機,用來編寫和執(zhí)行MySQL命令。

      檢索數(shù)據(jù)

      SELECT語句

      select 關鍵字  列名  from 表名
      

      檢索單個列

      // 檢索products 表中  prod_name 列的數(shù)據(jù)
      select prod_name from products 
      

      檢索多個列

      // 檢索products 表中 prod_name prod_id prod_price 列的數(shù)據(jù)
      SELECT prod_name,prod_id,prod_price FROM products
      

      檢索所有列

      // 檢索products 所有列的數(shù)據(jù)
      select * from products
      

      檢索不同的行

      檢索結果中,列有重復值,使用DISTINCT關鍵字,此關鍵字指示MySQL只返回不同的值

      SELECT DISTINCT vend_id  FROM products
      

      注意:不能部分使用DISTINCT

      DISTINCT關鍵字應用于所有列而不僅是前置它的列。如果給出SELECT DISTINCT vend_id,prod_price,除非指定的兩個列都不同,否則所有行都將被檢索出來。

      限制結果

      SELECT語句返回所有匹配的行,它們可能是指定表中的每個行。為了返回第一行或前幾行,可使用LIMIT子句。

      SELECT prod_name from products LIMIT 5
      

      帶一個值的LIMIT:從第一行開始,給出的數(shù)為返回的行數(shù)。

      帶兩個值的LIMIT:第一個數(shù)為開始位置,第二個數(shù)為要檢索的行數(shù)。

      使用完全限定的表名

      在SQL不僅可以通過列名引用列。 也可能會使用完全限定的名字來引用列(同時使用表名和列字)。

      SELECT products.prod_name from products
      

      因為不同表,可能有同名列

      排序檢索數(shù)據(jù)

      子句(clause) :SQL語句由子句構成,有些子句是必需的,而有的是可選的。一個子句通常由一個關鍵字和所提供的數(shù)據(jù)組
      成。子句的例子有SELECT語句的FROM子句,為了明確地排序用SELECT語句檢索出的數(shù)據(jù),可使用ORDER BY子句。

      ORDER BY子句取一個或多個列的名字,據(jù)此對輸出進行排序。

      SELECT prod_name from products ORDER BY prod_name
      

      通過非選擇列進行排序:通常, ORDER BY子句中使用的列將是為顯示所選擇的列。但是,實際上并不一定要這樣,用非檢索的列排序數(shù)據(jù)是完全合法的。

      按多個列排序

      // 檢索結果 首先按,然后再按價格排序
      SELECT prod_name , prod_id, prod_price from products ORDER BY prod_name,prod_price
      

      指定排序方向

      數(shù)據(jù)排序不限于升序排序(從A到Z)。這只是默認的排序順序,還可以使用ORDER BY子句以降序(從Z到A)順序排序。為了進行降序排序必須指定DESC關鍵字

      SELECT prod_name , prod_id, prod_price from products ORDER BY prod_id DESC
      

      DESC關鍵字只應用到直接位于其前面的列名

      SELECT prod_name , prod_id, prod_price from products ORDER BY prod_id DESC ,prod_name
      

      在上例中,只對prod_id列指定DESC,對prod_name列不指定。因此,prod_id列以降序排序,而prod_name列(在每個ID內)仍然按標準的升序排序。

      在多個列上降序排序 如果想在多個列上進行降序排序, 必須對每個列指定DESC關鍵字。

      DESC相反的關鍵字是ASC(ASCENDING), 在升序排序時可以指定它。但實際上, ASC沒有多大用處,因為升序是默認的(如果既不指定ASC也不指定DESC,則假定為ASC)。

      ORDER BY子句的位置:在給出ORDER BY子句時,應該保證它位于FROM子句之后如果使用LIMIT,它必須位于ORDER BY
      之后使用子句的次序不對將產(chǎn)生錯誤消息

      過濾數(shù)據(jù)

      使用WHERE子句

      數(shù)據(jù)庫表一般包含大量的數(shù)據(jù),很少需要檢索表中所有行。

      只檢索所需數(shù)據(jù)需要指定搜索條件( search criteria) ,搜索條件也稱為過濾條件( filtercondition)

      在SELECT語句中,數(shù)據(jù)根據(jù)WHERE子句中指定的搜索條件進行過濾。WHERE子句在表名(FROM子句)之后給出

      SELECT prod_name ,prod_price from products  WHERE prod_price = 5.99
      

      WHERE子句的位置 : 在同時使用ORDER BY和WHERE子句時,應該讓ORDER BY位于WHERE之后, 否則將會產(chǎn)生錯誤。

      WHERE子句操作符

      MySQL支持一下列出的所有條件操作符。

      操作符 說明
      = 等于(默認不區(qū)分大小寫)
      <> 不等于
      != 不等于
      < 小于
      <= 小于等于
      > 大于
      >= 大于等于
      BETWEEN 在指定的兩個值之間

      何時使用引號:在WHERE子句中使用的條件,會看到有的值括在單引號內(如'fuses'),而有的值未括起來單引號用來限定字符串如果將值與串類型的列進行比較,則需要限定引號用來與數(shù)值列進行比較的值不用引號

      范圍值檢查

      SELECT prod_name ,prod_price from products  WHERE prod_price  BETWEEN 5 AND 10
      

      在使用BETWEEN時,必須指定兩個值—所需范圍的低端值和高端值。這兩個值必須用AND關鍵字分隔。 BETWEEN匹配范圍中所有的值,包括指定的開始值和結束值。

      空值檢查

      在創(chuàng)建表時,表設計人員可以指定其中的列是否可以不包含值。在一個列不包含值時,稱其為包含空值NULL

      NULL 無值(no value),它與字段包含0空字符串或僅僅包含空格不同。

      SELECT語句有一個特殊的WHERE子句,可用來檢查具有NULL值的列。這個WHERE子句就是IS NULL子句

      SELECT prod_name ,prod_price from products  WHERE prod_price  IS NULL
      

      NULL與不匹配 : 在通過過濾選擇出不具有特定值的行時,你可能希望返回具有NULL值的行。但是,不行。因為null具有
      特殊的含義,數(shù)據(jù)庫不知道它們是否匹配,所以在匹配過濾或不匹配過濾時不返回它們(具有Null的行)

      因此,在過濾數(shù)據(jù)時,一定要驗證返回數(shù)據(jù)中確實給出了被過濾列具有NULL的行。

      數(shù)據(jù)過濾

      組合WHERE子句

      在過濾數(shù)據(jù)中介紹的所有WHERE子句在過濾數(shù)據(jù)時使用的都是單一的條件。為了進行更強的過濾控制, MySQL允許給出多個WHERE子句。這些子句可以兩種方式使用:以AND子句的方式OR子句的方式使用

      操作符(operator):用來聯(lián)結或改變WHERE子句中的子句的關鍵字。也稱為邏輯操作符( logical operator)

      AND操作符

      為了通過不止一個列進行過濾,可使用AND操作符給WHERE子句附加條件。

      SELECT prod_id,prod_price,prod_name FROM products	WHERE vend_id = 1003  and prod_id <= 10
      

      還可以添加多個過濾條件,每添加一條就要使用一個AND。

      OR操作符

      OR操作符與AND操作符不同,它指示MySQL檢索匹配任一條件的行。

      SELECT prod_id,prod_price,prod_name FROM products	WHERE vend_id = 1003  or prod_id <= 10
      

      OR :WHERE子句中使用的關鍵字,用來表示檢索匹配任一給定條件的行

      計算次序

      WHERE可包含任意數(shù)目的AND和OR操作符。允許兩者結合以進行復雜和高級的過濾。

      SELECT prod_price,prod_name,vend_id FROM products	WHERE vend_id = 1002  OR vend_id = 1003 AND prod_price >= 10
      
      

      SQL(像多數(shù)語言一樣)在處理OR操作符前,優(yōu)先處理AND操作符

      當SQL看到上述WHERE子句時,它理解為由供應商1003制造的任何價格為10美元(含)以上的產(chǎn)品,或者由供應商1002制造的任何產(chǎn)品,而不管其價格如何。換句話說,由于AND在計算次序中優(yōu)先級更高,操作符被錯誤地組合了。

      解決優(yōu)先級的方法是使用圓括號明確地分組相應的操作符

      SELECT prod_price,prod_name,vend_id FROM products	WHERE (vend_id = 1002  OR vend_id = 1003) AND prod_price >= 10
      
      

      圓括號具有較AND或OR操作符高的計算次序, DBMS首先過濾圓括號內的OR條件。

      這時, SQL語句變成了選擇由供應商1002或1003制造的且價格都在10美元(含)以上的任何產(chǎn)品,這正是我們所希望的。

      在WHERE子句中使用圓括號:任何時候使用具有AND和OR操作符的WHERE子句,都應該使用圓括號明確地分組操作符

      不要過分依賴默認計算次序,即使它確實是你想要的東西也是如此。使用圓括號沒有什么壞處,它能消除歧義。

      IN操作符

      圓括號在WHERE子句中還有另外一種用法。 IN操作符用來指定條件范圍,范圍中的每個條件都可以進行匹配。 IN取合法值的由逗號分隔的清單,全都括在圓括號中。

      SELECT prod_price,prod_name,vend_id FROM products	WHERE vend_id IN (1002,1003) ORDER BY prod_name
      

      此SELECT語句檢索供應商1002和1003制造的所有產(chǎn)品。 IN操作符后跟由逗號分隔的合法值清單,整個清單必須括在圓括號中。

      注意:IN匹配的是括號中的具體指而不是范圍IN操作符完成與OR相同的功能

      為什么要使用IN操作符?其優(yōu)點具體如下:

      • 在使用長的合法選項清單時, IN操作符的語法更清楚且更直觀。
      • 在使用IN時,計算的次序更容易管理(因為使用的操作符更少)。
      • IN操作符一般比OR操作符清單執(zhí)行更快。
      • IN的最大優(yōu)點是可以包含其他SELECT語句使得能夠更動態(tài)地建立WHERE子句。詳見:使用子查詢

      NOT操作符

      WHERE子句中的NOT操作符有且只有一個功能,那就是否定它之后所跟的任何條件

      SELECT prod_price,prod_name,vend_id FROM products	WHERE vend_id NOT IN (1002,1003) ORDER BY prod_name
      

      對于簡單的WHERE子句,使用NOT確實沒有什么優(yōu)勢

      但在更復雜的子句中, NOT是非常有用的。例如,在與IN操作符聯(lián)合使用時, NOT使找出與條件列表不匹配的行非常簡單

      MySQL中的NOT:MySQL支持使用NOT 對 IN 、 BETWEEN 和EXISTS子句取反這與多數(shù)其他DBMS允許使用NOT對各種條件取反有很大的差別。

      用通配符進行過濾

      LIKE操作符

      前面介紹的所有操作符都是針對已知值進行過濾的。不管是匹配一個還是多個值,測試大于還是小于已知值,或者檢查某個范圍的值,共同點是過濾中使用的值都是已知的。但是,這種過濾方法并不是任何時候都好用。

      通配符(wildcard) :用來匹配值的一部分的特殊字符

      利用通配符可創(chuàng)建比較特定數(shù)據(jù)的搜索模式

      搜索模式(search pattern): 由字面值通配符兩者組合構成的搜索條件

      通配符本身實際是SQL的WHERE子句中有特殊含義的字符, SQL支持幾種通配符。

      為在搜索子句中使用通配符必須使用LIKE操作符

      LIKE指示MySQL,后跟的搜索模式利用通配符匹配而不是直接相等匹配進行比較

      百分號( %)通配符

      最常使用的通配符是百分號(%)。在搜索串中, %表示任何字符出現(xiàn)任意次數(shù)

      例如,為了找出所有以詞jet起頭的產(chǎn)品,可使用以下SELECT語句:

      SELECT prod_price,prod_name,vend_id FROM products	WHERE prod_name LIKE "jet%";
      

      此例子使用了搜索模式'jet%'。在執(zhí)行這條子句時,將檢索任意以jet起頭的詞。 %告訴MySQL接受jet之后的任意字符,不管它有多少字符。

      區(qū)分大小寫根據(jù)MySQL的配置方式,搜索可以是區(qū)分大小寫的。如果區(qū)分大小寫, 'jet%'與JetPack 1000將不匹配。

      通配符可在搜索模式中任意位置使用,并且可以使用多個通配符

      下面的例子使用兩個通配符,它們位于模式的兩端:

      SELECT prod_price,prod_name,vend_id FROM products	WHERE prod_name LIKE "%anvil%";
      

      搜索模式'%anvil%'表示匹配任何位置包含文本anvil的值,而不論它之前或之后出現(xiàn)什么字符。

      重要的是要注意到,除了一個或多個字符外, %還能匹配0個字符。 %代表搜索模式中給定位置的0個、 1個或多個字符

      注意尾空格尾空格可能會干擾通配符匹配

      例如,在保存詞anvil 時 , 如果它后面有一個或多個空格 ,則子句WHERE prod_name LIKE '%anvil'將不會匹配它們,因為在最后的l后有多余的字符。解決這個問題的一個簡單的辦法是在搜索模式最后附加一個%。一個更好的辦法是使用函數(shù)(參見:使用數(shù)據(jù)處理函數(shù))去掉首尾空格。

      注意NULL雖然似乎%通配符可以匹配任何東西,但有一個例外,即NULL即使是WHERE prod_name LIKE '%'也不能匹配用值NULL作為產(chǎn)品名的行。

      下劃線( _)通配符

      另一個有用的通配符是下劃線(_)。下劃線的用途與%一樣,但下劃線只匹配單個字符而不是多個字符

      使用通配符的技巧

      正如所見, MySQL的通配符很有用。

      但這種功能是有代價的:通配符搜索的處理一般要比前面討論的其他搜索所花時間更長。這里給出一些使用通配符要記住的技巧。

      • 不要過度使用通配符。如果其他操作符能達到相同的目的,應該使用其他操作符。
      • 在確實需要使用通配符時,除非絕對有必要,否則不要把它們用在搜索模式的開始處把通配符置于搜索模式的開始處,搜索起來是最慢的。
      • 仔細注意通配符的位置。如果放錯地方,可能不會返回想要的數(shù)據(jù)。

      用正則表達式進行搜索

      正則表達式是用來匹配文本的特殊的串(字符集合)。

      使用MySQL正則表達式

      MySQL用WHERE子句對正則表達式提供了初步的支持,允許你指定正則表達式過濾SELECT檢索出的數(shù)據(jù)

      僅為正則表達式語言的一個子集:如果你熟悉正則表達式, 需要注意: MySQL僅支持多數(shù)正則表達式實現(xiàn)的一個很小的子集

      基本字符匹配

        SELECT prod_name from products WHERE prod_name REGEXP "1000" ORDER BY prod_name
      

      除關鍵字LIKE被REGEXP替代外,這條語句看上去非常像使用LIKE的語句;

      它告訴MySQL: REGEXP后所跟的東西作為正則表達式(與文字正文1000匹配的一個正則表達式)處理。

        SELECT prod_name from products WHERE prod_name REGEXP ".000" ORDER BY prod_name
      

      這里使用了正則表達式.000.是正則表達式語言中一個特殊的字符。它表示匹配任意一個字符,因此, 1000和2000都匹配且返回。

      當然,這個特殊的例子也可以用LIKE和通配符來完成 ;

      LIKE與REGEXP 在LIKE和REGEXP之間有一個重要的差別。

      請看以下兩條語句:

        SELECT prod_name from products WHERE prod_name LINK "1000" ORDER BY prod_name
      
        SELECT prod_name from products WHERE prod_name REGEXP "1000" ORDER BY prod_name
      

      如果執(zhí)行上述兩條語句,會發(fā)現(xiàn)第一條語句不返回數(shù)據(jù),而第二條語句返回一行。為什么?

      LIKE匹配整個列值如果被匹配的文本在列值中出現(xiàn)(僅僅是包含文本,不是列值等于文本), LIKE將不會找到它,相應的行也不被返回(除非使用通配符)

      而REGEXP在列值內進行匹配,如果被匹配的文本在列值中出現(xiàn), REGEXP將會找到它,相應的行將被返回。這是一個非常重要的差別。

      匹配不區(qū)分大小寫: MySQL中的正則表達式匹配(自版本3.23.4后)不區(qū)分大小寫(即,大寫和小寫都匹配)。為區(qū)分大小寫,可使用BINARY關鍵字,如WHERE prod_name REGEXP BINARY 'JetPack .000'。

      進行OR匹配

      為搜索兩個串之一(或者為這個串,或者為另一個串),使用|

        SELECT prod_name from products WHERE prod_name REGEXP "1000|2000" ORDER BY prod_name
      

      語句中使用了正則表達式1000|2000。 |為正則表達式的OR操作符。它表示匹配其中之一,因此1000和2000都匹配并返回。

      使用|從功能上類似于在SELECT語句中使用OR語句, 多個OR條件可并入單個正則表達式。

      兩個以上的OR條件:可以給出兩個以上的OR條件。例如,'1000 | 2000 | 3000'將匹配1000或2000或3000。

      匹配幾個字符之一

      如果你只想匹配特定的字符 ,可通過指定一組用[和]括起來的字符來完成 ;

        SELECT prod_name from products WHERE prod_name REGEXP "[123] Ton" ORDER BY prod_name
      

      這里,使用了正則表達式[123] Ton。 [123]定義一組字符,它的意思是匹配1或2或3,因此, 1 ton和2 ton都匹配且返回(沒有3 ton)。

      正如所見, [ ]是另一種形式的OR語句。 事實上,正則表達式[123]Ton為[1|2|3]Ton的縮寫,也可以使用后者。但是,需要用[]來定義OR語句查找什么。為更好地理解這一點,請看下面的例子:

        SELECT prod_name from products WHERE prod_name REGEXP "1|2|3 Ton" ORDER BY prod_name
      

      輸出:

      prod_name
      1 ton anvil
      2 ton anvil
      JetPack 1000
      JetPack 2000
      TNT (1 stick)

      這并不是期望的輸出。兩個要求的行被檢索出來,但還檢索出了另外3行。之所以這樣是由于MySQL假定你的意思是'1'或'2'或'3 ton'。除非把字符 | 括在(使用 [ ])一個集合中,否則它將應用于整個串

      上例中由于沒有使用 [ ],mysql檢索的是prod_name列中,含有1,或者2,或者3的行;

      字符集合也可以被否定,即,它們將匹配除指定字符外的任何東西。為否定一個字符集,在集合的開始處放置一個^即可。因此,盡管[123]匹配字符1、 2或3,但[^123]卻匹配除這些字符外的任何東西。

      匹配范圍

      集合可用來定義要匹配的一個或多個字符。例如,下面的集合將匹配數(shù)字0到9:

      [0123456789]

      為簡化這種類型的集合,可使用-來定義一個范圍。下面的式子功能上等同于上述數(shù)字列表:

      [0-9]

      范圍不限于完整的集合, [1-3]和[6-9]也是合法的范圍。此外,范圍不一定只是數(shù)值的, [a-z]匹配任意字母字符。

        SELECT prod_name from products WHERE prod_name REGEXP "[1-5] Ton" ORDER BY prod_name
      

      這里使用正則表達式[1-5] Ton。 [1-5]定義了一個范圍,這個表達式意思是匹配1到5。

      匹配特殊字符

      正則表達式語言由具有特定含義的特殊字符構成。我們已經(jīng)看到.、 []、|和-等,還有其他一些字符。

      為了匹配特殊字符必須用\為前導。 \\-表示查找-, \\.表示查找.

      這種處理就是所謂的轉義( escaping),正則表達式內具有特殊意義的所有字符都必須以這種方式轉義。這包括.、 |、 []以及迄今為止使用過的其他特殊字符。

      \\也用來引用元字符(具有特殊含義的字符),如下表。

      元字符 說明
      \\f 換頁
      \\n 換行
      \\r 回車
      \\t 制表
      \\v 縱向制表

      匹配\: 為了匹配反斜杠( \)字符本身,需要使用\\。

      匹配字符類

      為更方便工作,可以使用預定義的字符集,稱為字符類( character class)。

      說明
      [:alnum:] 任意字母和數(shù)字(同[a-zA-Z0-9])
      [:alpha:] 任意字符(同[a-zA-Z])
      [:blank:] 空格和制表(同[\t])
      [:cntrl:] ASCII控制字符( ASCII 0到31和127)
      [:digit:] 任意數(shù)字(同[0-9])
      [:graph:] 與[:print:]相同,但不包括空格
      [:lower:] 任意小寫字母(同[a-z])
      [:print:] 任意可打印字符
      [:punct:] 既不在[:alnum:]又不在[:cntrl:]中的任意字符
      [:space:] 包括空格在內的任意空白字符(同[\f\n\r\t\v])
      [:upper:] 任意大寫字母(同[A-Z])
      [:xdigit:] 任意十六進制數(shù)字(同[a-fA-F0-9])

      匹配多個實例

      目前為止使用的所有正則表達式都試圖匹配單次出現(xiàn)。如果存在一個匹配,該行被檢索出來,如果不存在,檢索不出任何行。但有時需要對匹配的數(shù)目進行更強的控制

      例如,你可能需要尋找所有的數(shù),不管數(shù)中包含多少數(shù)字,或者你可能想尋找一個單詞并且還能夠適應一個尾隨的s(如果存在),等等。

      正則表達式重復元字符表如下:

      元字符 說明
      * 0個或多個匹配
      + 1個或多個匹配(等于{1,})
      ? 0個或1個匹配(等于{0,1})
      指定數(shù)目的匹配
      不少于指定數(shù)目的匹配
      匹配數(shù)目的范圍( m不超過255)

      定位符

      目前為止的所有例子都是匹配一個串中任意位置的文本。為了匹配特定位置的文本,需要使用一下列出的定位符。

      元符號 說明
      ^ 文本的開始
      $ 文本的結尾
      [[:<:]] 詞的開始
      [[:>:]] 詞的結尾

      的雙重用途:有兩種用法。在集合中(用[和]定義),用它來否定該集合,否則,用來指串的開始處。

      使REGEXP起類似LIKE的作用

      前面說過, LIKE和REGEXP的不同在于LIKE匹配整個串而REGEXP匹配子串利用定位符,通過用^開始每個表達式,用$結束每個表達式,可以使REGEXP的作用與LIKE一樣

      創(chuàng)建計算字段

      計算字段

      存儲在數(shù)據(jù)庫表中的數(shù)據(jù)一般不是應用程序所需要的格式。

      比如:

      • 物品訂單表存儲物品的價格和數(shù)量,但不需要存儲每個物品的總價格(用價格乘以數(shù)量即可)。為打印發(fā)票,需要物品的總價格。

      • 需要根據(jù)表數(shù)據(jù)進行總數(shù)、平均數(shù)計算或其他計算。

      在上述每個例子中,存儲在表中的數(shù)據(jù)都不是應用程序所需要的我們需要直接從數(shù)據(jù)庫中檢索出轉換、計算或格式化過的數(shù)據(jù);而不是檢索出數(shù)據(jù),然后再在客戶機應用程序或報告程序中重新格式化。

      這就是計算字段發(fā)揮作用的所在了。

      與前面各章介紹過的列不同,計算字段并不實際存在于數(shù)據(jù)庫表中。計算字段是運行時在SELECT語句內創(chuàng)建的

      字段(field) :基本上與列( column) 的意思相同,經(jīng)常互換使用,不過數(shù)據(jù)庫列一般稱為列,而術語字段通常用在計算字段的連接上

      重要的是要注意到,只有數(shù)據(jù)庫知道SELECT語句中哪些列是實際的表列,哪些列是計算字段。從客戶機(如應用程序)的角度來看,計算字段的數(shù)據(jù)是以與其他列的數(shù)據(jù)相同的方式返回的

      拼接字段

      拼接(concatenate): 將值聯(lián)結到一起構成單個值。

      在MySQL的SELECT語句中,可使用Concat()函數(shù)來拼接兩個列。

      如下需求:

      vendors表包含供應商名和位置信息。假如要生成一個供應商報表,需要在供應商的名字中按照name(location)這樣的格式列出供應商的位置.

      SELECT  CONCAT(vend_name, '(' ,vend_country, ')' ) FROM vendors ORDER BY vend_name
      

      Concat()拼接串,即把多個串連接起來形成一個較長的串。Concat()需要一個或多個指定的串,各個串之間用逗號分隔。

      使用別名

      以上的例子中,新計算列默認沒有列名;

      為了解決這個問題, SQL支持列別名。 別名( alias) 是一個字段或值的替換名。別名用AS關鍵字賦予

      SELECT  CONCAT(vend_name, '(' ,vend_country, ')' ) as vend_titel FROM vendors ORDER BY vend_name
      

      AS vend_title。它指示SQL創(chuàng)建一個包含指定計算的名為vend_title的計算字段。從輸出中可以看到,結果與以前的相同,但現(xiàn)在列名為vend_title,任何客戶機應用都可以按名引用這個列,就像它是一個實際的表列一樣。

      別名的其他用途 : 別名還有其他用途。常見的用途包括在實際的表列名包含不符合規(guī)定的字符(如空格)時重新命名它,在原來的名字含混或容易誤解時擴充它,等等。

      導出列 :別名有時也稱為導出列( derived column),不管稱為什么,它們所代表的都是相同的東西。

      執(zhí)行算術計算

      計算字段的另一常見用途是對檢索出的數(shù)據(jù)進行算術計算

      如下需求:

      訂單號20005中的所有物品,每種商品的總價(商品數(shù)x訂購單價)

      SELECT  prod_id,quantity,item_price, quantity*item_price AS expanded_price FROM orderitems WHERE order_num = 20005
      

      MySQL支持以下列出的基本算術操作符。此外,圓括號可用來區(qū)分優(yōu)先順序

      操作符 說明
      +
      -
      *
      /

      如何測試計算 :雖然SELECT通常用來從表中檢索數(shù)據(jù),但可以省略FROM子句以便簡單地訪問和處理表達式。例如, SELECT 3*2;將返回6, SELECT Trim('abc');將返回abc,而SELECT Now()利用Now()函數(shù)返回當前日期和時間

      通過這些例子,可以明白如何根據(jù)需要使用SELECT進行試驗。

      使用數(shù)據(jù)處理函數(shù)

      函數(shù)

      與其他大多數(shù)計算機語言一樣, SQL支持利用函數(shù)來處理數(shù)據(jù)。函數(shù)一般是在數(shù)據(jù)上執(zhí)行的,它給數(shù)據(jù)的轉換和處理提供了方便。

      使用函數(shù)

      大多數(shù)SQL實現(xiàn)支持以下類型的函數(shù)。

      • 用于處理文本串(如刪除或填充值,轉換值為大寫或小寫)的文本函數(shù)。
      • 用于在數(shù)值數(shù)據(jù)上進行算術操作(如返回絕對值,進行代數(shù)運算)的數(shù)值函數(shù)。
      • 用于處理日期和時間值并從這些值中提取特定成分(例如,返回兩個日期之差,檢查日期有效性等)的日期和時間函數(shù)。
      • 返回DBMS正使用的特殊信息(如返回用戶登錄信息,檢查版本細節(jié))的系統(tǒng)函數(shù)。

      文本處理函數(shù)

      常用的文本處理函數(shù)。

      函數(shù) 說明
      Left() 返回串左邊的字符
      Length() 返回串的長度
      Locate() 找出串的一個子串
      Lower() 將串轉換為小寫
      LTrim() 去掉串左邊的空格
      Right() 返回串右邊的字符
      RTrim() 去掉串右邊的空格
      Soundex() 返回串的SOUNDEX值
      SubString() 返回子串的字符
      Upper() 將串轉換為大寫

      日期和時間處理函數(shù)

      日期和時間采用相應的數(shù)據(jù)類型和特殊的格式存儲,以便能快速和有效地排序或過濾,并且節(jié)省物理存儲空間。

      常用的日期和時間處理函數(shù)。

      函數(shù) 說明
      AddDate 增加一個日期(天、周等)
      AddTime 增加一個時間(時、分等)
      CurDate 返回當前日期
      CurTime 返回當前時間
      Date 返回日期時間的日期部分
      DateDiff 計算兩個日期之差
      Date_Add 高度靈活的日期運算函數(shù)
      Date_Format 返回一個格式化的日期或時間串
      Day 返回一個日期的天數(shù)部分
      DayOfWeek 對于一個日期,返回對應的星期幾
      Hour 返回一個時間的小時部分
      Minute 返回一個時間的分鐘部分
      Month 返回一個日期的月份部分
      Now 返回當前日期和時間
      Second 返回一個時間的秒部分
      Time 返回一個日期時間的時間部分
      Year 返回一個日期的年份部分

      用日期進行過濾需要注意一些別的問題和使用特殊的MySQL函數(shù)。

      首先需要注意的是MySQL使用的日期格式。無論你什么時候指定一個日期,不管是插入或更新表值還是用WHERE子句進行過濾,日期必須為格式y(tǒng)yyy-mm-dd。因此, 2005年9月1日,給出為2005-09-01。雖然其他的日期格式可能也行,但這是首選的日期格式,因為它排除了多義性(如,04/05/06是2006年5月4日或2006年4月5日或2004年5月6日或……)。

      如下例子:

      檢索出一個訂單記錄,該訂單記錄的order_date為2005-09-01。

      SELECT cust_id , order_num FROM orders WHERE order_date = "2005-09-01"
      

      使用WHERE order_date = '2005-09-01'可靠嗎?

      order_date的數(shù)據(jù)類型為datetime。這種類型存儲日期及時間值

      樣例表中的值全都具有時間值00:00:00,但實際中很可能并不總是這樣。

      比如 , 存儲的 order_date 值為2005-09-01 11:30:05,則WHERE order_date = '2005-09-01'失敗。即使給出具有該日期的一行,也不會把它檢索出來,因為WHERE匹配失敗。

      解決辦法是指示MySQL僅將給出的日期與列中的日期部分進行比較,而不是將給出的日期與整個列值進行比較

      為此,必須使用Date()函數(shù)。 Date(order_date)指示MySQL僅提取列的日期部分,更可靠的SELECT語句為:

      SELECT cust_id , order_num FROM orders WHERE DATE (order_date) = "2005-09-01"
      

      如果要的是日期請使用Date() : 如果你想要的僅是日期,則使用Date()是一個良好的習慣,即使你知道相應的列只包含日期也是如此。這樣,如果由于某種原因表中以后有日期和時間值,你的SQL代碼也不用改變。當然,也存在一個Time()函數(shù)在你只想要時間時應該使用它。

      還有一種日期比較需要說明。如果你想檢索出2005年9月下的所有訂單,怎么辦?

      有幾種解決辦法,其中之一如下所示:

      SELECT cust_id , order_num FROM orders WHERE DATE (order_date) BETWEEN "2005-09-01" AND "2005-09-03"
      

      還有另外一種辦法(一種不需要記住每個月中有多少天或不需要操心閏年2月的辦法):

      SELECT cust_id , order_num FROM orders WHERE YEAR(order_date) = 2005 AND MONTH(order_date) = 9
      

      Year()是一個從日期(或日期時間)中返回年份的函數(shù)。類似,Month()從日期中返回月份。因此, WHERE Year(order_date)= 2005 AND Month(order_date) = 9檢索出order_date為2005年9月的所有行。

      數(shù)值處理函數(shù)

      數(shù)值處理函數(shù)僅處理數(shù)值數(shù)據(jù)。這些函數(shù)一般主要用于代數(shù)、三角或幾何運算,因此沒有串或日期—時間處理函數(shù)的使用那么頻繁。

      常用數(shù)值處理函數(shù)

      函數(shù) 說明
      Abs() 返回一個數(shù)的絕對值
      Cos() 返回一個角度的余弦
      Exp() 返回一個數(shù)的指數(shù)值
      Mod() 返回除操作的余數(shù)
      Pi() 返回圓周率
      Rand() 返回一個隨機數(shù)
      Sin() 返回一個角度的正弦
      Sqrt() 返回一個數(shù)的平方根
      Tan() 返回一個角度的正切

      匯總數(shù)據(jù)

      聚集函數(shù)

      我們經(jīng)常需要匯總數(shù)據(jù)而不用把它們實際檢索出來,為此MySQL提供了專門的函數(shù)。

      聚集函數(shù)( aggregate function): 運行在行組上,計算和返回單個值的函數(shù)。

      SQL聚集函數(shù):

      函數(shù) 說明
      AVG() 返回某列的平均值
      COUNT() 返回某列的行數(shù)
      MAX() 返回某列的最大值
      MIN() 返回某列的最小值
      SUM() 返回某列值之和

      AVG()函數(shù)

      AVG()通過對表中行數(shù)計數(shù)并計算特定列值之和,求得該列的平均值。 AVG()可用來返回所有列的平均值,也可以用來返回特定列或行的平均值。

      例子:使用AVG()返回products表中所有產(chǎn)品的平均價格

      SELECT AVG(prod_price) AS avg_price FROM products
      

      例子:AVG()也可以用來確定特定列或行的平均值。下面的例子返回特定供應商所提供產(chǎn)品的平均價格:

      SELECT AVG(prod_price) AS avg_price FROM products WHERE vend_id = 1003
      

      只用于單個列 AVG()只能用來確定特定數(shù)值列的平均值,而且列名必須作為函數(shù)參數(shù)給出。為了獲得多個列的平均值,必須使用多個AVG()函數(shù)。

      NULL值 :AVG()函數(shù)忽略列值為NULL的行。

      COUNT()函數(shù)

      COUNT()函數(shù)進行計數(shù)。可利用COUNT()確定表中行的數(shù)目或符合特定條件的行的數(shù)目。

      COUNT()函數(shù)有兩種使用方式。

      • 使用COUNT(*)對表中行的數(shù)目進行計數(shù), 不管表列中包含的是空值( NULL)還是非空值。
      • 使用COUNT(column)對特定列中具有值的行進行計數(shù),忽略NULL值。

      例子:返回customers表中客戶的總數(shù);統(tǒng)計所有行,不管行中的列是否有數(shù)據(jù);

      SELECT COUNT(*) AS count_num FROM customers
      

      例子:只對具有電子郵件地址的客戶計數(shù);只統(tǒng)計cust_email中有數(shù)據(jù)的行;

      SELECT COUNT(cust_email) AS count_num FROM customers
      

      MAX()函數(shù)

      MAX()返回指定列中的最大值。 MAX()要求指定列名,如下所示:

      SELECT  MAX(prod_price) AS max_price FROM products 
      

      NULL值 :MAX()函數(shù)忽略列值為NULL的行。

      MIN()函數(shù)

      MIN()的功能正好與MAX()功能相反,它返回指定列的最小值。與MAX()一樣, MIN()要求指定列名,如下所示:

      SELECT  MIN(prod_price) AS min_price FROM products 
      

      NULL值: MIN()函數(shù)忽略列值為NULL的行。

      SUM()函數(shù)

      SUM()用來返回指定列值的和(總計)。

      SELECT SUM(quantity) as items_ordered FROM orderitems WHERE order_num = 20005
      

      SUM()也可以用來合計計算值。在下面的例子中,合計每項物品的item_price*quantity,得出總的訂單金額:

      SELECT SUM(quantity*item_price) as total_price FROM orderitems WHERE order_num = 20005
      

      在多個列上進行計算 :如本例所示,利用標準的算術操作符,所有聚集函數(shù)都可用來執(zhí)行多個列上的計算。

      NULL值 :SUM()函數(shù)忽略列值為NULL的行。

      聚集不同值

      以上5個聚集函數(shù)都可以如下使用:

      • 對所有的行執(zhí)行計算,指定ALL參數(shù)或不給參數(shù)(因為ALL是默認行為);
      • 只包含不同的值,指定DISTINCT參數(shù)。

      下面的例子使用AVG()函數(shù)返回特定供應商提供的產(chǎn)品的平均價格。

      它與上面的SELECT語句相同,但使用了DISTINCT參數(shù),因此平均值只考慮各個不同的價格

      SELECT AVG(DISTINCT prod_price) AS avg_price FROM products WHERE vend_id = 1003
      

      注意 :如果指定列名,則DISTINCT只能用于COUNT()。DISTINCT不能用于COUNT(*),因此不允許使用COUNT( DISTINCT),否則會產(chǎn)生錯誤。類似地, DISTINCT必須使用列名,不能用于計算或表達式

      將DISTINCT用于MIN()和MAX() :雖然DISTINCT從技術上可用于MIN()和MAX(),但這樣做實際上沒有價值。一個列中的最小值和最大值不管是否包含不同值都是相同的。

      組合聚集函數(shù)

      目前為止的所有聚集函數(shù)例子都只涉及單個函數(shù)。

      但實際上SELECT語句可根據(jù)需要包含多個聚集函數(shù)。請看下面的例子:

      SELECT AVG(prod_price) AS avg_price , COUNT(*) AS num_items, MIN(prod_price) AS min_price,MAX(prod_price) AS max_price  FROM products
      

      分組數(shù)據(jù)

      數(shù)據(jù)分組

      目前為止的所有計算都是在表的所有數(shù)據(jù)或匹配特定的WHERE子句的數(shù)據(jù)上進行的。

      下面的例子返回供應商1003提供的產(chǎn)品數(shù)目:

      SELECT COUNT(*) AS num_prods FROM products WHERE vend_id = 1003
      

      但如果要返回每個供應商提供的產(chǎn)品數(shù)目怎么辦?或者返回只提供單項產(chǎn)品的供應商所提供的產(chǎn)品,或返回提供10個以上產(chǎn)品的供應商怎么辦?

      這就是分組顯身手的時候了。

      分組允許把數(shù)據(jù)分為多個邏輯組,以便能對每個組進行聚集計算。

      創(chuàng)建分組

      分組是在SELECT語句的GROUP BY子句中建立的。

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

      上面的SELECT語句指定了兩個列, vend_id包含產(chǎn)品供應商的ID,num_prods為計算字段(用COUNT(*)函數(shù)建立)。

      GROUP BY子句指示MySQL按vend_id排序并分組數(shù)據(jù)。這導致對每個vend_id而不是整個表計算num_prods一次。從輸出中可以看到,供應商1001有3個產(chǎn)品,供應商1002有2個產(chǎn)品,供應商1003有7個產(chǎn)品,而供應商1005有2個產(chǎn)品。

      因為使用了GROUP BY,就不必指定要計算和估值的每個組了。系統(tǒng)會自動完成。 GROUP BY子句指示MySQL分組數(shù)據(jù),然后對每個組而不是整個結果集進行聚集。

      在具體使用GROUP BY子句前,需要知道一些重要的規(guī)定。

      • GROUP BY子句可以包含任意數(shù)目的列。這使得能對分組進行嵌套,為數(shù)據(jù)分組提供更細致的控制。
      • 如果在GROUP BY子句中嵌套了分組,數(shù)據(jù)將在最后規(guī)定的分組上進行匯總。換句話說,在建立分組時,指定的所有列都一起計算(所以不能從個別的列取回數(shù)據(jù))。
      • GROUP BY子句中列出的每個列都必須是檢索列或有效的表達式(但不能是聚集函數(shù))。如果在SELECT中使用表達式,則必須在GROUP BY子句中指定相同的表達式。不能使用別名。
      • 除聚集計算語句外, SELECT語句中的每個列都必須在GROUP BY子句中給出
      • 如果分組列中具有NULL值,則NULL將作為一個分組返回。如果列中有多行NULL值,它們將分為一組
      • GROUP BY子句必須出現(xiàn)在WHERE子句之后, ORDER BY子句之前

      過濾分組

      除了能用GROUP BY分組數(shù)據(jù)外, MySQL還允許過濾分組,規(guī)定包括哪些分組,排除哪些分組

      例如,可能想要列出至少有兩個訂單的所有顧客。為得出這種數(shù)據(jù),必須基于完整的分組而不是個別的行進行過濾。

      我們已經(jīng)看到了WHERE子句的作用。但是,在這個例子中WHERE不能完成任務,因為WHERE過濾指定的是行而不是分組。事實上, WHERE沒有分組的概念。

      MySQL為此目的提供了另外的子句,那就是HAVING子句。

      HAVING非常類似于WHERE。事實上,目前為止所學過的所有類型的WHERE子句都可以用HAVING來替代。唯一的差別是WHERE過濾行,而HAVING過濾分組。

      例如:列出至少有兩個訂單的所有顧客

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

      最后一行增加了HAVING子句,它過濾COUNT(*) >=2(兩個以上的訂單)的那些分組。

      分組和排序

      雖然GROUP BY和ORDER BY經(jīng)常完成相同的工作,但它們是非常不同的。

      以下列出了它們之間的差別:

      ORDER BY GROUP BY
      排序產(chǎn)生的輸出 分組行。但輸出可能不是分組的順序
      任意列都可以使用(甚至非選擇的列也可以使用) 只可能使用選擇列或表達式列,而且必須使用每個選擇列表達式
      不一定需要 如果與聚集函數(shù)一起使用列(或表達式),則必須使用

      SELECT子句順序

      下表列出了在SELECT語句中使用時必須遵循的次序,列出迄今為止所學過的子句。

      子句 說明 是否必須使用
      SELECT 要返回的列或表達式
      FROM 從中檢索數(shù)據(jù)的表 僅在從表選擇數(shù)據(jù)時使用
      WHERE 行級過濾
      GROUP BY 分組說明 僅在按組計算聚集時使用
      HAVING 組級過濾
      ORDER BY 輸出排序順序
      LIMIT 要檢索的行數(shù)

      使用子查詢

      迄今為止我們所看到的所有SELECT語句都是簡單查詢,即從單個數(shù)據(jù)庫表中檢索數(shù)據(jù)的單條語句

      SQL還允許創(chuàng)建子查詢( subquery) ,即嵌套在其他查詢中的查詢

      利用子查詢進行過濾

      有如下表:

      對于包含訂單號、客戶ID、訂單日期的每個訂單, orders表存儲一行。

      各訂單的物品存儲在相關的orderitems表中。 orders表不存儲客戶信息。它只存儲客戶的ID。實際的客戶信息存儲在customers表中。

      例子:需要列出訂購物品TNT2的所有客戶,步驟如下:

      • 檢索包含物品TNT2的所有訂單的編號。
      • 檢索具有前一步驟列出的訂單編號的所有客戶的ID。
      • 檢索前一步驟返回的所有客戶ID的客戶信息。
      1. 查詢點單編號
      SELECT order_num FROM orderitems WHERE prod_id = 'TNT2'
      
      1. 查詢用戶ID
      SELECT cust_id FROM orders WHERE order_num in (20005,20007)
      
      1. 查詢用戶信息
      SELECT cust_name,cust_contact FROM customers WHERE cust_id in (10001,10004)
      

      組合查詢:

      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 = 'TNT2'
      	)
      )
      

      在SELECT語句中,子查詢總是從內向外處理

      列必須匹配 在WHERE子句中使用子查詢(如這里所示),應該保證SELECT語句具有與WHERE子句中相同數(shù)目的列。通常,
      子查詢將返回單個列并且與單個列匹配,但如果需要也可以使用多個列。

      子查詢和性能: 這里給出的代碼有效并獲得所需的結果。

      但是,使用子查詢并不總是執(zhí)行這種類型的數(shù)據(jù)檢索的最有效的方法。可參考:連接表

      作為計算字段使用子查詢

      使用子查詢的另一方法是創(chuàng)建計算字段。假如需要顯示customers表中每個客戶的訂單總數(shù)。

      訂單與相應的客戶ID存儲在orders表中。

      為了執(zhí)行這個操作,遵循下面的步驟:

      1. 從customers表中檢索客戶列表。
      2. 對于檢索出的每個客戶,統(tǒng)計其在orders表中的訂單數(shù)目。
      SELECT cust_name,cust_state,(
      	SELECT COUNT(*) FROM orders WHERE orders.cust_id = customers.cust_id 
      ) AS orders FROM customers ORDER BY cust_name
      

      orders是一個計算字段,它是由圓括號中的子查詢建立的。該子查詢對檢索出的每個客戶執(zhí)行一次。

      子查詢中的WHERE子句與前面使用的WHERE子句稍有不同,因為它使用了完全限定列名;

      這種類型的子查詢稱為相關子查詢。任何時候只要列名可能有多義性,就必須使用這種語法(表名和列名由一個句點分隔)。

      逐漸增加子查詢來建立查詢: 用子查詢測試和調試查詢很有技巧性,特別是在這些語句的復雜性不斷增加的情況下更是如此。 用子查詢建立(和測試)查詢的最可靠的方法是逐漸進行,這與MySQL處理它們的方法非常相同。首先,建立和測試最內層的查詢。然后,用硬編碼數(shù)據(jù)建立和測試外層查詢,并且僅在確認它正常后才嵌入子查詢。這時,再次測試它。對于要增加的每個查詢,重復這些步驟。這樣做僅給構造查詢增加了一點點時間,但節(jié)省了以后(找出查詢?yōu)槭裁床徽#┑拇罅繒r間,并且極大地提高了查詢一開始就正常工作的可能性。

      聯(lián)結表

      聯(lián)結

      SQL最強大的功能之一就是能在數(shù)據(jù)檢索查詢的執(zhí)行中聯(lián)結(join)表。

      在能夠有效地使用聯(lián)結前,必須了解關系表以及關系數(shù)據(jù)庫設計的一些基礎知識。

      關系表

      表與表之間存在某種關系,由外鍵相關聯(lián)。

      外鍵(foreign key): 外鍵為某個表中的一列,它包含另一個表的主鍵值,定義了兩個表之間的關系。

      為什么要使用聯(lián)結

      如果數(shù)據(jù)存儲在多個表中,怎樣用單條SELECT語句檢索出數(shù)據(jù)?

      答案是使用聯(lián)結。簡單地說,聯(lián)結是一種機制,用來在一條SELECT語句中關聯(lián)表,因此稱之為聯(lián)結。使用特殊的語法,可以聯(lián)結多個表返回一組輸出,聯(lián)結在運行時關聯(lián)表中正確的行。

      維護引用完整性: 重要的是,要理解聯(lián)結不是物理實體。換句話說,它在實際的數(shù)據(jù)庫表中不存在。聯(lián)結由MySQL根據(jù)需
      要建立,它存在于查詢的執(zhí)行當中。

      在使用關系表時,僅在關系列中插入合法的數(shù)據(jù)非常重要。回到這里的例子,如果在products表中插入擁有非法供應商ID
      (即沒有在vendors表中出現(xiàn))的供應商生產(chǎn)的產(chǎn)品,則這些產(chǎn)品是不可訪問的,因為它們沒有關聯(lián)到某個供應商。

      為防止這種情況發(fā)生,可指示MySQL只允許在products表的供應商ID列中出現(xiàn)合法值(即出現(xiàn)在vendors表中的供應商)這就是維護引用完整性,它是通過在表的定義中指定主鍵和外鍵來實現(xiàn)的。(參見:創(chuàng)建和操作表

      創(chuàng)建聯(lián)結

      聯(lián)結的創(chuàng)建非常簡單,規(guī)定要聯(lián)結的所有表以及它們如何關聯(lián)即可

      SELECT vend_name, prod_name, prod_price 
      FROM vendors ,products 
      WHERE vendors.vend_id = products.vend_id 
      ORDER BY vend_name,prod_name
      

      與以前的SELECT語句不一樣,這條語句的FROM子句列出了兩個表,分別是vendors和products。它們就是這條SELECT語句聯(lián)結的兩個表的名字。這兩個表用WHERE子句正確聯(lián)結, WHERE子句指示MySQL匹配vendors表中的vend_id和products表中的vend_id。

      可 以 看 到 要 匹 配 的 兩 個 列 以 vendors.vend_id 和 products.vend_id指定。這里需要這種完全限定列名,因為如果只給出vend_id,則MySQL不知道指的是哪一個(它們有兩個,每個表中一個)。

      完全限定列名在引用的列可能出現(xiàn)二義性時,必須使用完全限定列名(用一個點分隔的表名和列名)。如果引用一個沒有用表名限制的具有二義性的列名, MySQL將返回錯誤。

      WHERE子句的重要性

      利用WHERE子句建立聯(lián)結關系似乎有點奇怪,但實際上,有一個很充分的理由。請記住,在一條SELECT語句中聯(lián)結幾個表時,相應的關系是在運行中構造的在數(shù)據(jù)庫表的定義中不存在能指示MySQL如何對表進行聯(lián)結的東西。你必須自己做這件事情。在聯(lián)結兩個表時,你實際上做的是將第一個表中的每一行與第二個表中的每一行配對。 WHERE子句作為過濾條件,它只包含那些匹配給定條件(這里是聯(lián)結條件)的行

      沒有WHERE子句,第一個表中的每個行將與第二個表中的每個行配對,而不管它們邏輯上是否可以配在一起。

      笛卡兒積(cartesian product) :由沒有聯(lián)結條件的表關系返回的結果為笛卡兒積。檢索出的行的數(shù)目將是第一個表中的行數(shù)乘以第二個表中的行數(shù)。

      內部聯(lián)結

      目前為止所用的聯(lián)結稱為等值聯(lián)結(equijoin),它基于兩個表之間的相等測試這種聯(lián)結也稱為內部聯(lián)結

      其實,對于這種聯(lián)結可以使用稍微不同的語法來明確指定聯(lián)結的類型。

      SELECT
      	vend_name,
      	prod_name,
      	prod_price 
      FROM
      	vendors
      	INNER JOIN products ON vendors.vend_id = products.vend_id
      

      此語句中的SELECT與前面的SELECT語句相同,但FROM子句不同。這里,兩個表之間的關系是FROM子句的組成部分,以INNER JOIN指定。在使用這種語法時,聯(lián)結條件用特定的ON子句而不是WHERE子句給出。傳遞給ON的實際條件與傳遞給WHERE的相同。

      聯(lián)結多個表

      SQL對一條SELECT語句中可以聯(lián)結的表的數(shù)目沒有限制。創(chuàng)建聯(lián)結的基本規(guī)則也相同。

      SELECT
      	vend_name,
      	prod_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 = 20005
      

      性能考慮:MySQL在運行時關聯(lián)指定的每個表以處理聯(lián)結。這種處理可能是非常耗費資源的,因此應該仔細,不要聯(lián)結不必要的表。聯(lián)結的表越多,性能下降越厲害

      創(chuàng)建高級聯(lián)結

      使用表別名

      別名除了用于列名計算字段外, SQL還允許給表名起別名。這樣做有兩個主要理由:

      • 縮短SQL語句;
      • 允許在單條SELECT語句中多次使用相同的表
      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 = 'TNT2'
      

      在此例子中,表別名只用于WHERE子句。但是,表別名不僅能用于WHERE子句,它還可以用于SELECT的列表、 ORDER BY子句以及語句的其他部分。

      應該注意,表別名只在查詢執(zhí)行中使用與列別名不一樣,表別名不返回到客戶機

      使用不同類型的聯(lián)結

      之前已經(jīng)了解了內部聯(lián)結或等值聯(lián)結( equijoin) 的簡單聯(lián)結

      現(xiàn)在來看3種其他聯(lián)結,它們分別是自聯(lián)結自然聯(lián)結外部聯(lián)結

      自聯(lián)結

      使用表別名的主要原因之一是能在單條SELECT語句中不止一次引用相同的表

      例子:查找生成某商品(其ID為DTNTR)的的生產(chǎn)商生產(chǎn)的其他商品;

      方法1(子查詢):

      SELECT
      	prod_id,
      	prod_name 
      FROM
      	products 
      WHERE
      	vend_id = ( SELECT vend_id FROM products WHERE prod_id = 'DTNTR' )
      

      方法2(自聯(lián)結):

      SELECT
      	p1.prod_id,
      	p2.prod_name 
      FROM
      	products AS p1,
      	products AS p2 
      WHERE
      	p1.vend_id = p2.vend_id 
      	AND p2.prod_id = 'DTNTR'
      

      此查詢中需要的兩個表實際上是相同的表,因此products表在FROM子句中出現(xiàn)了兩次。雖然這是完全合法的,但對products
      的引用具有二義性,因為MySQL不知道你引用的是products表中的哪個實例。

      為解決此問題,使用了表別名。 products的第一次出現(xiàn)為別名p1,第二次出現(xiàn)為別名p2。現(xiàn)在可以將這些別名用作表名。

      例如, SELECT語句使用p1前綴明確地給出所需列的全名。如果不這樣, MySQL將返回錯誤,因為分別存在兩個名為prod_id、 prod_name的列。 MySQL不知道想要的是哪一個列(即使它們事實上是同一個列)。 WHERE(通過匹配p1中的vend_id和p2中的vend_id)首先聯(lián)結兩個表,然后按第二個表中的prod_id過濾數(shù)據(jù),返回所需的數(shù)據(jù)。

      用自聯(lián)結而不用子查詢自聯(lián)結通常作為外部語句用來替代從相同表中檢索數(shù)據(jù)時使用的子查詢語句

      雖然最終的結果是相同的,但有時候處理聯(lián)結遠比處理子查詢快得多。應該試一下兩種方法,以確定哪一種的性能更好。

      自然聯(lián)結

      無論何時對表進行聯(lián)結,應該至少有一個列出現(xiàn)在不止一個表中(被聯(lián)結的列)

      標準的聯(lián)結(前一章中介紹的內部聯(lián)結)返回所有數(shù)據(jù),甚至相同的列多次出現(xiàn)。 自然聯(lián)結排除多次出現(xiàn),使每個列只返回一次。

      怎樣完成這項工作呢?答案是,系統(tǒng)不完成這項工作,由你自己完成它。自然聯(lián)結是這樣一種聯(lián)結,其中你只能選擇那些唯一的列。這一般是*通過對表使用通配符(SELECT ),對所有其他表的列使用明確的子集來完成的。

      SELECT
      	c.*,
      	o.order_num,
      	o.order_date,
      	oi.prod_id
      FROM
      	customers AS c,
      	orders AS o,
      	orderitems AS oi
      WHERE
      	c.cust_id = o.cust_id
      	AND oi.order_item = o.order_num
      	AND prod_id = 'FB'
      

      在這個例子中,通配符只對第一個表使用。所有其他列明確列出,所以沒有重復的列被檢索出來。

      外部聯(lián)結

      許多聯(lián)結將一個表中的行與另一個表中的行相關聯(lián)。但有時候會需要包含沒有關聯(lián)行的那些行。

      例如,可能需要使用聯(lián)結來完成以下工作:

      • 對每個客戶下了多少訂單進行計數(shù),包括那些至今尚未下訂單的客戶;
      • 列出所有產(chǎn)品以及訂購數(shù)量,包括沒有人訂購的產(chǎn)品;
      • 計算平均銷售規(guī)模,包括那些至今尚未下訂單的客戶。

      在上述例子中,聯(lián)結包含了那些在相關表中沒有關聯(lián)行的行。這種類型的聯(lián)結稱為外部聯(lián)結

      下面的SELECT語句給出一個簡單的內部聯(lián)結。它檢索所有客戶及其訂單:

      SELECT
      	customers.cust_id,
      	orders.order_num
      FROM
      	customers INNER JOIN orders ON customers.cust_id = orders.cust_id
      

      外部聯(lián)結語法類似。為了檢索所有客戶,包括那些沒有訂單的客戶,可如下進行:

      SELECT
      	customers.cust_id,
      	orders.order_num 
      FROM
      	customers
      	LEFT OUTER JOIN orders ON customers.cust_id = orders.cust_id
      

      與內部聯(lián)結關聯(lián)兩個表中的行不同的是,外部聯(lián)結還包括沒有關聯(lián)行的行在使用OUTER JOIN語法時,必須使用RIGHT或LEFT關鍵字指定包括其所有行的表( RIGHT指出的是OUTER JOIN右邊的表,而LEFT指出的是OUTER JOIN左邊的表)

      上面的例子使用LEFT OUTER JOIN從FROM子句的左邊表(customers表)中選擇所有行。

      左外連接(Left Outer Join)

      左外連接從左表(左側表)中選取所有的行,以及右表中與左表匹配的行。如果右表中沒有匹配的行,則在結果集中用 NULL 值填充右表的列。

      右外連接(Right Outer Join)

      右外連接從右表(右側表)中選取所有的行,以及左表中與右表匹配的行。如果左表中沒有匹配的行,則在結果集中用 NULL 值填充左表的列。

      使用帶聚集函數(shù)的聯(lián)結

      雖然至今為止聚集函數(shù)的所有例子只是從單個表匯總數(shù)據(jù),但這些函數(shù)也可以與聯(lián)結一起使用

      如果要檢索所有客戶及每個客戶所下的訂單數(shù),下面使用了COUNT()函數(shù)的代碼可完成此工作:

      SELECT
      	customers.cust_id,
      	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
      

      此SELECT語句使用INNER JOIN將customers和orders表互相關聯(lián)。

      GROUP BY 子句按客戶分組數(shù)據(jù) , 因此,函數(shù)調用 COUNT(orders.order_num)對每個客戶的訂單計數(shù),將它作為num_ord返回。

      使用聯(lián)結和聯(lián)結條件

      在總結關于聯(lián)結的這兩章前,有必要匯總一下關于聯(lián)結及其使用的某些要點。

      • 注意所使用的聯(lián)結類型。一般我們使用內部聯(lián)結,但使用外部聯(lián)結也是有效的。
      • 保證使用正確的聯(lián)結條件,否則將返回不正確的數(shù)據(jù)。
      • 應該總是提供聯(lián)結條件,否則會得出笛卡兒積。
      • 在一個聯(lián)結中可以包含多個表,甚至對于每個聯(lián)結可以采用不同的聯(lián)結類型。雖然這樣做是合法的,一般也很有用,但應該在一起測試它們前,分別測試每個聯(lián)結。這將使故障排除更為簡單。

      組合查詢

      多數(shù)SQL查詢都只包含從一個或多個表中返回數(shù)據(jù)的單條SELECT語句。 MySQL也允許執(zhí)行多個查詢(多條SELECT語句),并將結果作為單個查詢結果集返回。這些組合查詢通常稱為并( union) 或復合查詢(compound query)

      有兩種基本情況,其中需要使用組合查詢:

      • 在單個查詢中從不同的表返回類似結構的數(shù)據(jù);
      • 對單個表執(zhí)行多個查詢,按單個查詢返回數(shù)據(jù)。

      組合查詢和多個WHERE條件多數(shù)情況下,組合相同表的兩個查詢完成的工作與具有多個WHERE子句條件的單條查詢完成的工作相同。換句話說,任何具有多個WHERE子句的SELECT語句都可以作為一個組合查詢給出,在以下段落中可以看到這一點。這兩種技術在不同的查詢中性能也不同。因此,應該試一下這兩種技術,以確定對特定的查詢哪一種性能更好。

      創(chuàng)建組合查詢

      可用UNION操作符來組合數(shù)條SQL查詢。利用UNION,可給出多條SELECT語句,將它們的結果組合成單個結果集

      使用UNION

      UNION的使用很簡單。所需做的只是給出每條SELECT語句,在各條語句之間放上關鍵字UNION。

      例子:需要價格小于等于5的所有物品的一個列表,而且還想包括供應商1001和1002生產(chǎn)的所有物品(不考慮價格)。當然,可以利用WHERE子句來完成此工作,不過這次我們將使用UNION。

      單條sql語句:

      SELECT
        vend_id,
        prod_id,
        prod_price 
      FROM
        products 
      WHERE
        prod_price <= 5
      
      SELECT
        vend_id,
        prod_id,
        prod_price 
      FROM
        products 
      WHERE
        vend_id IN (1001,1002)
      

      組合語句如下:

      SELECT
        vend_id,
        prod_id,
        prod_price 
      FROM
        products 
      WHERE
        vend_id IN ( 1001, 1002 ) UNION
      SELECT
        vend_id,
        prod_id,
        prod_price 
      FROM
        products 
      WHERE
        prod_price <= 5
      

      這條語句由前面的兩條SELECT語句組成,語句中用UNION關鍵字分隔。 UNION指示MySQL執(zhí)行兩條SELECT語句,并把輸出組合成單個查詢結果集。

      作為參考,這里給出使用多條WHERE子句而不是使用UNION的相同查詢:

      SELECT
        vend_id,
        prod_id,
        prod_price 
      FROM
        products 
      WHERE
        prod_price <= 5 
        OR vend_id IN (1001,1002)
      

      在這個簡單的例子中,使用UNION可能比使用WHERE子句更為復雜。但對于更復雜的過濾條件,或者從多個表(而不是單個表)中檢索數(shù)據(jù)的情形,使用UNION可能會使處理更簡單。

      UNION規(guī)則

      在進行并時有幾條規(guī)則需要注意 :

      • UNION必須由兩條或兩條以上的SELECT語句組成,語句之間用關鍵字UNION分隔(因此,如果組合4條SELECT語句,將要使用3個UNION關鍵字)。
      • UNION中的每個查詢必須包含相同的列、表達式或聚集函數(shù)(不過各個列不需要以相同的次序列出)
      • 列數(shù)據(jù)類型必須兼容:類型不必完全相同,但必須是DBMS可以隱含地轉換的類型(例如,不同的數(shù)值類型或不同的日期類型)。

      包含或取消重復的行

      上面的例子中,第一條SELECT語句返回4行,第二條SELECT語句返回5行。但在用UNION組合兩條SELECT語句后,只返回了8行而不是9行。

      UNION從查詢結果集中自動去除了重復的行(它的行為與單條SELECT語句中使用多個WHERE子句條件一樣 )

      這是UNION的默認行為,但是如果需要,可以改變它。事實上,如果想返回所有匹配行,可使用UNION ALL而不是UNION

      SELECT
        vend_id,
        prod_id,
        prod_price 
      FROM
        products 
      WHERE
        vend_id IN ( 1001, 1002 ) UNION ALL
      SELECT
        vend_id,
        prod_id,
        prod_price 
      FROM
        products 
      WHERE
        prod_price <= 5
      

      UNION與WHERE: 本章開始時說過, UNION幾乎總是完成與多個WHERE條件相同的工作。 UNION ALL為UNION的一種形式,它完成WHERE子句完成不了的工作

      如果確實需要每個條件的匹配行全部出現(xiàn)(包括重復行),則必須使用UNION ALL而不是WHERE。

      對組合查詢結果排序

      SELECT語句的輸出用ORDER BY子句排序。在用UNION組合查詢時,只能使用一條ORDER BY子句,它必須出現(xiàn)在最后一條SELECT語句之后。

      對于結果集,不存在用一種方式排序一部分,而又用另一種方式排序另一部分的情況,因此不允許使用多條ORDER BY子句。

      SELECT
        vend_id,
        prod_id,
        prod_price 
      FROM
        products 
      WHERE
        vend_id IN ( 1001, 1002 ) UNION ALL
      SELECT
        vend_id,
        prod_id,
        prod_price 
      FROM
        products 
      WHERE
        prod_price <= 5 
      ORDER BY
        vend_id,
        prod_price
      

      組合不同的表:為使表述比較簡單,本章例子中的組合查詢使用的均是相同的表。

      但是其中使用UNION的組合查詢可以應用不同的表

      全文本搜索

      理解全文本搜索

      并非所有引擎都支持全文本搜索 : MySQL支持幾種基本的數(shù)據(jù)庫引擎。并非所有的引擎都支持本書所描述的全文本搜索。兩個最常使用的引擎為MyISAM和InnoDB前者支持全文本搜索,而后者不支持

      這就是為什么雖然本書中 創(chuàng) 建 的 多 數(shù) 樣 例 表 使 用 InnoDB , 而有一個樣例表(productnotes表)卻使用MyISAM的原因。如果你的應用中需要全文本搜索功能,應該記住這一點。

      之前介紹了LIKE關鍵字,它利用通配操作符匹配文本(和部分文本)。使用LIKE,能夠查找包含特殊值或部分值的行(不管這些值位于列內什么位置)。

      使用正則表達式,可以編寫查找所需行的非常復雜的匹配模式。

      雖然這些搜索機制非常有用,但存在幾個重要的限制。

      • 性能——通配符和正則表達式匹配通常要求MySQL嘗試匹配表中所有行(而且這些搜索極少使用表索引)。因此,由于被搜索行數(shù)不斷增加,這些搜索可能非常耗時。
      • 明確控制——使用通配符和正則表達式匹配,很難(而且并不總是能)明確地控制匹配什么和不匹配什么。例如,指定一個詞必須匹配,一個詞必須不匹配,而一個詞僅在第一個詞確實匹配的情況下才可以匹配或者才可以不匹配。
      • 智能化的結果——雖然基于通配符和正則表達式的搜索提供了非常靈活的搜索,但它們都不能提供一種智能化的選擇結果的方法。例如,一個特殊詞的搜索將會返回包含該詞的所有行,而不區(qū)分包含單個匹配的行和包含多個匹配的行(按照可能是更好的匹配來排列它們)。類似,一個特殊詞的搜索將不會找出不包含該詞但包含其他相關詞的行。

      所有這些限制以及更多的限制都可以用全文本搜索來解決。在使用全文本搜索時, MySQL不需要分別查看每個行,不需要分別分析和處理每個詞。 MySQL創(chuàng)建指定列中各詞的一個索引,搜索可以針對這些詞進行。這樣, MySQL可以快速有效地決定哪些詞匹配(哪些行包含它們),哪些詞不匹配,它們匹配的頻率,等等。

      使用全文本搜索

      為了進行全文本搜索,必須索引被搜索的列,而且要隨著數(shù)據(jù)的改變不斷地重新索引。在對表列進行適當設計后, MySQL會自動進行所有的索引和重新索引。

      在索引之后, SELECT可與Match()和Against()一起使用以實際執(zhí)行搜索。

      啟用全文本搜索支持

      一般在創(chuàng)建表時啟用全文本搜索。 CREATE TABLE語句(參見:創(chuàng)建和操作表)接受FULLTEXT子句,它給出被索引列的一個逗號分隔的列表。

      下面的CREATE語句演示了FULLTEXT子句的使用:

      CREATE TABLE `productnotes` (
        `note_id` int NOT NULL AUTO_INCREMENT,
        `prod_id` char(10) NOT NULL,
        `note_date` datetime NOT NULL,
        `note_text` text NUll,
        PRIMARY KEY (`note_id`),
        FULLTEXT KEY (`note_text`)
      ) ENGINE=MyISAM 
      

      這些列中有一個名為note_text的列,為了進行全文本搜索, MySQL根據(jù)子句FULLTEXT(note_text)的指示對它進行索引。這里的FULLTEXT索引單個列,如果需要也可以指定多個列

      在定義之后, MySQL自動維護該索引。在增加、更新或刪除行時,索引隨之自動更新。

      可以在創(chuàng)建表時指定FULLTEXT,或者在稍后指定(在這種情況下所有已有數(shù)據(jù)必須立即索引)。

      不要在導入數(shù)據(jù)時使用FULLTEXT :更新索引要花時間,雖然不是很多,但畢竟要花時間。如果正在導入數(shù)據(jù)到一個新表,此時不應該啟用FULLTEXT索引。應該首先導入所有數(shù)據(jù),然后再修改表, 定義FULLTEXT。 這樣有助于更快地導入數(shù)據(jù)(而且使索引數(shù)據(jù)的總時間小于在導入每行時分別進行索引所需的總時間)。

      進行全文本搜索

      在索引之后,使用兩個函數(shù)Match()和Against()執(zhí)行全文本搜索,其中Match()指定被搜索的列Against()指定要使用的搜索表達式。

      SELECT
        note_text 
      FROM
        productnotes 
      WHERE
        MATCH ( note_text ) Against (
        "rabbit")
      

      此SELECT語句檢索單個列note_text。由于WHERE子句,一個全文本搜索被執(zhí)行。 Match(note_text)指示MySQL針對指定的列進行搜索Against('rabbit')指定詞rabbit作為搜索文本。由于有兩行包含詞rabbit,這兩個行被返回。

      使用完整的Match()說 明傳遞給Match()的值必須與FULLTEXT()定義中的相同。如果指定多個列,則必須列出它們(而且次序正確)。

      搜索不區(qū)分大小寫 :除非使用BINARY方式,否則全文本搜索不區(qū)分大小寫。

      利用link查詢:

      SELECT
        note_text 
      FROM
        productnotes 
      WHERE
      note_text LIKE '%rabbit%'
      

      述兩條SELECT語句都不包含ORDER BY子句。后者(使用LIKE)以不特別有用的順序返回數(shù)據(jù)

      前者(使用全文本搜索)返回以文本匹配的良好程度排序的數(shù)據(jù)。兩個行都包含詞rabbit,但包含詞rabbit作為第3個詞的行的等級比作為第20個詞的行高。這很重要。全文本搜索的一個重要部分就是對結果排序。具有較高等級的行先返回(因為這些行很可能是你真正想要的行)。

      排序多個搜索項 :如果指定多個搜索項,則包含多數(shù)匹配詞的那些行將具有比包含較少詞(或僅有一個匹配)的那些行高的等級值。

      正如所見,全文本搜索提供了簡單LIKE搜索不能提供的功能。而且,由于數(shù)據(jù)是索引的,全文本搜索還相當快。

      使用查詢擴展

      查詢擴展用來設法放寬所返回的全文本搜索結果的范圍。

      考慮下面的情況。你想找出所有提到anvils的注釋。只有一個注釋包含詞anvils,但你還想找出可能與你的搜索有關的所有其他行,即使它們不包含詞anvils。

      這也是查詢擴展的一項任務。在使用查詢擴展時, MySQL對數(shù)據(jù)和索引進行兩遍掃描來完成搜索:

      • 首先,進行一個基本的全文本搜索,找出與搜索條件匹配的所有行;
      • 其次, MySQL檢查這些匹配行并選擇所有有用的詞(我們將會簡要地解釋MySQL如何斷定什么有用,什么無用)。
      • 再其次, MySQL再次進行全文本搜索,這次不僅使用原來的條件,而且還使用所有有用的詞

      利用查詢擴展,能找出可能相關的結果,即使它們并不精確包含所查找的詞。

      SELECT
        note_text 
      FROM
        productnotes 
      WHERE
        MATCH ( note_text ) Against (
        "anvils" WITH QUERY EXPANSION)
      

      這次返回了7行。

      第一行包含詞anvils,因此等級最高。

      第二行與anvils無關,但因為它包含第一行中的兩個詞( customer和recommend),所以也被檢索出來。

      第3行也包含這兩個相同的詞,但它們在文本中的位置更靠后且分開得更遠,因此也包含這一行,但等級為第三。第三行確實也沒有涉及anvils(按它們的產(chǎn)品名)。

      正如所見,查詢擴展極大地增加了返回的行數(shù),但這樣做也增加了你實際上并不想要的行的數(shù)目。

      行越多越好 :表中的行越多(這些行中的文本就越多),使用查詢擴展返回的結果越好。

      布爾文本搜索

      MySQL支持全文本搜索的另外一種形式,稱為布爾方式( boolean mode)。以布爾方式,可以提供關于如下內容的細節(jié):

      • 要匹配的詞;
      • 要排斥的詞(如果某行包含這個詞,則不返回該行,即使它包含其他指定的詞也是如此);
      • 排列提示(指定某些詞比其他詞更重要,更重要的詞等級更高);
      • 表達式分組;
      • 另外一些內容。

      即使沒有FULLTEXT索引也可以使用 : 布爾方式不同于迄今為止使用的全文本搜索語法的地方在于 , 即使沒有定義FULLTEXT索引,也可以使用它但這是一種非常緩慢的操作(其性能將隨著數(shù)據(jù)量的增加而降低)

      例子:全文本搜索檢索包含詞heavy的所有行(有兩行)

      SELECT
        note_text 
      FROM
        productnotes 
      WHERE
        MATCH ( note_text ) Against (
        "heavy" IN BOOLEAN MODE)
      

      其中使用了關鍵字IN BOOLEAN MODE,但實際上沒有指定布爾操作符,因此,其結果與沒有指定布爾方式的結果相同。

      為了匹配包含heavy但不包含任意以rope開始的詞的行, 可使用以下查詢:

      SELECT
        note_text 
      FROM
        productnotes 
      WHERE
        MATCH ( note_text ) Against (
        "heavy -rope*" IN BOOLEAN MODE)
      

      這次只返回一行。這一次仍然匹配詞heavy,但-rope*明確地指示MySQL排除包含rope*(任何以rope開始的詞,包括ropes)的行,這就是為什么上一個例子中的第一行被排除的原因。

      我們已經(jīng)看到了兩個全文本搜索布爾操作符-和*, - 排除一個詞,而*是截斷操作符(可想象為用于詞尾的一個通配符)。

      以下列出支持的所有布爾操作符:

      布爾操作符 說明
      + 包含,詞必須存在
      - 排除,詞必須不出現(xiàn)
      > 包含,而且增加等級值
      < 包含,且減少等級值
      () 把詞組成子表達式(允許這些子表達式作為一個組被包含、排除、排列等)
      ~ 取消一個詞的排序值
      * 詞尾的通配符
      "" 定義一個短語(與單個詞的列表不一樣,它匹配整個短語以便包含或排除這個短語)

      下面舉幾個例子,說明某些操作符如何使用:

      SELECT
        note_text 
      FROM
        productnotes 
      WHERE
        MATCH ( note_text ) Against (
        "+rabbit +bait" IN BOOLEAN MODE)
      

      這個搜索匹配包含詞rabbit和bait的行。

      SELECT
        note_text 
      FROM
        productnotes 
      WHERE
        MATCH ( note_text ) Against (
        "rabbit bait" IN BOOLEAN MODE)
      

      沒有指定操作符,這個搜索匹配包含rabbit和bait中的至少一個詞的行。

      SELECT
        note_text 
      FROM
        productnotes 
      WHERE
        MATCH ( note_text ) Against (
        '"rabbit bait"' IN BOOLEAN MODE)
      

      這個搜索匹配短語rabbit bait而不是匹配兩個詞rabbit和bait。

      SELECT
        note_text 
      FROM
        productnotes 
      WHERE
        MATCH ( note_text ) Against (
        ">rabbit <carrot" IN BOOLEAN MODE)
      

      匹配rabbit和carrot,增加前者的等級,降低后者的等級。

      SELECT
        note_text 
      FROM
        productnotes 
      WHERE
        MATCH ( note_text ) Against (
        "+safe +(<combination)" IN BOOLEAN MODE)
      

      這個搜索匹配詞safe和combination,降低后者的等級。

      排列而不排序 : 在布爾方式中,不按等級值降序排序返回的行

      全文本搜索的使用說明

      給出關于全文本搜索的某些重要的說明:

      • 在索引全文本數(shù)據(jù)時,短詞被忽略且從索引中排除。短詞定義為那些具有3個或3個以下字符的詞(如果需要,這個數(shù)目可以更改)。
      • MySQL帶有一個內建的非用詞( stopword)列表,這些詞在索引全文本數(shù)據(jù)時總是被忽略。如果需要,可以覆蓋這個列表(請參閱MySQL文檔以了解如何完成此工作)。
      • 許多詞出現(xiàn)的頻率很高,搜索它們沒有用處(返回太多的結果)。因此, MySQL規(guī)定了一條50%規(guī)則,如果一個詞出現(xiàn)在50%以上的行中,則將它作為一個非用詞忽略。 50%規(guī)則不用于IN BOOLEANMODE。
      • 如果表中的行數(shù)少于3行,則全文本搜索不返回結果(因為每個詞或者不出現(xiàn),或者至少出現(xiàn)在50%的行中)。
      • 忽略詞中的單引號。例如, don't索引為dont。
      • 不具有詞分隔符(包括日語和漢語)的語言不能恰當?shù)胤祷厝谋舅阉鹘Y果。
      • 如前所述,僅在MyISAM數(shù)據(jù)庫引擎中支持全文本搜索。

      插入數(shù)據(jù)

      INSERT是用來插入(或添加)行到數(shù)據(jù)庫表的。插入可以用幾種方式使用:

      • 插入完整的行;
      • 插入行的一部分;
      • 插入多行;
      • 插入某些查詢的結果。

      插入完整的行

      把數(shù)據(jù)插入表中的最簡單的方法是使用基本的INSERT語法,它要求指定表名和被插入到新行中的值。

      INSERT INTO customers
      VALUES
      	(
      		NULL,
      		"pep E.niehao",
      		"100 niehao",
      		"los niehao",
      		"ca",
      		"90046",
      		"usa",
      		NULL,
      NULL 
      	)
      

      此例子插入一個新客戶到customers表。存儲到每個表列中的數(shù)據(jù)在VALUES子句中給出,對每個列必須提供一個值。如果某
      個列沒有值(如上面的cust_contact和cust_email列),應該使用NULL值(假定表允許對該列指定空值)各個列必須以它們在表定義中出現(xiàn)的次序填充。第一列cust_id也為NULL。這是因為每次插入一個新行時,該列由MySQL自動增量。你不想給出一個值(這是MySQL的工作),又不能省略此列(如前所述,必須給出每個列),所以指定一個NULL值(它被MySQL忽略, MySQL在這里插入下一個可用的cust_id值)。

      雖然這種語法很簡單,但并不安全,應該盡量避免使用。

      上面的SQL語句高度依賴于表中列的定義次序,并且還依賴于其次序容易獲得的信息

      即使可得到這種次序信息,也不能保證下一次表結構變動后各個列保持完全相同的次序。

      因此,編寫依賴于特定列次序的SQL語句是很不安全的。如果這樣做,有時難免會出問題。

      編寫INSERT語句的更安全(不過更煩瑣)的方法如下:

      INSERT INTO customers ( cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_name )
      VALUES
      	(
      		"pep E.niehao",
      		"100 niehao",
      		"los niehao",
      		"ca",
      		"90046",
      		"usa",
      		NULL,
      NULL 
      	)
      

      此例子完成與前一個INSERT語句完全相同的工作,但在表名后的括號里明確地給出了列名。

      你會發(fā)現(xiàn)cust_id的NULL值是不必要的,cust_id列并沒有出現(xiàn)在列表中,所以不需要任何值。

      省略列

      如果表的定義允許,則可以在INSERT操作中省略某些列。省略的列必須滿足以下某個條件。

      • 該列定義為允許NULL值(無值或空值)
      • 在表定義中給出默認值。這表示如果不給出值,將使用默認值。

      提高整體性能:

      數(shù)據(jù)庫經(jīng)常被多個客戶訪問,對處理什么請求以及用什么次序處理進行管理是MySQL的任務。 INSERT操作可能很耗時(特別是有很多索引需要更新時),而且它可能降低等待處理的SELECT語句的性能。

      如果數(shù)據(jù)檢索是最重要的(通常是這樣),則你可以通過在INSERT和INTO之間添加關鍵字LOW_PRIORITY,指示MySQL
      降低INSERT語句的優(yōu)先級,如下所示:

      INSERT LOW_PRIORITY INTO

      這個方法也同樣適用于 UPDATE 和 DELETE 語句。

      插入多個行

      可以使用多條INSERT語句,甚至一次提交它們,每條語句用一個分號結束;

      INSERT INTO customers
      VALUES
      	( "pep E.niehao", "100 niehao", "los niehao", "ca", "90046", "usa", NULL, NULL );
      INSERT INTO customers
      VALUES
      	( "pep E.niehao", "100 niehao", "los niehao", "ca", "90046", "usa", NULL, NULL );
      

      或者,只要每條INSERT語句中的列名(和次序)相同,可以如下組合各語句:

      INSERT INTO customers ( cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_name )
      VALUES
      	( "pep E.niehao", "100 niehao", "los niehao", "ca", "90046", "usa", NULL, NULL ),
      	( "pep E.niehao", "100 niehao", "los niehao", "ca", "90046", "usa", NULL, NULL ),
      

      提高INSERT的性能此技術可以提高數(shù)據(jù)庫處理的性能,因為MySQL用單條INSERT語句處理多個插入比使用多條INSERT語句快。

      插入檢索出的數(shù)據(jù)

      INSERT一般用來給表插入一個指定列值的行。

      但是, INSERT還存在另一種形式,可以利用它將一條SELECT語句的結果插入表中

      這就是所謂的INSERT SELECT,顧名思義,它是由一條INSERT語句和一條SELECT語句組成的。

      例子:假如你想從另一表中合并客戶列表到你的customers表。 不需要每次讀取一行,然后再將它用INSERT插入,可以如下進行:

      INSERT TO 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 
      FROM
      	custnew
      

      這個例子使用INSERT SELECT從custnew中將所有數(shù)據(jù)導入customers。 SELECT語句從custnew檢索出要插入的值,而不
      是列出它們。 SELECT中列出的每個列對應于customers表名后所跟的列表中的每個列。這條語句將插入多少行有賴于custnew表中有多少行。如果這個表為空,則沒有行被插入

      INSERT SELECT中SELECT語句可包含WHERE子句以過濾插入的數(shù)據(jù)

      INSERT SELECT中的列名

      為簡單起見,這個例子在INSERT和SELECT語句中使用了相同的列名。但是,不一定要求列名匹配
      事實上, MySQL甚至不關心SELECT返回的列名。它使用的是列的位置,因此SELECT中的第一列(不管其列名)將用來填充表列中指定的第一個列,第二列將用來填充表列中指定的第二個列,如此等等。

      這對于從使用不同列名的表中導入數(shù)據(jù)是非常有用的

      更新和刪除數(shù)據(jù)

      更新數(shù)據(jù)

      為了更新(修改)表中的數(shù)據(jù),可使用UPDATE語句。可采用兩種方式使用UPDATE:

      • 更新表中特定行;
      • 更新表中所有行

      不要省略WHERE子句:在使用UPDATE時一定要注意細心。因為稍不注意,就會更新表中所有行。

      基本的UPDATE語句由3部分組成,分別是:

      • 要更新的表;
      • 列名和它們的新值;
      • 確定要更新行的過濾條件。
      UPDATE customers 
      SET cust_email = "elmer@fudd.com" 
      WHERE
      	cust_id = 10005
      

      多列更新

      UPDATE customers 
      SET cust_email = "elmer@fudd.com",
      cust_name = "ceshi" 
      WHERE
      	cust_id = 10005
      

      在UPDATE語句中使用子查詢: UPDATE語句中可以使用子查詢,使得能用SELECT語句檢索出的數(shù)據(jù)更新列數(shù)據(jù)。

      關于子查詢及使用的更多內容,參見:使用子查詢

      IGNORE關鍵字

      如果用UPDATE語句更新多行,并且在更新這些行中的一行或多行時出一個現(xiàn)錯誤,則整個UPDATE操作被取消錯誤發(fā)生前更新的所有行被恢復到它們原來的值)。

      為即使是發(fā)生錯誤,也繼續(xù)進行更新,可使用IGNORE關鍵字,如下所示:UPDATE IGNORE customers…

      為了刪除某個列的值,可設置它為NULL(假如表定義允許NULL值)

      刪除數(shù)據(jù)

      為了從一個表中刪除(去掉)數(shù)據(jù),使用DELETE語句。可以兩種方式使用DELETE:

      • 從表中刪除特定的行;
      • 從表中刪除所有行。

      不要省略WHERE子句: 在使用DELETE時一定要注意細心。因為稍不注意,就會錯誤地刪除表中所有行

      DELETE customers 
      FROM
      	cust_id = 10006
      

      DELETE不需要列名或通配符。

      DELETE刪除整行而不是刪除列。為了刪除指定的列,請使用UPDATE語句。

      刪除表的內容而不是表DELETE語句從表中刪除行,甚至是刪除表中所有行。但是, DELETE不刪除表本身。

      更快的刪除 :如果想從表中刪除所有行,不要使用DELETE。可使用TRUNCATE TABLE語句,它完成相同的工作,但速度更
      快( TRUNCATE實際是刪除原來的表并重新創(chuàng)建一個表,而不是逐行刪除表中的數(shù)據(jù))

      更新和刪除的指導原則

      前一節(jié)中使用的UPDATE和DELETE語句全都具有WHERE子句,這樣做的理由很充分。如果省略了WHERE子句,則UPDATE或DELETE將被應用到表中所有的行。換句話說,如果執(zhí)行UPDATE而不帶WHERE子句,則表中每個行都將用新值更新。類似地,如果執(zhí)行DELETE語句而不帶WHERE子句,表的所有數(shù)據(jù)都將被刪除。

      使用UPDATE或DELETE時所遵循的習慣:

      • 除非確實打算更新和刪除每一行,否則絕對不要使用不帶WHERE子句的UPDATE或DELETE語句。
      • 保證每個表都有主鍵(如果忘記這個內容,請參見:連結表),盡可能像WHERE子句那樣使用它(可以指定各主鍵、多個值或值的范圍)。
      • 在對UPDATE或DELETE語句使用WHERE子句前,應該先用SELECT進行測試,保證它過濾的是正確的記錄,以防編寫的WHERE子句不正確。
      • 使用強制實施引用完整性的數(shù)據(jù)庫(關于這個內容,請參見:連結表),這樣MySQL將不允許刪除具有與其他表相關聯(lián)的數(shù)據(jù)的行。

      創(chuàng)建和操縱表

      創(chuàng)建表

      MySQL不僅用于表數(shù)據(jù)操縱,而且還可以用來執(zhí)行數(shù)據(jù)庫和表的所有操作,包括表本身的創(chuàng)建和處理。

      一般有兩種創(chuàng)建表的方法:

      • 使用具有交互式創(chuàng)建和管理表的工具(GUI工具);
      • 表也可以直接用MySQL語句操縱。

      為了用程序創(chuàng)建表,可使用SQL的CREATE TABLE語句。

      表創(chuàng)建基礎

      為利用CREATE TABLE創(chuàng)建表,必須給出下列信息:

      • 新表的名字,在關鍵字CREATE TABLE之后給出
      • 表列的名字和定義,用逗號分隔

      CREATE TABLE語句也可能會包括其他關鍵字或選項,但至少要包括表的名字和列的細節(jié)

      CREATE TABLE `customers` (
        `cust_id` int(11) NOT NULL AUTO_INCREMENT,
        `cust_name` char(50) NOT NULL,
        `cust_address` char(50)  NULL,
        `cust_city` char(50)  NULL,
        `cust_state` char(5)  NULL,
        `cust_zip` char(10)  NULL,
        `cust_country` char(50)  NULL,
        `cust_contact` char(50)  NULL,
        `cust_email` char(255)  NULL,
        PRIMARY KEY (`cust_id`)
      ) ENGINE=InnoDB; 
      

      從上面的例子中可以看到,表名緊跟在CREATE TABLE關鍵字后面

      實際的表定義(所有列)括在圓括號之中。各列之間用逗號分隔。這個表由9列組成。

      每列的定義以列名(它在表中必須是唯一的)開始,后跟列的數(shù)據(jù)類型

      表的主鍵可以在創(chuàng)建表時用PRIMARY KEY關鍵字指定。這里,列cust_id指定作為主鍵列

      整條語句由右圓括號后的分號結束 。

      處理現(xiàn)有的表在創(chuàng)建新表時,指定的表名必須不存在,否則將出錯。如果要防止意外覆蓋已有的表, SQL要求首先手工刪
      除該表,然后再重建它,而不是簡單地用創(chuàng)建表語句覆蓋它。

      如果你僅想在一個表不存在時創(chuàng)建它,應該在表名后給出IFNOT EXISTS。這樣做不檢查已有表的模式是否與你打算創(chuàng)建
      的表模式相匹配。它只是查看表名是否存在,并且僅在表名不存在時創(chuàng)建它。

      使用NULL值

      NULL值就是沒有值或缺值允許NULL值的列也允許在插入行時不給出該列的值。不允許NULL值的列不接受該列沒有值的行,換句話說,在插入或更新行時,該列必須有值。

      每個表列或者是NULL列,或者是NOT NULL列,這種狀態(tài)在創(chuàng)建時由表的定義規(guī)定

      CREATE TABLE `orders` (
        `order_num` int(11) NOT NULL AUTO_INCREMENT,
        `order_date` datetime NOT NULL,
        `cust_id` int(11) NOT NULL,
        PRIMARY KEY (`order_num`),
      ) ENGINE=InnoDB
      

      這條語句創(chuàng)建本書中所用的orders表。

      orders包含3個列,分別是訂單號、訂單日期和客戶ID。所有3個列都需要,因此每個列的定義都含有關鍵字NOT NULL。這將會阻止插入沒有值的列。如果試圖插入沒有值的列,將返回錯誤,且插入失敗。

      理解NULL : 不要把NULL值與空串相混淆NULL值是沒有值,它不是空串。如果指定''(兩個單引號,其間沒有字符),這
      在NOT NULL列中是允許的。空串是一個有效的值,它不是無值。 NULL值用關鍵字NULL而不是空串指定。

      主鍵再介紹

      正如所述,主鍵值必須唯一

      即,表中的每個行必須具有唯一的主鍵值。如果主鍵使用單個列,則它的值必須唯一。如果使用多個列,則這些列的組合值必須唯一。

      CREATE TABLE例子都是用單個列作為主鍵。其中主鍵用以下的類似的語句定義:

      PRIMARY KEY (vend_id),
      

      為創(chuàng)建由多個列組成的主鍵,應該以逗號分隔的列表給出各列名,如下所示:

      PRIMARY KEY (order_num,order_item),
      

      訂單號(order_num列)和訂單物品(order_item列)的組合是唯一的,從而作為主鍵。

      主鍵可以在創(chuàng)建表時定義, 或者在創(chuàng)建表之后定義。

      主鍵和NULL值主鍵為其值唯一標識表中每個行的列。主鍵中只能使用不允許NULL值的列。允許NULL值的列不能作為唯一標識。

      使用AUTO_INCREMENT

      AUTO_INCREMENT告訴MySQL,本列每當增加一行時自動增量

      每次執(zhí)行一個INSERT操作時, MySQL自動對該列增量(從而才有這個關鍵字AUTO_INCREMENT),給該列賦予下一個可用的值。這樣給每個行分配一個唯一的cust_id,從而可以用作主鍵值。

       `order_id` int(11) NOT NULL AUTO_INCREMENT,
      

      每個表只允許一個AUTO_INCREMENT列,而且它必須被索引(如,通過使它成為主鍵)。

      覆蓋AUTO_INCREMENT :

      如果一個列被指定為AUTO_INCREMENT,則它需要使用特殊的值嗎?你可以簡單地在INSERT語句中指定一個值,只要它是唯一的(至今尚未使用過)即可,該值將被用來替代自動生成的值。后續(xù)的增量將開始使用該手工插入的值。

      確定AUTO_INCREMENT值 :

      讓MySQL生成(通過自動增量)主鍵的一個缺點是你不知道這些值都是誰。

      考慮這個場景:你正在增加一個新訂單。這要求在orders表中創(chuàng)建一行, 然后在orderitms表中對訂購的每項物品創(chuàng)建一行。 order_num在orderitems表中與訂單細節(jié)一起存儲。這就是為什么orders表和orderitems表為相互關聯(lián)的表的原因。這顯然要求你在插入orders行之后,插入orderitems行之前知道生成的order_num。

      那么,如何在使用AUTO_INCREMENT列時獲得這個值呢?可使用last_insert_id()函數(shù)獲得這個值,如下所示:

      select last_insert_id()

      此語句返回最后一個AUTO_INCREMENT值,然后可以將它用于后續(xù)的MySQL語句。

      指定默認值

      如果在插入行時沒有給出值, MySQL允許指定此時使用的默認值。默認值用CREATE TABLE語句的列定義中的DEFAULT關鍵字指定。

      CREATE TABLE `orderitems` (
        `order_num` int(11) NOT NULL,
        `order_item` int(11) NOT NULL,
        `prod_id` char(10) NOT NULL,
        `quantity` int(11) NOT NULL DEFAULT 1,
        `item_price` decimal(8,2) NOT NULL,
        PRIMARY KEY (`order_num`,`order_item`),
      ) ENGINE=InnoDB 
      

      這條語句創(chuàng)建包含組成訂單的各物品的orderitems表(訂單本身存儲在orders表中)。

      quantity列包含訂單中每項物品的數(shù)量。在此例子中,給該列的描述添加文本DEFAULT 1指示MySQL,在未給出數(shù)量的情況下使用數(shù)量1。

      不允許函數(shù)與大多數(shù)DBMS不一樣, MySQL不允許使用函數(shù)作為默認值,它只支持常量。

      引擎類型

      迄今為止使用的CREATE TABLE語句全都以ENGINE=InnoDB語句結束。

      與其他DBMS一樣, MySQL有一個具體管理和處理數(shù)據(jù)的內部引擎。

      在你使用CREATE TABLE語句時,該引擎具體創(chuàng)建表,而在你使用SELECT語句或進行其他數(shù)據(jù)庫處理時,該引擎在內部處理你的請求。

      多數(shù)時候,此引擎都隱藏在DBMS內,不需要過多關注它。

      但MySQL與其他DBMS不一樣,它具有多種引擎它打包多個引擎,這些引擎都隱藏在MySQL服務器內,全都能執(zhí)行CREATE TABLE和SELECT等命令。

      當然,你完全可以忽略這些數(shù)據(jù)庫引擎。如果省略ENGINE=語句,則使用默認引擎(很可能是MyISAM),多數(shù)SQL語句都會默認使用它。

      但并不是所有語句都默認使用它,這就是為什么ENGINE=語句很重要的原因。

      以下是幾個需要知道的引擎:

      • InnoDB是一個可靠的事務處理引擎(參見:管理事務處理),它不支持全文本搜索
      • MEMORY在功能等同于MyISAM, 但由于數(shù)據(jù)存儲在內存(不是磁盤)中,速度很快(特別適合于臨時表);
      • MyISAM是一個性能極高的引擎,它支持全文本搜索(參見:全文本檢索),但不支持事務處理

      外鍵不能跨引擎混用引擎類型有一個大缺陷外鍵(用于強制實施引用完整性)不能跨引擎,即使用一個引擎的表不能引用具有使用不同引擎的表的外鍵。

      那么, 你應該使用哪個引擎?這有賴于你需要什么樣的特性。 MyISAM由于其性能和特性可能是最受歡迎的引擎。但如果你不需要可靠的事務處理,可以使用其他引擎。

      更新表

      為更新表定義,可使用ALTER TABLE語句。

      但是,理想狀態(tài)下,當表中存儲數(shù)據(jù)以后,該表就不應該再被更新。在表的設計過程中需要花費大量時間來考慮,以便后期不對該表進行大的改動。

      為了使用ALTER TABLE更改表結構,必須給出下面的信息:

      • 在ALTER TABLE之后給出要更改的表名(該表必須存在,否則將出錯)
      • 所做更改的列表

      這條語句給vendors表增加一個名為vend_phone的列,必須明確其數(shù)據(jù)類型。

      ALTER TABLE vendors 
      ADD vend_phone CHAR(20)
      

      刪除該列:

      ALTER TABLE vendors 
      DROP COLUMN vend_phone
      

      ALTER TABLE的一種常見用途是定義外鍵。

      ALTER TABLE orders 
      ADD CONSTRAINT fk_order_customer FOREIGN KYE ( cust_id ) 
      REFERENCES customers (cust_id)
      

      復雜的表結構更改一般需要手動刪除過程,它涉及以下步驟:

      • 用新的列布局創(chuàng)建一個新表;
      • 使用INSERT SELECT語句(關于這條語句的詳細介紹,請參見:插入數(shù)據(jù))從舊表復制數(shù)據(jù)到新表。如果有必要,可使用轉換函數(shù)和計算字段;
      • 檢驗包含所需數(shù)據(jù)的新表;
      • 重命名舊表(如果確定,可以刪除它);
      • 用舊表原來的名字重命名新表;
      • 根據(jù)需要,重新創(chuàng)建觸發(fā)器、存儲過程、索引和外鍵。

      小心使用ALTER TABLE : 使用ALTER TABLE要極為小心,應該在進行改動前做一個完整的備份(模式和數(shù)據(jù)的備份)。數(shù)據(jù)
      庫表的更改不能撤銷,如果增加了不需要的列,可能不能刪除它們。類似地,如果刪除了不應該刪除的列,可能會丟失該列中的所有數(shù)據(jù)。

      刪除表

      刪除表(刪除整個表而不是其內容)非常簡單,使用DROP TABLE語句即可:

      DROP TABLE customers2
      

      這條語句刪除customers 2表(假設它存在)。刪除表沒有確認,也不能撤銷,執(zhí)行這條語句將永久刪除該表。

      重命名表

      使用RENAME TABLE語句可以重命名一個表:

      RENAME TABLE customers2 TO customers 
      

      RENAME TABLE所做的僅是重命名一個表。

      使用視圖

      視圖

      視圖是虛擬的表。與包含數(shù)據(jù)的表不一樣,視圖只包含使用時動態(tài)檢索數(shù)據(jù)的查詢

      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 = 'TNT2'
      

      此查詢用來檢索訂購了某個特定產(chǎn)品的客戶。

      任何需要這個數(shù)據(jù)的人都必須理解相關表的結構,并且知道如何創(chuàng)建查詢和對表進行聯(lián)結。為了檢索其他產(chǎn)品(或多個產(chǎn)品)的相同數(shù)據(jù),必須修改最后的WHERE子句

      現(xiàn)在,假如可以把整個查詢包裝成一個名為productcustomers的虛擬表,則可以如下輕松地檢索出相同的數(shù)據(jù)

      SELECT
      	cust_name,
      	cust_contact 
      FROM
      	productcustomers 
      WHERE
      	prod_id = 'TNT2'
      

      這就是視圖的作用。 productcustomers是一個視圖,作為視圖,它不包含表中應該有的任何列或數(shù)據(jù),它包含的是一個SQL查詢(與上面用以正確聯(lián)結表的相同的查詢)

      為什么使用視圖

      我們已經(jīng)看到了視圖應用的一個例子。下面是視圖的一些常見應用。

      • 重用SQL語句。
      • 簡化復雜的SQL操作。在編寫查詢后,可以方便地重用它而不必知道它的基本查詢細節(jié)。
      • 使用表的組成部分而不是整個表。
      • 保護數(shù)據(jù)。可以給用戶授予表的特定部分的訪問權限而不是整個表的訪問權限。
      • 更改數(shù)據(jù)格式和表示。視圖可返回與底層表的表示和格式不同的數(shù)據(jù)。

      在視圖創(chuàng)建之后,可以用與表基本相同的方式利用它們。可以對視圖執(zhí)行SELECT操作,過濾和排序數(shù)據(jù),將視圖聯(lián)結到其他視圖或表,甚至能添加和更新數(shù)據(jù)。

      重要的是知道視圖僅僅是用來查看存儲在別處的數(shù)據(jù)的一種設施

      視圖本身不包含數(shù)據(jù),因此它們返回的數(shù)據(jù)是從其他表中檢索出來的

      在添加或更改這些表中的數(shù)據(jù)時,視圖將返回改變過的數(shù)據(jù)。

      性能問題 :因為視圖不包含數(shù)據(jù),所以每次使用視圖時,都必須處理查詢執(zhí)行時所需的任一個檢索。如果你用多個聯(lián)結和過濾創(chuàng)建了復雜的視圖或者嵌套了視圖,可能會發(fā)現(xiàn)性能下降得很厲害。因此,在部署使用了大量視圖的應用前,應該進行測試。

      視圖的規(guī)則和限制

      下面是關于視圖創(chuàng)建和使用的一些最常見的規(guī)則和限制

      • 與表一樣,視圖必須唯一命名(不能給視圖取與別的視圖或表相同的名字)。
      • 對于可以創(chuàng)建的視圖數(shù)目沒有限制。
      • 為了創(chuàng)建視圖,必須具有足夠的訪問權限。這些限制通常由數(shù)據(jù)庫管理人員授予。
      • 視圖可以嵌套,即可以利用從其他視圖中檢索數(shù)據(jù)的查詢來構造一個視圖。
      • ORDER BY可以用在視圖中,但如果從該視圖檢索數(shù)據(jù)SELECT中也含有ORDER BY,那么該視圖中的ORDER BY將被覆蓋。
      • 視圖不能索引,也不能有關聯(lián)的觸發(fā)器或默認值。
      • 視圖可以和表一起使用。例如,編寫一條聯(lián)結表和視圖的SELECT語句。

      使用視圖

      在理解什么是視圖(以及管理它們的規(guī)則及約束)后,我們來看一下視圖的創(chuàng)建。

      • 視圖用CREATE VIEW語句來創(chuàng)建
      • 使用SHOW CREATE VIEW viewname;來查看創(chuàng)建視圖的語句
      • 用DROP刪除視圖,其語法為DROP VIEW viewname;。
      • 更新視圖時,可以先用DROP再用CREATE,也可以直接用CREATE ORREPLACE VIEW。如果要更新的視圖不存在,則第2條更新語句會創(chuàng)建一個視圖;如果要更新的視圖存在,則第2條更新語句會替換原有視圖。

      利用視圖簡化復雜的聯(lián)結

      視圖的最常見的應用之一是隱藏復雜的SQL,這通常都會涉及聯(lián)結

      CREATE VIEW productcustomers AS
      SELECT
      	cust_name,
      	cust_contact,
      	prod_id
      FROM
      	customers AS c,
      	orders AS o,
      	orderitems AS oi
      WHERE
      	c.cust_id = o.cust_id
      	AND oi.order_num = o.order_num
      

      這條語句創(chuàng)建一個名為productcustomers的視圖, 它聯(lián)結三個表,以返回已訂購了任意產(chǎn)品的所有客戶的列表。如果執(zhí)行SELECT * FROM productcustomers,將列出訂購了任意產(chǎn)品的客戶。

      創(chuàng)建可重用的視圖 創(chuàng)建不受特定數(shù)據(jù)限制的視圖是一種好辦法。

      用視圖重新格式化檢索出的數(shù)據(jù)

      視圖的另一常見用途是重新格式化檢索出的數(shù)據(jù)。

      SELECT
      	CONCAT( vend_name, '(', vend_country, ')' ) AS vend_titel 
      FROM
      	vendors 
      ORDER BY
      	vend_name
      

      現(xiàn)在,假如經(jīng)常需要這個格式的結果。不必在每次需要時執(zhí)行聯(lián)結,創(chuàng)建一個視圖,每次需要時使用它即可。

      CREATE VIEW vendorlocations AS SELECT
      CONCAT( vend_name, '(', vend_country, ')' ) AS vend_titel 
      FROM
      	vendors 
      ORDER BY
      	vend_name
      

      用視圖過濾不想要的數(shù)據(jù)

      視圖對于應用普通的WHERE子句也很有用 。

      WHERE子句與WHERE子句 :如果從視圖檢索數(shù)據(jù)時使用了一條WHERE子句,則兩組子句(一組在視圖中,另一組是傳遞給視圖的)將自動組合。

      使用視圖與計算字段

      視圖對于簡化計算字段的使用特別有用。

      更新視圖

      迄今為止的所有視圖都是和SELECT語句使用的。然而,視圖的數(shù)據(jù)能否更新?答案視情況而定

      通常,視圖是可更新的(即,可以對它們使用INSERT、 UPDATE和DELETE)。更新一個視圖將更新其基表(可以回憶一下,視圖本身沒有數(shù)據(jù))。如果你對視圖增加或刪除行,實際上是對其基表增加或刪除行

      但是,并非所有視圖都是可更新的。基本上可以說,如果MySQL不能正確地確定被更新的基數(shù)據(jù),則不允許更新(包括插入和刪除)。這實際上意味著,如果視圖定義中有以下操作,則不能進行視圖的更新

      • 分組(使用GROUP BY和HAVING);
      • 聯(lián)結;
      • 子查詢;
      • 并;
      • 聚集函數(shù)( Min()、 Count()、 Sum()等);
      • DISTINCT;
      • 導出(計算)列。

      將視圖用于檢索:一般,應該將視圖用于檢索( SELECT語句)而不用于更新( INSERT、 UPDATE和DELETE)

      使用存儲過程

      存儲過程

      使用的大多數(shù)SQL語句都是針對一個或多個表的單條語句。

      并非所有操作都這么簡單,經(jīng)常會有一個完整的操作需要多條語句才能完成

      例如:

      • 為了處理訂單,需要核對以保證庫存中有相應的物品。
      • 如果庫存有物品,這些物品需要預定以便不將它們再賣給別的人,并且要減少可用的物品數(shù)量以反映正確的庫存量。
      • 庫存中沒有的物品需要訂購,這需要與供應商進行某種交互。
      • 關于哪些物品入庫(并且可以立即發(fā)貨)和哪些物品退訂,需要通知相應的客戶。

      執(zhí)行這個處理需要針對許多表的多條MySQL語句。此外,需要執(zhí)行的具體語句及其次序也不是固定的,它們可能會(和將)根據(jù)哪些物品在庫存中哪些不在而變化。

      那么,怎樣編寫此代碼?可以單獨編寫每條語句,并根據(jù)結果有條件地執(zhí)行另外的語句。

      在每次需要這個處理時(以及每個需要它的應用中)都必須做這些工作。

      另一種方式:可以創(chuàng)建存儲過程。存儲過程簡單來說,就是為以后的使用而保存的一條或多條MySQL語句的集合

      可將其視為批文件,雖然它們的作用不僅限于批處理

      為什么要使用存儲過程

      下面列出一些主要的理由:

      • 通過把處理封裝在容易使用的單元中,簡化復雜的操作(正如前面例子所述)。
      • 由于不要求反復建立一系列處理步驟,這保證了數(shù)據(jù)的完整性。如果所有開發(fā)人員和應用程序都使用同一(試驗和測試)存儲過程,則所使用的代碼都是相同的。這一點的延伸就是防止錯誤。需要執(zhí)行的步驟越多,出錯的可能性就越大。防止錯誤保證了數(shù)據(jù)的一致性。
      • 簡化對變動的管理。如果表名、列名或業(yè)務邏輯(或別的內容)有變化,只需要更改存儲過程的代碼。使用它的人員甚至不需要知道這些變化。

      換句話說,使用存儲過程有3個主要的好處,即簡單、安全、高性能。顯然,它們都很重要。不過,在將SQL代碼轉換為存儲過程前,也必須知道它的一些缺陷。

      • 一般來說,存儲過程的編寫比基本SQL語句復雜,編寫存儲過程需要更高的技能,更豐富的經(jīng)驗。
      • 你可能沒有創(chuàng)建存儲過程的安全訪問權限。許多數(shù)據(jù)庫管理員限制存儲過程的創(chuàng)建權限,允許用戶使用存儲過程,但不允許他們創(chuàng)建存儲過程。

      使用存儲過程

      執(zhí)行存儲過程

      MySQL稱存儲過程的執(zhí)行為調用因此MySQL執(zhí)行存儲過程的語句為CALL。 CALL接受存儲過程的名字以及需要傳遞給它的任意參數(shù)。

      CALL productpricing (
      	@pricelow,
      	@pricehigh,
      	@priceeaverage 
      )
      

      存儲過程可以顯示結果,也可以不顯示結果

      創(chuàng)建存儲過程

      例子:一個返回產(chǎn)品平均價格的存儲過程。

      CREATE PROCEDURE `productpricing`( )
      BEGIN
        	SELECT AVG(prod_price) AS priceaverage
      	FROM products;
      END
      

      存儲過程名為productpricing,用CREATE PROCEDURE productpricing()語句定義

      如果存儲過程接受參數(shù),它們將在()中列舉出來此存儲過程沒有參數(shù),但后跟的()仍然需要

      BEGIN和END語句用來限定存儲過程體,過程體本身僅是一個簡單的SELECT語句(使用第12章介紹的Avg()函數(shù))。

      使用這個存儲過程如下:

      CALL productpricing ()
      

      ALL productpricing();執(zhí)行剛創(chuàng)建的存儲過程并顯示返回的結果

      因為存儲過程實際上是一種函數(shù),所以存儲過程名后需要有()符號(即使不傳遞參數(shù)也需要)。

      刪除存儲過程

      為刪除剛創(chuàng)建的存儲過程,可使用以下語句:

      DROP PROCEDURE productpricing
      

      僅當存在時刪除如果指定的過程不存在,則DROP PROCEDURE將產(chǎn)生一個錯誤

      當過程存在想刪除它時(如果過程不存在也不產(chǎn)生錯誤)可使用DROP PROCEDURE IF EXISTS

      使用參數(shù)

      一般,存儲過程并不顯示結果而是把結果返回給你指定的變量

      CREATE DEFINER=`root`@`localhost` PROCEDURE `productpricing`( 
      OUT pl DECIMAL(8,2),
      OUT ph DECIMAL(8,2),
      OUT pa DECIMAL(8,2)
      )
      BEGIN
        SELECT Min(prod_price)
      	INTO pl
      	FROM products;
      	SELECT Max(prod_price)
      	INTO ph
      	FROM products;
      	SELECT AVG(prod_price)
      	INTO pa
      	FROM products;
      END
      

      存儲過程接受3個參數(shù): pl存儲產(chǎn)品最低價格, ph存儲產(chǎn)品最高價格, pa存儲產(chǎn)品平均價格。

      每個參數(shù)必須具有指定的類型,這里使用十進制值。

      關鍵字OUT指出相應的參數(shù)用來從存儲過程傳出一個值(返回給調用者)MySQL支持IN(傳遞給存儲過程)、 OUT(從存儲過程傳出,如這里所用)和INOUT(對存儲過程傳入和傳出)類型的參數(shù)

      存儲過程的代碼位于BEGIN和END語句內,如前所見,它們是一系列SELECT語句,用來檢索值,然后保存到相應的變量(通過指定INTO關鍵字)。

      為調用此修改過的存儲過程,必須指定3個變量名,如下所示:

      CALL productpricing (
      	@pricelow,
      	@pricehigh,
      	@priceeaverage 
      )
      

      由于此存儲過程要求3個參數(shù),因此必須正好傳遞3個參數(shù),不多也不少。所以,這條CALL語句給出3個參數(shù)。它們是存儲過程將保存結果的3個變量的名字。

      變量名所有MySQL變量都必須以@開始

      在調用時,這條語句并不顯示任何數(shù)據(jù)。它返回以后可以顯示(或在其他處理中使用)的變量

      建立智能存儲過程

      迄今為止使用的所有存儲過程基本上都是封裝MySQL簡單的SELECT語句。雖然它們全都是有效的存儲過程例子,但它們所能完成的工作你直接用這些被封裝的語句就能完成。

      只有在存儲過程內包含業(yè)務規(guī)則和智能處理時,它們的威力才真正顯現(xiàn)出來。

      考慮這個場景。你需要獲得與以前一樣的訂單合計,但需要對合計增加營業(yè)稅,不過只針對某些顧客(或許是你所在州中那些顧客)。那么,你需要做下面幾件事情:

      • 獲得合計(與以前一樣);
      • 把營業(yè)稅有條件地添加到合計;
      • 返回合計(帶或不帶稅)。

      存儲過程的完整工作如下:

      CREATE DEFINER=`root`@`localhost` PROCEDURE `ordertotal`( 
      IN onumber INT,
      IN taxable BOOLEAN,
      OUT ototal DECIMAL(8,2)
      )
          COMMENT 'obtain order total ,optionaly adding tax'
      BEGIN
      
      	DECLARE total DECIMAL(8,2);
      	DECLARE taxrate INT DEFAULT 6;
      	
        SELECT SUM(item_price*quantity)
      	FROM orderitems
      	WHERE order_num = onumber
      	INTO total;
      	
      	IF taxable THEN
      		SELECT total+(total/100*taxrate) INTO total;
      	END IF;
      		SELECT total INTO ototal;
      END
      

      此存儲過程有很大的變動。首先,增加了注釋(前面放置--)。

      在存儲過程復雜性增加時,這樣做特別重要。添加了另外一個參數(shù)taxable,它是一個布爾值(如果要增加稅則為真,否則為假)。

      在存儲過程體中,用DECLARE語句定義了兩個局部變量DECLARE要求指定變量名和數(shù)據(jù)類型,它也支持可選的默認值(這個例子中的taxrate的默認被設置為6%)。 SELECT語句已經(jīng)改變,因此其結果存儲到total(局部變量)而不是ototal。 IF語句檢查taxable是否為真,如果為真,則用另一SELECT語句增加營業(yè)稅到局部變量total。最后,用另一SELECT語句將total(它增加或許不增加營業(yè)稅)保存到ototal。

      COMMENT關鍵字: 本例子中的存儲過程在CREATE PROCEDURE語句中包含了一個COMMENT值。它不是必需的,但如果給出,將在SHOW PROCEDURE STATUS的結果中顯示。

      IF語句 :這個例子給出了MySQL的IF語句的基本用法。 IF語句還支持ELSEIF和ELSE子句(前者還使用THEN子句,后者不
      使用)

      檢查存儲過程

      為顯示用來創(chuàng)建一個存儲過程的CREATE語句,使用SHOW CREATEPROCEDURE語句:

      SHOW CREATE PROCEDURE ordertotal
      

      為了獲得包括何時、由誰創(chuàng)建等詳細信息的存儲過程列表, 使用SHOW PROCEDURE STATUS。

      限制過程狀態(tài)結果 : SHOW PROCEDURE STATUS列出所有存儲過程。為限制其輸出,可使用LIKE指定一個過濾模式,例如:

      SHOW PROCEDURE STATUS LIKE 'ordertotal';

      使用游標

      游標

      由前幾章可知, MySQL檢索操作返回一組稱為結果集的行。這組返回的行都是與SQL語句相匹配的行(零行或多行)。使用簡單的SELECT語句,例如,沒有辦法得到第一行、下一行或前10行,也不存在每次一行地處理所有行的簡單方法(相對于成批地處理它們)。

      有時,需要在檢索出來的行中前進或后退一行或多行。這就是使用游標的原因。

      游標( cursor) 是一個存儲在MySQL服務器上的數(shù)據(jù)庫查詢,它不是一條SELECT語句,而是被該語句檢索出來的結果集

      在存儲了游標之后,應用程序可以根據(jù)需要滾動或瀏覽其中的數(shù)據(jù)。

      游標主要用于交互式應用,其中用戶需要滾動屏幕上的數(shù)據(jù),并對數(shù)據(jù)進行瀏覽或做出更改。

      只能用于存儲過程:不像多數(shù)DBMS, MySQL游標只能用于存儲過程(和函數(shù))

      使用游標

      使用游標涉及幾個明確的步驟:

      • 在能夠使用游標前,必須聲明(定義)它。這個過程實際上沒有檢索數(shù)據(jù),它只是定義要使用的SELECT語句。
      • 一旦聲明后,必須打開游標以供使用。這個過程用前面定義的SELECT語句把數(shù)據(jù)實際檢索出來。
      • 對于填有數(shù)據(jù)的游標,根據(jù)需要取出(檢索)各行
      • 在結束游標使用時,必須關閉游標

      在聲明游標后,可根據(jù)需要頻繁地打開和關閉游標。在游標打開后,可根據(jù)需要頻繁地執(zhí)行取操作。

      創(chuàng)建游標

      游標用DECLARE語句創(chuàng)建。 DECLARE命名游標,并定義相應的SELECT語句,根據(jù)需要帶WHERE和其他子句。

      例如,下面的語句定義了名為ordernumbers的游標, 使用了可以檢索所有訂單的SELECT語句。

      CREATE PROCEDURE `productpricing`( )
      BEGIN
        DECLARE ordernumber CURSOR
        FOR
      	SELECT order_num FROM orders;
      END;
      

      這個存儲過程并沒有做很多事情, DECLARE語句用來定義和命名游標,這里為ordernumbers。 存儲過程處理完成后,游標就消失(因為它局限于存儲過程)。

      在定義游標之后,可以打開它。

      打開和關閉游標

      游標用OPEN CURSOR語句來打開

      OPEN ordernumbers
      

      在處理OPEN語句時執(zhí)行查詢,存儲檢索出的數(shù)據(jù)以供瀏覽和滾動

      游標處理完成后,應當使用如下語句關閉游標:

      CLOSE  ordernumbers
      

      CLOSE釋放游標使用的所有內部內存和資源,因此在每個游標不再需要時都應該關閉。

      在一個游標關閉后,如果沒有重新打開,則不能使用它。但是,使用聲明過的游標不需要再次聲明,用OPEN語句打開它就可以了。

      隱含關閉:如果你不明確關閉游標, MySQL將會在到達END語句時自動關閉它。

      下面是前面例子的修改版本:

      CREATE PROCEDURE `processorder`( )
      BEGIN
        DECLARE ordernumbers CURSOR
        FOR
        SELECT order_num FROM orders;
        
        OPEN ordernumber
        
        CLOSE ordernumbers
      END;
      

      這個存儲過程聲明、打開和關閉一個游標。但對檢索出的數(shù)據(jù)什么也沒做。

      使用游標數(shù)據(jù)

      在一個游標被打開后,可以使用FETCH語句分別訪問它的每一行。FETCH指定檢索什么數(shù)據(jù)(所需的列),檢索出來的數(shù)據(jù)存儲在什么地方。它還向前移動游標中的內部行指針,使下一條FETCH語句檢索下一行(不重復讀取同一行)。

      第一個例子從游標中檢索單個行(第一行):

      CREATE PROCEDURE `processorder`( )
      BEGIN
        
        DELETE o INT
      
        DECLARE ordernumbers CURSOR
        FOR
        SELECT order_num FROM orders;
        
        OPEN ordernumber
        
        FETCH ordernumber INTO o
        
        CLOSE ordernumbers
      END;
      

      其中FETCH用來檢索當前行的order_num列(將自動從第一行開始)到一個名為o的局部聲明的變量中。對檢索出的數(shù)據(jù)不做任何處理。

      在下一個例子中,循環(huán)檢索數(shù)據(jù),從第一行到最后一行:

      CREATE PROCEDURE `processorder` ( ) BEGIN
      	
      	DECLARE done BOOLEAN DEFAULT 0
        DECLARE o INT 
        
        DECLARE ordernumbers CURSOR 
        FOR 
        SELECT order_num  FROM orders;
        
        DECLARE CONTINUE HANDLER FOR SQLSTATE "02000"  SET done = 1;
        OPEN ordernumber
        REPEAT
            FETCH ordernumber INTO o;
          	UNTIL done  END REPEAT;
      	 CLOSE ordernumbers; 
      END;
      

      這個例子使用FETCH檢索當前order_num到聲明的名為o的變量中。

      但與前一個例子不一樣的是,這個例子中的FETCH是在REPEAT內,因此它反復執(zhí)行直到done為真(由UNTIL done END REPEAT;規(guī)定)。為使它起作用,用一個DEFAULT 0(假,不結束)定義變量done。那么, done怎樣才能在結束時被設置為真呢?答案是用以下語句

       DECLARE CONTAINS HANDLER FOR SQLSTATE "02000" SET done =1
      

      這條語句定義了一個CONTINUE HANDLER,它是在條件出現(xiàn)時被執(zhí)行的代碼。

      這里, 它指出當SQLSTATE '02000'出現(xiàn)時, SET done=1。 SQLSTATE '02000'是一個未找到條件, 當REPEAT由于沒有更多的行供循環(huán)而不能繼續(xù)時,出現(xiàn)這個條件。

      DECLARE語句的次序 : DECLARE語句的發(fā)布存在特定的次序。用DECLARE語句定義的局部變量必須在定義任意游標或句柄
      之前定義,而句柄必須在游標之后定義。不遵守此順序將產(chǎn)生錯誤消息。

      下面是游標存儲過程樣例:

      CREATE PROCEDURE `processorder` ( ) BEGIN
      	
      	DECLARE done BOOLEAN DEFAULT 0
        DECLARE o INT
      	DECLARE t DECIMAL(8,2) 
        
        DECLARE ordernumbers CURSOR 
        FOR 
        SELECT order_num  FROM orders;
        
        DECLARE CONTINUE HANDLER FOR SQLSTATE "02000"  SET done = 1;
      	
      	CREATE TABLE IF NOT EXISTS ordertotals(order_num INT, total DECIMAL(8,2));
      	
        OPEN ordernumber
      	
        REPEAT
            FETCH ordernumber INTO o;
      			
      			CALL ordertotal(o, 1 ,t);
      			
      			INSERT INTO ordertotals(order_num,total) VALUES (o, t);
      			
          	UNTIL done  END REPEAT;
      	 CLOSE ordernumbers; 
      END;
      

      在這個例子中,我們增加了另一個名為t的變量(存儲每個訂單的合計)。 此存儲過程還在運行中創(chuàng)建了一個新表(如果它不存在的話), 名為ordertotals。 這個表將保存存儲過程生成的結果FETCH像以前一樣取每個order_num,然后用CALL執(zhí)行另一個存儲過程(我們在前一章中創(chuàng)建)來計算每個訂單的帶稅的合計(結果存儲到t)。最后,用INSERT保存每個訂單的訂單號和合計。

      使用觸發(fā)器

      觸發(fā)器

      MySQL語句在需要時被執(zhí)行,存儲過程也是如此。但是,如果你想要某條語句(或某些語句)在事件發(fā)生時自動執(zhí)行,怎么辦呢?例如:

      • 每當增加一個顧客到某個數(shù)據(jù)庫表時,都檢查其電話號碼格式是否正確,州的縮寫是否為大寫;
      • 每當訂購一個產(chǎn)品時,都從庫存數(shù)量中減去訂購的數(shù)量;
      • 無論何時刪除一行,都在某個存檔表中保留一個副本。

      所有這些例子的共同之處是它們都需要在某個表發(fā)生更改時自動處理。這確切地說就是觸發(fā)器

      觸發(fā)器是MySQL響應以下任意語句而自動執(zhí)行的一條MySQL語句(或位于BEGIN和END語句之間的一組語句)

      • DELETE;
      • INSERT;
      • UPDATE

      其他MySQL語句不支持觸發(fā)器。

      創(chuàng)建觸發(fā)器

      在創(chuàng)建觸發(fā)器時,需要給出4條信息:

      • 唯一的觸發(fā)器名;
      • 觸發(fā)器關聯(lián)的表;
      • 觸發(fā)器應該響應的活動( DELETE、 INSERT或UPDATE);
      • 觸發(fā)器何時執(zhí)行(處理之前或之后)。

      保持每個數(shù)據(jù)庫的觸發(fā)器名唯一 :在MySQL 5中,觸發(fā)器名必須在每個表中唯一,但不是在每個數(shù)據(jù)庫中唯一。這表示同一
      數(shù)據(jù)庫中的兩個表可具有相同名字的觸發(fā)器。這在其他每個數(shù)據(jù)庫觸發(fā)器名必須唯一的DBMS中是不允許的,而且以后的
      MySQL版本很可能會使命名規(guī)則更為嚴格。因此,現(xiàn)在最好是在數(shù)據(jù)庫范圍內使用唯一的觸發(fā)器名。

      觸發(fā)器用CREATE TRIGGER語句創(chuàng)建。

      CREATE TRIGGER newproduct AFTER ON products FOR EACH ROW
      SELECT
      	'Product added'
      

      CREATE TRIGGER用來創(chuàng)建名為newproduct的新觸發(fā)器。觸發(fā)器可在一個操作發(fā)生之前或之后執(zhí)行,這里給出了AFTER INSERT,所以此觸發(fā)器將在INSERT語句成功執(zhí)行后執(zhí)行。這個觸發(fā)器還指定FOR EACH ROW,因此代碼對每個插入行執(zhí)行。在這個例子中,文本Product added將對每個插入的行顯示一次。

      僅支持表 :只有表才支持觸發(fā)器,視圖不支持(臨時表也不支持)

      觸發(fā)器按每個表每個事件每次地定義,每個表每個事件每次只允許一個觸發(fā)器。因此,每個表最多支持6個觸發(fā)器(每條INSERT、 UPDATE和DELETE的之前和之后)單一觸發(fā)器不能與多個事件或多個表關聯(lián),所以,如果你需要一個對INSERT和UPDATE操作執(zhí)行的觸發(fā)器,則應該定義兩個觸發(fā)器。

      觸發(fā)器失敗如果BEFORE觸發(fā)器失敗,則MySQL將不執(zhí)行請求的操作。此外,如果BEFORE觸發(fā)器或語句本身失敗, MySQL將不執(zhí)行AFTER觸發(fā)器(如果有的話)。

      刪除觸發(fā)器

      為了刪除一個觸發(fā)器,可使用DROP TRIGGER語句,如下所示:

      DROP TRIGGER newporduct;
      

      觸發(fā)器不能更新或覆蓋。為了修改一個觸發(fā)器,必須先刪除它,然后再重新創(chuàng)建

      使用觸發(fā)器

      INSERT觸發(fā)器

      INSERT觸發(fā)器在INSERT語句執(zhí)行之前或之后執(zhí)行。需要知道以下幾點:

      • 在INSERT觸發(fā)器代碼內,可引用一個名為NEW的虛擬表,訪問被插入的行
      • 在BEFORE INSERT觸發(fā)器中, NEW中的值也可以被更新(允許更改被插入的值)
      • 對于AUTO_INCREMENT列NEW在INSERT執(zhí)行之前包含0,在INSERT執(zhí)行之后包含新的自動生成值

      下面舉一個例子(一個實際有用的例子)。 AUTO_INCREMENT列具有MySQL自動賦予的值。

      CREATE TRIGGER neworder AFTER INSERT ON orders FOR EACH ROW
      SELECT
      	NEW.order_num;
      

      此代碼創(chuàng)建一個名為neworder的觸發(fā)器,它按照AFTER INSERTON orders執(zhí)行。在插入一個新訂單到orders表時, MySQL生
      成一個新訂單號并保存到order_num中。觸發(fā)器從NEW. order_num取得這個值并返回它。此觸發(fā)器必須按照AFTER INSERT執(zhí)行,因為在BEFOREINSERT語句執(zhí)行之前,新order_num還沒有生成。對于orders的每次插入使用這個觸發(fā)器將總是返回新的訂單號。

      BEFORE或AFTER?: 通常,將BEFORE用于數(shù)據(jù)驗證和凈化(目的是保證插入表中的數(shù)據(jù)確實是需要的數(shù)據(jù))。

      DELETE觸發(fā)器

      DELETE觸發(fā)器在DELETE語句執(zhí)行之前或之后執(zhí)行。需要知道以下兩點:

      • 在DELETE觸發(fā)器代碼內,你可以引用一個名為OLD的虛擬表,訪問被刪除的行;
      • OLD中的值全都是只讀的,不能更新。

      下面的例子演示使用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;
      

      在任意訂單被刪除前將執(zhí)行此觸發(fā)器。它使用一條INSERT語句將OLD中的值(要被刪除的訂單)保存到一個名為archive_orders的存檔表中(為實際使用這個例子,你需要用與orders相同的列創(chuàng)建一個名為archive_orders的表)。

      使用BEFORE DELETE觸發(fā)器的優(yōu)點(相對于AFTER DELETE觸發(fā)器來說)為,如果由于某種原因,訂單不能存檔, DELETE本身將被放棄。

      多語句觸發(fā)器 :正如所見,觸發(fā)器deleteorder使用BEGIN和END語句標記觸發(fā)器體。這在此例子中并不是必需的,不過也沒有害處。使用BEGIN END塊的好處是觸發(fā)器能容納多條SQL語句(在BEGIN END塊中一條挨著一條)。

      UPDATE觸發(fā)器

      UPDATE觸發(fā)器在UPDATE語句執(zhí)行之前或之后執(zhí)行。需要知道以下幾點:

      • 在UPDATE觸發(fā)器代碼中,你可以引用一個名為OLD的虛擬表訪問以前( UPDATE語句前)的值引用一個名為NEW的虛擬表訪問新更新的值;
      • 在BEFORE UPDATE觸發(fā)器中, NEW中的值可能也被更新(允許更改將要用于UPDATE語句中的值)
      • OLD中的值全都是只讀的,不能更新。

      下面的例子保證州名縮寫總是大寫(不管UPDATE語句中給出的是大寫還是小寫):

      CREATE TRIGGER updatevendor BEFORE UPDATE ON vendor FOR EACH ROW
      SET
      	NEW.vend_state = Upper(NEW.vend_state)
      

      每次更新一個行時, NEW.vend_state中的值(將用來更新表行的值)都用Upper(NEW.vend_state)替換。

      關于觸發(fā)器的進一步介紹

      我們再介紹一些使用觸發(fā)器時需要記住的重點:

      • 創(chuàng)建觸發(fā)器可能需要特殊的安全訪問權限,但是,觸發(fā)器的執(zhí)行是自動的。如果INSERT、 UPDATE或DELETE語句能夠執(zhí)行,則相關的觸發(fā)器也能執(zhí)行。
      • 應該用觸發(fā)器來保證數(shù)據(jù)的一致性(大小寫、格式等)。在觸發(fā)器中執(zhí)行這種類型的處理的優(yōu)點是它總是進行這種處理,而且是透明地進行,與客戶機應用無關。
      • 觸發(fā)器的一種非常有意義的使用是創(chuàng)建審計跟蹤。使用觸發(fā)器,把更改(如果需要,甚至還有之前和之后的狀態(tài))記錄到另一個表非常容易。
      • 遺憾的是, MySQL觸發(fā)器中不支持CALL語句。這表示不能從觸發(fā)器內調用存儲過程。所需的存儲過程代碼需要復制到觸發(fā)器內。

      管理事務處理

      事務處理

      并非所有引擎都支持事務處理:MySQL支持幾種基本的數(shù)據(jù)庫引擎。正如本章所述,并非所有引擎都支持明確的事務處理管理。 MyISAM和InnoDB是兩種最常使用的引擎。前者不支持明確的事務處理管理,而后者支持。

      如果你的應用中需要事務處理功能,則一定要使用正確的引擎類型。

      事務處理(transaction processing)可以用來維護數(shù)據(jù)庫的完整性,它保證成批的MySQL操作要么完全執(zhí)行,要么完全不執(zhí)行。

      前面章中使用的orders表就是一個很好的例子。訂單存儲在orders和orderitems兩個表中: orders存儲實際的訂單,而orderitems存儲訂購的各項物品。這兩個表使用稱為主鍵的唯一ID互相關聯(lián)。這兩個表又與包含客戶和產(chǎn)品信息的其他表相關聯(lián)。

      給系統(tǒng)添加訂單的過程如下。

      • 檢查數(shù)據(jù)庫中是否存在相應的客戶(從customers表查詢),如果不存在,添加他/她。
      • 檢索客戶的ID。
      • 添加一行到orders表,把它與客戶ID關聯(lián)。
      • 檢索orders表中賦予的新訂單ID。
      • 對于訂購的每個物品在orderitems表中添加一行,通過檢索出來的ID把它與orders表關聯(lián)(以及通過產(chǎn)品ID與products表關聯(lián))。

      現(xiàn)在,假如由于某種數(shù)據(jù)庫故障(如超出磁盤空間、安全限制、表鎖等)阻止了這個過程的完成。

      這里就需要使用事務處理了。事務處理是一種機制,用來管理必須成批執(zhí)行的MySQL操作,以保證數(shù)據(jù)庫不包含不完整的操作結果。

      利用事務處理,可以保證一組操作不會中途停止,它們或者作為整體執(zhí)行,或者完全不執(zhí)行(除非明確指示)

      如果沒有錯誤發(fā)生,整組語句提交給(寫到)數(shù)據(jù)庫表。如果發(fā)生錯誤,則進行回退(撤銷)以恢復數(shù)據(jù)庫到某個已知且安全的狀態(tài)。

      在使用事務和事務處理時,有幾個關鍵詞匯反復出現(xiàn)。下面是關于事務處理需要知道的幾個術語:

      • 事務(transaction)指一組SQL語句;
      • 回退(rollback)指撤銷指定SQL語句的過程;
      • 提交(commit)指將未存儲的SQL語句結果寫入數(shù)據(jù)庫表;
      • 保留點( savepoint)指事務處理中設置的臨時占位符( placeholder),你可以對它發(fā)布回退(與回退整個事務處理不同)。

      控制事務處理

      管理事務處理的關鍵在于將SQL語句組分解為邏輯塊并明確規(guī)定數(shù)據(jù)何時應該回退,何時不應該回退。

      MySQL使用下面的語句來標識事務的開始:

      START TRANSACTION
      

      使用ROLLBACK

      MySQL的ROLLBACK命令用來回退(撤銷) MySQL語句。

      SELECT * FROM ordertotals;
      START TRANSACTION;
      
      DELETE FROM ordertotals;
      SELECT * FROM ordertotals;
      ROLLBACK;
      
      SELECT * FROM ordertotals;
      

      這個例子從顯示ordertotals表的內容開始。首先執(zhí)行一條SELECT以顯示該表不為空。然后開始一個事務處理,用一條DELETE語句刪除ordertotals中的所有行。另一條SELECT語句驗證ordertotals確實為空。這時用一條ROLLBACK語句回退START TRANSACTION之后的所有語句,最后一條SELECT語句顯示該表不為空。

      顯然, ROLLBACK只能在一個事務處理內使用(在執(zhí)行一條STARTTRANSACTION命令之后)

      哪些語句可以回退? : 事務處理用來管理INSERT、 UPDATE和DELETE語句

      你不能回退SELECT語句。(這樣做也沒有什么意義。)

      你不能回退CREATE或DROP操作。事務處理塊中可以使用這兩條語句,但如果你執(zhí)行回退,它們不會被撤銷。

      使用COMMIT

      一般的MySQL語句都是直接針對數(shù)據(jù)庫表執(zhí)行和編寫的。這就是所謂的隱含提交( implicit commit)即提交(寫或保存)操作是自動進行的。

      但是,在事務處理塊中,提交不會隱含地進行為進行明確的提交,使用COMMIT語句,如下所示:

      START TRANSACTION;
      
      DELETE FROM orderitems WHERE order_num = 20010;
      DELETE FROM orders WHERE order_num = 20010;
      
      COMMIT;
      

      在這個例子中,從系統(tǒng)中完全刪除訂單20010。因為涉及更新兩個數(shù)據(jù)庫表orders和orderItems,所以使用事務處理塊來保證訂單不被部分刪除。最后的COMMIT語句僅在不出錯時寫出更改。

      如果第一條DELETE起作用,但第二條失敗,則DELETE不會提交(實際上,它是被自動撤銷的)。

      隱含事務關閉 : 當COMMIT或ROLLBACK語句執(zhí)行后,事務會自動關閉(將來的更改會隱含提交)

      使用保留點

      簡單的ROLLBACK和COMMIT語句就可以寫入或撤銷整個事務處理

      但是,只是對簡單的事務處理才能這樣做,更復雜的事務處理可能需要部分提交或回退。

      例如,前面描述的添加訂單的過程為一個事務處理。如果發(fā)生錯誤,只需要返回到添加orders行之前即可,不需要回退到customers表(如果存在的話)。

      為了支持回退部分事務處理必須能在事務處理塊中合適的位置放置占位符。這樣,如果需要回退,可以回退到某個占位符

      這些占位符稱為保留點。為了創(chuàng)建占位符,可如下使用SAVEPOINT語句:

      SAVEPOINT delete1
      

      每個保留點都取標識它的唯一名字,以便在回退時, MySQL知道要回退到何處。為了回退到本例給出的保留點,可如下進行:

      ROLLBACK TO delete1
      

      保留點越多越好可以在MySQL代碼中設置任意多的保留點,越多越好。為什么呢?因為保留點越多,你就越能按自己的意愿靈活地進行回退。

      釋放保留點 : 保留點在事務處理完成(執(zhí)行一條ROLLBACK或COMMIT)后自動釋放。自MySQL 5以來,也可以用RELEASE
      SAVEPOINT明確地釋放保留點。

      更改默認的提交行為

      正如所述,默認的MySQL行為是自動提交所有更改。換句話說,任何時候你執(zhí)行一條MySQL語句,該語句實際上都是針對表執(zhí)行的,而且所做的更改立即生效。

      更改默認行為可以使用一下命令:

      SET autocommit=0 
      

      autocommit標志決定是否自動提交更改,不管有沒有COMMIT語句。設置autocommit為0(假)指示MySQL不自動提交更改
      (直到autocommit被設置為真為止)。

      標志為連接專用 : autocommit標志是針對每個連接而不是服務器的

      全球化和本地化

      字符集和校對順序

      數(shù)據(jù)庫表被用來存儲和檢索數(shù)據(jù)

      不同的語言和字符集需要以不同的方式存儲和檢索。因此, MySQL需要適應不同的字符集(不同的字母和字符),適應不同的排序和檢索數(shù)據(jù)的方法。

      在討論多種語言和字符集時,將會遇到以下重要術語:

      • 字符集:為字母和符號的集合;
      • 編碼:為某個字符集成員的內部表示;
      • 校對:為規(guī)定字符如何比較的指令。

      校對為什么重要:排序英文正文很容易,對嗎?或許不。考慮詞APE、 apex和Apple。它們處于正確的排序順序嗎?這有賴于你是否想?yún)^(qū)分大小寫。使用區(qū)分大小寫的校對順序,這些詞有一種排序方式,使用不區(qū)分大小寫的校對順序有另外一種排序方式。這不僅影響排序(如用ORDER BY排序數(shù)據(jù)),還影響搜索(例如 ,尋找 apple 的 WHERE子 句 是 否能 找到APPLE)。在使用諸如法文à或德文?這樣的字符時,情況更復雜,在使用不基于拉丁文的字符集(日文、希伯來文、俄文等)時,情況更為復雜。

      在MySQL的正常數(shù)據(jù)庫活動(SELECT、 INSERT等)中,不需要操心太多的東西。使用何種字符集和校對的決定在服務器、數(shù)據(jù)庫和表級進行。

      使用字符集和校對順序

      MySQL支持眾多的字符集。為查看所支持的字符集完整列表,使用以下語句:

      SHOW CHARACTER SET ;
      

      這條語句顯示所有可用的字符集以及每個字符集的描述和默認校對。

      為了查看所支持校對的完整列表,使用以下語句:

      SHOW COLLATION
      

      此語句顯示所有可用的校對,以及它們適用的字符集。可以看到有的字符集具有不止一種校對。

      例如, latin1對不同的歐洲語言有幾種校對,而且許多校對出現(xiàn)兩次,一次區(qū)分大小寫(由_cs表示)一次不區(qū)分大小寫(由_ci表示)。

      通常系統(tǒng)管理在安裝時定義一個默認的字符集和校對。

      此外,也可以在創(chuàng)建數(shù)據(jù)庫時,指定默認的字符集和校對。為了確定所用的字符集和校對,可以使用以下語句:

      SHOW VARIABLES LIKE 'character%';
      SHOW VARIABLES LIKE 'collation%';
      

      實際上,字符集很少是服務器范圍(甚至數(shù)據(jù)庫范圍)的設置。

      不同的表,甚至不同的列可能需要不同的字符集,而且兩者都可以在創(chuàng)建表時指定。

      為了給表指定字符集和校對,可使用帶子句的CREATE TABLE

      CREATE TABLE `myTable` (
        `columnn1` INT
        `columnn2` VARCHAR(10)
      ) DEFAULT CHARACTER SET hebrew
      	COLLATE hebrew_general_ci;
      

      此語句創(chuàng)建一個包含兩列的表,并且指定一個字符集和一個校對順序。

      這個例子中指定了CHARACTER SET和COLLATE兩者。一般, MySQL如下確定使用什么樣的字符集和校對。

      • 如果指定CHARACTER SET和COLLATE兩者,則使用這些值。
      • 如果只指定CHARACTER SET,則使用此字符集及其默認的校對(如SHOW CHARACTER SET的結果中所示)。
      • 如果既不指定CHARACTER SET,也不指定COLLATE,則使用數(shù)據(jù)庫默認。

      除了能指定字符集和校對的表范圍外, MySQL還允許對每個列設置它們,如下所示:

      CREATE TABLE `myTable` (
        `columnn1` INT,
        `columnn2` VARCHAR(10),
      	`colum3` VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_general_ci
      ) DEFAULT CHARACTER SET hebrew
      	COLLATE hebrew_general_ci;
      

      這里對整個表以及一個特定的列指定了CHARACTER SET和COLLATE。

      如前所述,校對在對用ORDER BY子句檢索出來的數(shù)據(jù)排序時起重要的作用

      如果你需要用與創(chuàng)建表時不同的校對順序排序特定的SELECT語句,可以在SELECT語句自身中進行

      SELECT
      	* 
      FROM
      	customers 
      ORDER BY
      	lastname,
      	firstname COLLATE latin1_general_cs
      

      此SELECT使用COLLATE指定一個備用的校對順序(在這個例子中,為區(qū)分大小寫的校對)。這顯然將會影響到結果排序的次序。

      SELECT的其他COLLATE子句 :除了這里看到的在ORDER BY子句中使用以外, COLLATE還可以用于GROUP BY、 HAVING、聚集函數(shù)、別名等。

      安全管理

      訪問控制

      MySQL服務器的安全基礎是: 用戶應該對他們需要的數(shù)據(jù)具有適當?shù)脑L問權,既不能多也不能少。換句話說,用戶不能對過多的數(shù)據(jù)具有過多的訪問權。

      考慮以下內容:

      • 多數(shù)用戶只需要對表進行讀和寫,但少數(shù)用戶甚至需要能創(chuàng)建和刪除表;
      • 某些用戶需要讀表,但可能不需要更新表;
      • 你可能想允許用戶添加數(shù)據(jù),但不允許他們刪除數(shù)據(jù);
      • 某些用戶(管理員)可能需要處理用戶賬號的權限,但多數(shù)用戶不需要;
      • 你可能想讓用戶通過存儲過程訪問數(shù)據(jù),但不允許他們直接訪問數(shù)據(jù);
      • 你可能想根據(jù)用戶登錄的地點限制對某些功能的訪問。

      這些都只是例子,但有助于說明一個重要的事實,即你需要給用戶提供他們所需的訪問權,且僅提供他們所需的訪問權。這就是所謂的訪問控制,管理訪問控制需要創(chuàng)建和管理用戶賬號。

      管理用戶

      MySQL用戶賬號和信息存儲在名為mysql的MySQL數(shù)據(jù)庫中。一般不需要直接訪問mysql數(shù)據(jù)庫和表(你稍后會明白這一點),但有時需要直接訪問。需要直接訪問它的時機之一是在需要獲得所有用戶賬號列表時。為此,可使用以下代碼:

      USE mysql
      SELECT user FROM user;
      

      mysql數(shù)據(jù)庫有一個名為user的表, 它包含所有用戶賬號。 user表有一個名為user的列,它存儲用戶登錄名。

      創(chuàng)建用戶賬號

      為了創(chuàng)建一個新用戶賬號,使用CREATE USER語句,如下所示:

      CREATE USER ben IDENTIFIED BY "p@$$w0rd";
      

      CREATE USER創(chuàng)建一個新用戶賬號。在創(chuàng)建用戶賬號時不一定需要口令,不過這個例子用IDENTIFIED BY 'p@$$wOrd'給出了一個口令。

      指定散列口令 : IDENTIFIED BY指定的口令為純文本, MySQL將在保存到user表之前對其進行加密。為了作為散列值指定口令,使用IDENTIFIED BY PASSWORD。

      使用GRANT或INSERT : GRANT語句也可以創(chuàng)建用戶賬號,但一般來說CREATE USER是最清楚和最簡單的句子。此外, 也可以通過直接插入行到user表來增加用戶, 不過為安全起見,一般不建議這樣做。 MySQL用來存儲用戶賬號信息的表(以及表模式等)極為重要,對它們的任何毀壞都可能嚴重地傷害到MySQL服務器。因此,相對于直接處理來說,最好是用標記和函數(shù)來處理這些表。

      為重新命名一個用戶賬號,使用RENAME USER語句,如下所示:

      RENAME USER ben TO bforta;
      

      刪除用戶賬號

      為了刪除一個用戶賬號(以及相關的權限),使用DROP USER語句,如下所示:

      DROP USER bforta;
      

      設置訪問權限

      在創(chuàng)建用戶賬號后,必須接著分配訪問權限。新創(chuàng)建的用戶賬號沒有訪問權限。它們能登錄MySQL,但不能看到數(shù)據(jù),不能執(zhí)行任何數(shù)據(jù)庫操作。

      為看到賦予用戶賬號的權限,使用SHOW GRANTS FOR,如下所示:

      SHOW GRANTS FOR bforta ; 
      

      輸出結果顯示用戶bforta有一個權限USAGE ON *.*。 USAGE表示根本沒有權限(我知道,這不很直觀),所以,此結果表示在任意數(shù)據(jù)庫和任意表上對任何東西沒有權限。

      為設置權限,使用GRANT語句。 GRANT要求你至少給出以下信息:

      • 要授予的權限;
      • 被授予訪問權限的數(shù)據(jù)庫或表;
      • 用戶名
      GRANT SELECT ON crashcourse.* TO bforta
      

      此GRANT允許用戶在crashcourse.*( crashcourse數(shù)據(jù)庫的所有表)上使用SELECT。 通過只授予SELECT訪問權限,用戶bforta對crashcourse數(shù)據(jù)庫中的所有數(shù)據(jù)具有只讀訪問權限。

      GRANT的反操作為REVOKE,用它來撤銷特定的權限。下面舉一個例子:

      REVOKE SELECT ON crashcourse.* FROM bforta
      

      這條REVOKE語句取消剛賦予用戶bforta的SELECT訪問權限。 被撤銷的訪問權限必須存在,否則會出錯。

      GRANT和REVOKE可在幾個層次上控制訪問權限:

      • 整個服務器,使用GRANT ALL和REVOKE ALL;
      • 整個數(shù)據(jù)庫,使用ON database.*;
      • 特定的表,使用ON database.table;
      • 特定的列;
      • 特定的存儲過程。

      以下列出可以授予或撤銷的每個權限:

      權限 說明
      ALL 除GRANT OPTION外的所有權限
      ALTER 使用ALTER TABLE
      ALTER ROUTINE 使用ALTER PROCEDURE和DROP PROCEDURE
      CREATE 使用CREATE TABLE
      CREATE ROUTINE 使用CREATE PROCEDURE
      CREATE TEMPORARY TABLES 使用CREATE TEMPORARY TABLE
      CREATE USER 使用CREATE USER、 DROP USER、 RENAME USER和REVOKE ALL PRIVILEGES
      CREATE VIEW 使用CREATE VIEW
      DELETE 使用DELETE
      DROP 使用DROP TABLE
      EXECUTE 使用CALL和存儲過程
      FILE 使用SELECT INTO OUTFILE和LOAD DATA INFILE
      GRANT OPTION 使用GRANT和REVOKE
      INDEX 使用CREATE INDEX和DROP INDEX
      INSERT 使用INSERT
      LOCK TABLES 使用LOCK TABLES
      PROCESS 使用SHOW FULL PROCESSLIST
      RELOAD 使用FLUSH
      REPLICATION CLIENT 服務器位置的訪問
      REPLICATION SLAVE 由復制從屬使用
      SELECT 使用SELECT
      SHOW DATABASES 使用SHOW DATABASES
      SHOW VIEW 使用SHOW CREATE VIEW
      SHUTDOWN 使用mysqladmin shutdown(用來關閉MySQL)
      SUPER 使用CHANGE MASTER、 KILL、 LOGS、 PURGE、 MASTER和SET GLOBAL。還允許mysqladmin調試登錄
      UPDATE 使用UPDATE
      USAGE 無訪問權限

      更改口令

      為了更改用戶口令,可使用SET PASSWORD語句。新口令必須如下加密:

      SET PASSWORD FOR bforta = PASSWORD("xxxx")
      

      SET PASSWORD更新用戶口令。新口令必須傳遞到Password()函數(shù)進行加密。

      SET PASSWORD還可以用來設置你自己的口令:

      SET PASSWORD  = PASSWORD("xxxx")
      

      在不指定用戶名時, SET PASSWORD更新當前登錄用戶的口令。

      數(shù)據(jù)庫維護

      備份數(shù)據(jù)

      像所有數(shù)據(jù)一樣, MySQL的數(shù)據(jù)也必須經(jīng)常備份。由于MySQL數(shù)據(jù)庫是基于磁盤的文件,普通的備份系統(tǒng)和例程就能備份MySQL的數(shù)據(jù)。但是,由于這些文件總是處于打開和使用狀態(tài),普通的文件副本備份不一定總是有效。

      下面列出這個問題的可能解決方案。

      • 使用命令行實用程序mysqldump轉儲所有數(shù)據(jù)庫內容到某個外部文件。在進行常規(guī)備份前這個實用程序應該正常運行,以便能正確地備份轉儲文件。
      • 可用命令行實用程序mysqlhotcopy從一個數(shù)據(jù)庫復制所有數(shù)據(jù)(并非所有數(shù)據(jù)庫引擎都支持這個實用程序)。
      • 可以使用MySQL的BACKUP TABLE或SELECT INTO OUTFILE轉儲所有數(shù)據(jù)到某個外部文件。這兩條語句都接受將要創(chuàng)建的系統(tǒng)文件名,此系統(tǒng)文件必須不存在,否則會出錯。數(shù)據(jù)可以用RESTORETABLE來復原。

      首先刷新未寫數(shù)據(jù) : 為了保證所有數(shù)據(jù)被寫到磁盤(包括索引數(shù)據(jù)),可能需要在進行備份前使用FLUSH TABLES語句。

      進行數(shù)據(jù)庫維護

      MySQL提供了一系列的語句,可以(應該)用來保證數(shù)據(jù)庫正確和正常運行。

      以下是你應該知道的一些語句 :

      • ANALYZE TABLE,用來檢查表鍵是否正確。 ANALYZE TABLE返回如下所示的狀態(tài)信息:
      • CHECK TABLE用來針對許多問題對表進行檢查。 在MyISAM表上還對索引進行檢查。 CHECK TABLE支持一系列的用于MyISAM表的方式。CHANGED檢查自最后一次檢查以來改動過的表。 EXTENDED執(zhí)行最徹底的檢查, FAST只檢查未正常關閉的表, MEDIUM檢查所有被刪除的鏈接并進行鍵檢驗, QUICK只進行快速掃描。如下所示, CHECK TABLE發(fā)現(xiàn)和修復問題
      • 如果MyISAM表訪問產(chǎn)生不正確和不一致的結果,可能需要用REPAIR TABLE來修復相應的表。這條語句不應該經(jīng)常使用,如果需要經(jīng)常使用,可能會有更大的問題要解決。
      • 如果從一個表中刪除大量數(shù)據(jù),應該使用OPTIMIZE TABLE來收回所用的空間,從而優(yōu)化表的性能 。

      查看日志文件

      MySQL維護管理員依賴的一系列日志文件。主要的日志文件有以下幾種:

      • 錯誤日志。它包含啟動和關閉問題以及任意關鍵錯誤的細節(jié)。此日志通常名為hostname.err,位于data目錄中。此日志名可用--log-error命令行選項更改。
      • 查詢日志。它記錄所有MySQL活動,在診斷問題時非常有用。此日志文件可能會很快地變得非常大,因此不應該長期使用它。此日志通常名為hostname.log,位于data目錄中。此名字可以用--log命令行選項更改。
      • 二進制日志。它記錄更新過數(shù)據(jù)(或者可能更新過數(shù)據(jù))的所有語句。此日志通常名為hostname-bin,位于data目錄內。此名字可以用--log-bin命令行選項更改。注意, 這個日志文件是MySQL5中添加的,以前的MySQL版本中使用的是更新日志。
      • 緩慢查詢日志。顧名思義,此日志記錄執(zhí)行緩慢的任何查詢。這個日志在確定數(shù)據(jù)庫何處需要優(yōu)化很有用。此日志通常名為hostname-slow.log , 位 于 data 目 錄 中 。 此 名 字 可 以 用--log-slow-queries命令行選項更改。

      在使用日志時,可用FLUSH LOGS語句來刷新和重新開始所有日志文件。

      改善性能

      數(shù)據(jù)庫管理員把他們生命中的相當一部份時間花在了調整、試驗以改善DBMS性能之上。在診斷應用的滯緩現(xiàn)象和性能問題時,性能不良的數(shù)據(jù)庫(以及數(shù)據(jù)庫查詢)通常是最常見的禍因。

      可以看出,下面的內容并不能完全決定MySQL的性能。我們只是想回顧一下前面各章的重點,提供進行性能優(yōu)化探討和分析的一個出發(fā)點。

      • 首先, MySQL(與所有DBMS一樣)具有特定的硬件建議。在學習和研究MySQL時,使用任何舊的計算機作為服務器都可以。但對用于生產(chǎn)的服務器來說,應該堅持遵循這些硬件建議。
      • 一般來說,關鍵的生產(chǎn)DBMS應該運行在自己的專用服務器上。
      • MySQL是用一系列的默認設置預先配置的,從這些設置開始通常是很好的。但過一段時間后你可能需要調整內存分配、緩沖區(qū)大小等。(為查看當前設置,可使用SHOW VARIABLES;和SHOWSTATUS;。)
      • MySQL一個多用戶多線程的DBMS,換言之,它經(jīng)常同時執(zhí)行多個任務。如果這些任務中的某一個執(zhí)行緩慢,則所有請求都會執(zhí)行緩慢。如果你遇到顯著的性能不良,可使用SHOW PROCESSLIST顯示所有活動進程(以及它們的線程ID和執(zhí)行時間)。你還可以用KILL命令終結某個特定的進程(使用這個命令需要作為管理員登錄)。
      • 總是有不止一種方法編寫同一條SELECT語句。 應該試驗聯(lián)結、并、子查詢等,找出最佳的方法。
      • 使用EXPLAIN語句讓MySQL解釋它將如何執(zhí)行一條SELECT語句。
      • 一般來說,存儲過程執(zhí)行得比一條一條地執(zhí)行其中的各條MySQL語句快。
      • 應該總是使用正確的數(shù)據(jù)類型。
      • 決不要檢索比需求還要多的數(shù)據(jù)。換言之,不要用SELECT *(除非你真正需要每個列)。
      • 有的操作(包括INSERT)支持一個可選的DELAYED關鍵字,如果使用它,將把控制立即返回給調用程序,并且一旦有可能就實際執(zhí)行該操作。
      • 在導入數(shù)據(jù)時,應該關閉自動提交。你可能還想刪除索引(包括FULLTEXT索引),然后在導入完成后再重建它們。
      • 必須索引數(shù)據(jù)庫表以改善數(shù)據(jù)檢索的性能。確定索引什么不是一件微不足道的任務,需要分析使用的SELECT語句以找出重復的WHERE和ORDER BY子句。如果一個簡單的WHERE子句返回結果所花的時間太長,則可以斷定其中使用的列(或幾個列)就是需要索引的對象。
      • 你的SELECT語句中有一系列復雜的OR條件嗎?通過使用多條SELECT語句和連接它們的UNION語句,你能看到極大的性能改進。
      • 索引改善數(shù)據(jù)檢索的性能,但損害數(shù)據(jù)插入、刪除和更新的性能。如果你有一些表,它們收集數(shù)據(jù)且不經(jīng)常被搜索,則在有必要之前不要索引它們。(索引可根據(jù)需要添加和刪除。)
      • LIKE很慢。一般來說,最好是使用FULLTEXT而不是LIKE。
      • 數(shù)據(jù)庫是不斷變化的實體。一組優(yōu)化良好的表一會兒后可能就面目全非了。由于表的使用和內容的更改,理想的優(yōu)化和配置也會改變。
      • 最重要的規(guī)則就是,每條規(guī)則在某些條件下都會被打破。

      MySQL語句的語法

      在閱讀語句語法時,應該記住以下約定 :

      • |符號用來指出幾個選擇中的一個,因此, NULL | NOT NULL表示或者給出NULL或者給出NOT NULL。
      • 包含在方括號中的關鍵字或子句(如[like this])是可選的。
      • 既沒有列出所有的MySQL語句,也沒有列出每一條子句和選項。

      ALTER TABLE

      ALTER TABLE用來更新已存在表的模式。為了創(chuàng)建新表,應該使用CREATE TABLE。

      COMMIT

      COMMIT用來將事務處理寫到數(shù)據(jù)庫。

      CREATE INDEX

      CREATE INDEX用于在一個或多個列上創(chuàng)建索引。

      CREATE PROCEDURE

      CREATE PROCEDURE用于創(chuàng)建存儲過程。

      CREATE TABLE

      CREATE TABLE用于創(chuàng)建新數(shù)據(jù)庫表。為更新已經(jīng)存在的表的結構,使用ALTER TABLE。

      CREATE USER

      CREATE USER 用于向系統(tǒng)中添加新的用戶賬戶。

      CREATE VIEW

      CREATE VIEW用來創(chuàng)建一個或多個表上的新視圖。

      DELETE

      DELETE從表中刪除一行或多行。

      DROP

      DROP永久地刪除數(shù)據(jù)庫對象(表、視圖、索引等)。

      INSERT

      INSERT給表增加一行。

      INSERT SELECT

      INSERT SELECT插入SELECT的結果到一個表。

      ROLLBACK

      ROLLBACK用于撤銷一個事務處理塊。

      SAVEPOINT

      SAVEPOINT為使用ROLLBACK語句設立保留點。

      SELECT

      SELECT用于從一個或多個表(視圖)中檢索數(shù)據(jù)。

      START TRANSACTION

      START TRANSACTION表示一個新的事務處理塊的開始。

      UPDATE

      UPDATE更新表中一行或多行。

      MySQL數(shù)據(jù)類型

      數(shù)據(jù)類型是定義列中可以存儲什么數(shù)據(jù)以及該數(shù)據(jù)實際怎樣存儲的基本規(guī)則。

      數(shù)據(jù)類型用于以下目的:

      • 數(shù)據(jù)類型允許限制可存儲在列中的數(shù)據(jù)。例如,數(shù)值數(shù)據(jù)類型列只能接受數(shù)值。
      • 數(shù)據(jù)類型允許在內部更有效地存儲數(shù)據(jù)。可以用一種比文本串更簡潔的格式存儲數(shù)值和日期時間值。
      • 數(shù)據(jù)類型允許變換排序順序。如果所有數(shù)據(jù)都作為串處理,則1位于10之前,而10又位于2之前(串以字典順序排序,從左邊開始比較,一次一個字符)。作為數(shù)值數(shù)據(jù)類型,數(shù)值才能正確排序。

      在設計表時,應該特別重視所用的數(shù)據(jù)類型。使用錯誤的數(shù)據(jù)類型可能會嚴重地影響應用程序的功能和性能。更改包含數(shù)據(jù)的列不是一件小事(而且這樣做可能會導致數(shù)據(jù)丟失)。

      串數(shù)據(jù)類型

      最常用的數(shù)據(jù)類型是串數(shù)據(jù)類型。它們存儲串,如名字、地址、電話號碼、郵政編碼等。有兩種基本的串類型,分別為定長串和變長串 。

      定長串接受長度固定的字符串,其長度是在創(chuàng)建表時指定的。

      定長列不允許多于指定的字符數(shù)目。它們分配的存儲空間與指定的一樣多。 因此, 如果串Ben存儲到30個字符的名字字段,則存儲的是30個字符, CHAR屬于定長串類型。

      變長串存儲可變長度的文本。有些變長數(shù)據(jù)類型具有最大的定長,而有些則是完全變長的。不管是哪種,只有指定的數(shù)據(jù)得到保存(額外的數(shù)據(jù)不保存) TEXT屬于變長串類型。

      既然變長數(shù)據(jù)類型這樣靈活,為什么還要使用定長數(shù)據(jù)類型?回答是因為性能。 MySQL處理定長列遠比處理變長列快得多。此外, MySQL不允許對變長列(或一個列的可變部分)進行索引。這也會極大地影響性能

      串數(shù)據(jù)類型列表:

      數(shù)據(jù)類型 說明
      CHAR 1~255個字符的定長串。它的長度必須在創(chuàng)建時指定,否則MySQL假定為CHAR(1)
      ENUM 接受最多64 K個串組成的一個預定義集合的某個串
      LONGTEXT 與TEXT相同,但最大長度為4 GB
      MEDIUMTEXT 與TEXT相同,但最大長度為16 K
      SET 接受最多64個串組成的一個預定義集合的零個或多個串
      TEXT 最大長度為64 K的變長文本
      TINYTEXT 與TEXT相同,但最大長度為255字節(jié)
      VARCHAR 長度可變,最多不超過255字節(jié)。如果在創(chuàng)建時指定為VARCHAR(n),則可存儲0到n個字符的變長串(其中n≤255)

      使用引號 :不管使用何種形式的串數(shù)據(jù)類型,串值都必須括在引號內(通常單引號更好)。

      數(shù)值數(shù)據(jù)類型

      數(shù)值數(shù)據(jù)類型存儲數(shù)值。 MySQL支持多種數(shù)值數(shù)據(jù)類型,每種存儲的數(shù)值具有不同的取值范圍。顯然,支持的取值范圍越大,所需存儲空間越多。此外,有的數(shù)值數(shù)據(jù)類型支持使用十進制小數(shù)點(和小數(shù)),而有的則只支持整數(shù)。下面的表列出了常用的MySQL數(shù)值數(shù)據(jù)類型。

      有符號或無符號 : 所有數(shù)值數(shù)據(jù)類型(除BIT和BOOLEAN外)都可以有符號或無符號。有符號數(shù)值列可以存儲正或負的數(shù)值,無符號數(shù)值列只能存儲正數(shù)。默認情況為有符號,但如果你知道自己不需要存儲負值,可以使用UNSIGNED關鍵字,這樣做將允許你存儲兩倍大小的值。

      數(shù)據(jù)類型 說明
      BIT 位字段, 1~64位。(在MySQL 5之前, BIT在功能上等價于TINYINT
      BIGINT 整數(shù)值,支持?9223372036854775808~9223372036854775807 (如果是UNSIGNED,為0~18446744073709551615)的數(shù)
      BOOLEAN(或BOOL) 布爾標志,或者為0或者為1,主要用于開/關(on/off)標志
      DECIMAL(或DEC) 精度可變的浮點值
      DOUBLE 雙精度浮點值
      FLOAT 單精度浮點值
      INT(或INTEGER) 整數(shù)值,支持?2147483648~2147483647(如果是UNSIGNED,為0~4294967295)的數(shù)
      MEDIUMINT 整數(shù)值,支持?8388608~8388607(如果是UNSIGNED,為0~ 16777215)的數(shù)
      REAL 4字節(jié)的浮點值
      SMALLINT 整數(shù)值,支持?32768~32767(如果是UNSIGNED,為0~ 65535)的數(shù)
      TINYINT 整數(shù)值,支持?128~127(如果為UNSIGNED,為0~255)的數(shù)

      不使用引號 :與串不一樣,數(shù)值不應該括在引號內

      存儲貨幣數(shù)據(jù)類型: MySQL中沒有專門存儲貨幣的數(shù)據(jù)類型,一般情況下使用DECIMAL(8, 2)

      日期和時間數(shù)據(jù)類型

      MySQL使用專門的數(shù)據(jù)類型來存儲日期和時間值

      數(shù)據(jù)類型 說明
      DATE 表示1000-01-01~9999-12-31的日期,格式為YYYY-MM-DD
      DATETIME DATE和TIME的組合
      TIMESTAMP 功能和DATETIME相同(但范圍較小)
      TIME 格式為HH:MM:SS
      YEAR 用2位數(shù)字表示,范圍是70(1970年)~69(2069年),用4位數(shù)字表示,范圍是1901年~2155年

      二進制數(shù)據(jù)類型

      二進制數(shù)據(jù)類型可存儲任何數(shù)據(jù)(甚至包括二進制信息),如圖像、多媒體、字處理文檔等

      數(shù)據(jù)類型 說明
      BLOB Blob最大長度為64 KB
      MEDIUMBLOB Blob最大長度為16 MB
      LONGBLOB Blob最大長度為4 GB
      TINYBLOB Blob最大長度為255字節(jié)
      posted @ 2024-07-09 01:50  CD、小月  閱讀(166)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲成人免费一级av| 国产精品视频亚洲二区| 亚洲精品专区永久免费区| 日韩精品一区二区三区激情视频 | 欧美videosdesexo吹潮| 久久99精品久久久大学生| 亚洲国产99精品国自产拍| 亚洲中文精品一区二区| av亚洲一区二区在线| 中文字幕人妻无码一区二区三区| 午夜福利激情一区二区三区| 亚洲日韩精品无码av海量| 好紧好湿太硬了我太爽了视频| 久久国产自拍一区二区三区| 人人澡人摸人人添| 爱性久久久久久久久| 瑞安市| 日日碰狠狠添天天爽五月婷| 九九热精品在线视频免费| 久久月本道色综合久久| 亚洲精品熟女一区二区| 亚洲av综合久久成人网| 天天躁夜夜躁狠狠喷水| 无码一级视频在线| 性一交一乱一伦一| 国产精品伦人一久二久三久| 三上悠亚日韩精品二区| 左权县| 自偷自拍亚洲综合精品| 亚洲国产日韩在线视频| 人人人澡人人肉久久精品| 国产亚洲中文字幕久久网| 亚洲人成色77777| 国产精品va在线观看无码不卡| 国内不卡不区二区三区| 精品国产精品午夜福利| 亲子乱aⅴ一区二区三区| 五月综合婷婷开心综合婷婷| 日区中文字幕一区二区| 国产精品免费第一区二区| 精品无码久久久久久久动漫|