?? core9.htm
字號:
<html><head><title>第九章 查詢數據庫 http://jjlzg.yeah.net</title><meta http-equiv=Content-Type content="text/html; charset=gb2312"></head><body bgcolor="#00000" text="#00cc66"><b>第九章 查詢數據庫</b><br> 這一章介紹如何用TQuery構件查詢數據庫,如何通過SQL語句檢索、插入、更新和刪除數據。SQL是符合工業標準的關系數據庫語言,既可以用于遠程的基于服務器的數據庫,如Sybase、Oracle、InterBase和Microsoft SQL Server,也可以用于本地數據庫如Paradox、dBASE、FoxPro和Access以及符合ODBC的數據庫。<br> <b>9.1 有效地使用查詢</b><br> 要有效地使用查詢,必須熟悉標準的SQL語言以及所使用的服務器對SQL-92的限制和擴展,同時還要熟悉BDE。<br> <b>9.1.1 查詢桌面數據庫</b><br> 作為一個桌面開發者,應對表格、記錄和字段的概念有所了解,又能熟練地使用TTable構件訪問數據集中的每一條記錄和每一個字段。<br> 還可以使用TTable的范圍和過濾功能在數據集中選擇一部分記錄,前者用于選擇一塊連續的記錄,這些記錄的值在一個特定的范圍內; 后者用于選擇非連續的記錄,這些記錄符合特定的條件。<br> 所謂查詢,非常類似于過濾,不同的是,查詢要用到TQuery構件和SQL屬性,有時候可能還要用到Params屬性。從功能上講,查詢要比過濾復雜和強大些,這主要體現在:<br> .可以同時查詢幾個表格<br> .可以讓查詢結果中只包含部分字段,而過濾將返回所有字段。<br> 查詢也可以帶參數,此時稱為參數化查詢。所謂參數,類似于變量,它的實際的值由BDE在執行SQL語句之前賦值。參數化查詢的好處是,不需要修改SQL語句,只要修改參數的值,就能執行不同的查詢功能。<br> 大部分情況下,使用TQuery構件是為了在數據集中選擇一部分字段和記錄,但也可以使用SQL語句實現更新、插入和刪除記錄的功能,這是與TTable構件的一個區別。<br> <b>9.1.2 查詢遠程數據庫</b><br> 要查詢遠程數據庫,必須熟悉SQL語句以及服務器對標準SQL的限制和擴展。<br> TQuery構件的SQL屬性用于指定要執行的SQL語句, Params屬性用于提供參數。TQuery構件的功能并不只限于SQL語句和參數,它還是BDE與應用程序之間的接口。<br> 應用程序可以通過TQuery構件的屬性和方法來操縱SQL語句和參數。TQuery構件最終還是通過SQL Links與遠程服務器進行通訊的,遠程服務器把查詢結果返回給BDE,再由BDE返回給應用程序。<br> <b>9.2 可以查詢哪些數據庫</b><br> 使用TQuery構件可以查詢下列數據庫:<br> 一是Paradox或dBASE,這是通過BDE內置的Local SQL實現的。Local SQL是SQL-92標準的一個子集,支持大部分DML和DDL。<br> 二是Local InterBase Server,這是通過InterBase引擎實現的。<br> 三是遠程數據庫,如Oracle、Sybase、MS-SQL Server、InFormix、DB2和InterBase,不過,必須安裝了相應的SQL Links驅動程序。不同的服務器對標準SQL都有不同的限制和擴展,要查詢遠程數據庫之前,務必要查閱它的有關文檔。<br> Delphi 4還支持異構查詢,也就是說,可以同時查詢幾個不同類型的數據庫。<br> <b>9.3 使用TQuery構件的一般步驟</b><br> 第一步是把一個TQuery構件放到數據模塊上,設置它的DatabaseName屬性指定要訪問的數據庫。對于Paradox和dBASE來說,DatabaseName屬性可以設為BDE別名如DBEMOS、DefaultDD、IBLOCAL等,也可以是自定義的別名或者表所在的路徑。<br> 對于SQL表來說,DatabaseName屬性只能設為BDE別名。如果應用程序使用TDatabase構件來連接數據庫,DatabaseName屬性也可以設為應用程序專用的別名。<br> 第二步是設置SQL屬性指定要執行的SQL語句,有必要的話還可以設置Params屬性為SQL語句設置參數。<br> 第三步是把TDataSource構件放到數據模塊上,設置它的DataSet屬性指定TQuery構件。再把TDBGrid構件放到窗體上,設置它的DataSource屬性指定TDataSource構件。<br> 第四步是執行SQL語句。要執行SQL語句有兩種方式,一是在設計期把Active屬性設為True,程序啟動時將自動執行SQL語句。另一種方式是在運行期調用Open或ExecSQL執行SQL語句。如果希望返回查詢結果,調用Open,如果不需要返回查詢結果,調用ExecSQL。在調用Open或ExecSQL之前,最好先調用Prepare通知服務器作好準備。<br> 執行SQL語句所返回的查詢結果實際上是數據集中滿足特定條件的記錄所組成的子集,數據庫柵格中只顯示符合特定條件的記錄。<br> <b>9.4 指定要執行的SQL語句</b><br> 可以設置SQL屬性以指定要執行的SQL語句。在設計期,只要把Active屬性設為True,就會自動執行SQL語句。在運行期,首先要調用Prepare通知服務器準備好,然后調用Open或ExecSQL執行SQL函數語句。<br> <b>9.4.1 概述</b><br> SQL屬性是一個典型的TStrings對象。SQL屬性一般只包含一條完整的SQL語句,但可以分成幾行寫,TQuery構件會自動把幾行字符串合并成一條SQL語句。<br> 把SQL語句分成幾行寫的好處是,SQL語句的邏輯結構比較清楚,有利于今后維護和調試。所以,SQL語句的SELECT部分和WHERE部分一般都不在同一行上。<br> SQL語句可以不帶參數,把字段名稱和值固定在SQL語句中,例如,下面這個SQL語句就是硬寫(Hard-Coded)的:<br> SELECT * FROM Customer WHERE CustNo = 1231<br> 注意:如果要查詢的是本地數據庫,如果SQL語句中的字段名包含空格或其他特殊符號,必須用引號括起來,前面還要加上表格名和小圓點。<br> 如果用參數的話,查詢就靈活得多,應用程序不需要改寫SQL語句本身,只要修改參數的值,就能使SQL語句執行不同的查詢功能。在執行SQL語句之前,TQuery構件會自動把實際的值替換SQL語句中的參數,即使并沒有顯式地調用Prepare函數。<br> 下面這條SQL語句是典型的參數化查詢:<br> SELECT * FROM Customer WHERE CustNo = :Number<br> 其中,Number就是一個參數,它的前面必須加冒號。在運行期,應用程序必須提供Number參數的值,每次執行SQL語句時,Number參數的值可以不同。<br> 參數的值是通過TQuery的Params屬性提供的。<br> <b>9.4.2 在設計期指定SQL語句</b><br> 在設計期,要指定SQL語句,可以在對象觀察器中單擊SQL屬性邊上的省略號按鈕,彈出一個字符串列表編輯器,如圖9.1所示。 <br> 圖9.1 在設計期指定SQL語句<br> SQL語句可以分成幾行寫,但同一單詞不能分開。一般情況下,SQL屬性只能包含一條完整的SQL語句,但有些服務器允許同時執行幾條SQL語句,這種情況下,可以輸入多條SQL語句。<br> 如果使用Delphi 4的Client/Server版本或Enterprise版本,也可以用SQLBuilder這個實用工具來建立SQL語句。要使用SQL Builder,在TQuery構件上單擊鼠標右鍵,在彈出的菜單中選擇“SQL Builder”命令。<br> <b>9.4.3 在運行期指定SQL語句</b><br> 在運行期,要指定SQL屬性有三種方式,一是直接設置SQL屬性,二是調用LoadFromFile從文件中讀取SQL語句,或者從另一個TStrings對象中獲得SQL語句。<br> 在直接設置SQL屬性之前,首先要調用Close函數。如果SQL屬性中本來已經有了SQL語句,還要調用Clear把原來的SQL語句清除。<br> 下面的代碼演示了怎樣在運行期直接設置SQL屬性:<br> With CustomerQuery Do<br> Begin<br> Close;<br> With SQL Do<br> Begin<br> Clear;<br> Add('SELECT * FROM Customer');<br> Add('WHERE Company = 'Light Diver');<br> End;<br> Open;<br> End;<br> 有時候,可能想在原來的SQL語句的基礎上修改或增加一行,這時候就不能調用Clear把原來的SQL語句清掉,例如:<br> CustomerQuery.SQL[1] := 'WHERE Company = "Light Diver"';<br> 也可以調用LoadFromFile從文件中獲取SQL語句,這主要是因為TStrings對象支持文件操作。LoadFromFile會自動把原來的SQL語句清掉。<br> 下面的代碼是調用LoadFromFile的例子:<br> CustomerQuery.Close;<br> CustomerQuery.SQL.LoadFromFile('c:\orders.txt');<br> CustomerQuery.Open;<br> 還可以從另一個TStrings對象中獲取SQL語句,這就要調用TStrings的Assign函數。Assign 會自動把原來的SQL語句清空。<br> 下面的代碼是調用Assign的例子:<br> CustomerQuery.Close;<br> CustomerQuery.SQL.Assign(Memo1.Lines);<br> CustomerQuery.Open;<br> <b>9.5 參 數</b><br> 要使用參數化查詢,必須在SQL語句中加入參數,例如:<br> INSERT INTO Country (Name, Capital, Population)<br> VALUES (:Name, :Capital, :Population)<br> 其中,Name、Capital和Population是三個參數。<br> 在執行上述SQL語句之前,應用程序應當調用Prepare函數通知BDE和服務器預先分配好資源,以加快查詢速度。程序示例如下:<br> With Query1 Do<br> Begin<br> Close;<br> Unprepare;<br> ParamByName('Name').AsString := 'China';<br> ParamByName('Capital').AsString := 'Beijing';<br> ParamByName('Population').AsInteger := '120000';<br> Prepare;<br> Open;<br> End;<br> <b>9.5.1 在設計期提供參數</b><br> 要在設計期提供參數,單擊Params屬性邊上的省略號按鈕,彈出如圖9.2所示的編輯器。<br> 圖9.2 在設計期設置Params屬性<br> 如果SQL語句中沒有包含任何參數,圖9.2所示的編輯器就是空白的。這個編輯器的工具欄總是禁止的,這意味著只能在SQL語句中加入參數。<br> 選擇其中一個參數(TParam對象),就可以在對象觀察器中設置它的屬性,或者建立事件句柄。TParam的主要屬性有:<br> DataType屬性用于指定參數的數據類型,它的初始值總是ftUnknown,必須設置每個參數的數據類型。<br> ParamType屬性用于指定參數的使用類型,它的初始值也是ptUnknown。<br> Value屬性用于給出參數的值。當然,也可以在運行期給出參數的值。<br> <b>9.5.2 在運行期提供參數</b><br> 要在運行期訪問參數,有三種方式:<br> 一是通過ParamByName函數按名稱訪問參數。<br> 二是通過Params屬性按序號訪問參數。<br> 三是通過TParams對象的ParamValues屬性按名稱訪問參數。<br> 假設一條SQL語句有三個參數:<br> INSERT INTO "COUNTRY.DB"<br> (Name, Capital, Continent)<br> VALUES (:Name, :Capital, :Continent)<br> 下面這行代碼通過ParamByName函數來訪問其中的Capital參數:Query1.ParamByName('Capital').AsString := Edit1.Text;<br> 下面這行代碼通過Params屬性來訪問其中的Name參數: <br> Query1.Params[0].AsString := Edit1.Text;<br> 下面這行代碼通過TParams對象的ParamValues屬性來同時訪問三個參數:<br> Query1.Params.ParamValues['Country;Capital;Continent'] :=VarArrayOf([Edit1.Text, Edit2.Text, Edit3.Text]); <br> <b>9.5.3 從另一個數據集獲得參數</b><br> TQuery構件的DataSource屬性用于指定一個數據源(TDataSource構件),如果應用程序既沒有在設計期也沒有在運行期給參數賦值,它就在這個數據源中查找與參數名匹配的字段,然后用這個字段的值作為參數的值。<br> 假設一個數據模塊叫LinkModule,上面有一個TQuery構件叫OrdersQuery,它的SQL語句如下:<br> SELECT CustNo, OrderNo, SaleDate<br> FROM Orders WHERE CustNo = :CustNo<br> 另外,數據模塊上還有下列構件:<br> .一個TTable構件叫CustomersTable,它的TableName屬性設為CUSTOMER.DB。<br> .一個TDataSource構件叫OrdersSource,它的DataSet屬性設為OrdersQuery。<br> .一個TDataSource構件叫CustomersSource,它的DataSet屬性設為CustomersTable。<br> .OrdersQuery的DataSource屬性也設為CustomersSource。<br> 假設應用程序有一個窗體叫LinkedQuery,窗體上有兩個TDBGrid構件,它們的DataSource屬性分別指定CustomersSource和OrdersSource。<br> 如果編譯和運行這個應用程序,將看到如圖9.3所示的效果:<br> 圖9.3 從另一個數據集獲得參數<br> 這里簡單解釋一下圖9.3。如果沒有對SQL語句中的:CustNo參數賦值,OrdersQuery將試圖從CustomersSource指定的數據集中查找匹配的字段。由于CustomersSource是從CUSTOMER.DB中獲取數據的,而CUSTOMER.DB中恰好有一個CustNo字段,所以,:CustNo參數的值就是CustNo字段的值。如果您在顯示CUSTOMER.DB的柵格中選擇了另一條記錄,將導致:CustNo參數的值跟著變化。<br> <b>9.6 執 行 查 詢</b><br> 當指定了SQL語句并且提供了參數后,就可以執行查詢了。如果是第一次執行查詢,最好調用Prepare通知BDE或服務器做好準備,這樣能加快查詢的速度。<br> 既可以在設計期執行查詢,也可以在運行期執行查詢。<br> 要在設計期執行查詢,只要把Active屬性設為True。不過,在設計期能執行的SQL語句,僅限于SELECT語句,不能是INSERT、UPDATE或DELETE語句。<br> 要在運行期執行查詢,可以調用Open或ExecSQL函數,其中,Open適合于執行SELECT語句,而ExecSQL適合于執行INSERT、UPDATE或DELETE語句,后者不返回結果。<br> 在調用Open或ExecSQL之前,首先要調用Close。程序示例如下:<br> CustomerQuery.Close;<br> CustomerQuery.Open;<br> 如果在編程的時候無法確定是否要返回查詢結果,可以用Try...Except結構把這兩個過程都寫進去,一般Open在Try部分調用,而ExecSQL在Except部分調用,這樣,即使Open調用失敗,也能執行到ExecSQL。程序示例如下:<br> Try<br> Query2.Open;<br> Except <br> On E: Exception Do<br> If not (E is ENoResultSet) then Raise;<br> End;<br> 前面多次提到,在執行查詢前最好先調用Prepare,盡管這并不是必須的。預先調用Prepare能夠改善應用程序的性能。程序示例如下:<br> CustomerQuery.Close;<br> If not (CustomerQuery.Prepared) then<br> CustomerQuery.Prepare;<br> CustomerQuery.Open;<br> 上述程序首先調用Close,然后檢查Prepared屬性,如果這個屬性返回True,表示已經準備好,如果這個屬性返回False,表示沒有準備好,此時就要調用Prepare。<br> <b>9.7 異 構 查 詢</b><br> 所謂異構查詢,就是同時查詢幾個不同的數據庫。這些數據庫的類型可以不同。例如,可以同時查詢Oracle數據庫、Sybase數據庫和本地的dBASE表。當程序執行異構查詢的時候,BDE通過Local SQL來分析和處理這個查詢,而不是用與服務器相關的特定的SQL語法。<br> 建立一個異構查詢的一般步驟是這樣的:<br> 第一步,把一個TQuery構件放到窗體或數據模塊上,讓DatabaseName屬性空著。<br> 第二步,為要查詢的每一個數據庫建立一個單獨的BDE別名。<br> 第三步,設置SQL屬性以指定要執行的SQL語句。在SQL語句中,表的名字前要加別名和冒號,并且用雙引號括起來。字段名前要加表名和小圓點。例如:<br> SELECT Customer.CustNo, Orders.OrderNo<br> FROM "Oracle1:CUSTOMER"<br> JOIN "Sybase1:ORDERS"<br> ON (Customer.CustNo = Orders.CustNo)<br> WHERE (Customer.CustNo = 1503)<br> 第四步,設置Params屬性提供參數。<br> 第五步,調用Prepare通知BDE或服務器做好準備,然后調用Open或ExecSQL執行查詢。如果顯式地使用TDatabase構件連接數據庫,并且設置了它的DatabaseName屬性定義了應用程序專用的別名,在SQL語句中可以用專用的別名代替BDE別名。<br> <b>9.8 查 詢 結 果</b><br> 默認情況下,查詢結果是只讀的。應用程序可以用數據控件去顯示查詢結果,但用戶不能編輯數據。怎樣才能使用戶能夠編輯數據呢?<br> 要使用戶能夠編輯數據,必須把TQuery構件的RequestLive屬性設為True。不過,把RequestLive屬性設為True并不能保證查詢結果一定是可以修改的,因為這還取決于查詢使用的是Local SQL還是與服務器相關的SQL。<br> 像查詢Paradox或dBASE以及異構查詢都是使用Local SQL,而查詢遠程服務器則使用與服務器相關的SQL。即使RequestLive屬性設為True,而且查詢的是本地數據庫,但由于SELECT語句的文法不合適,BDE也將返回只讀的查詢結果。<br> 因此,在編輯數據之前,先要訪問CanModify屬性。只有當這個屬性返回True時,才表示查詢結果是可編輯的。</body></html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -