第二十九章 多重欄位的搜尋引擎 *********************************************** 版權所有, 非經允許, 請勿分享! 作者 :mis2000lab@yahoo.com.tw 本書網站 : http://www.taconet.com.tw/mis2000_aspnet/ *********************************************** 台科大圖書, 電話 :(02)2908-5945 郵購方式 ---- 帳號 :1913396-0, 帳戶 : 台科大圖書股份有限公司本書編號 93002, 書名 : ASP.NET 經典實務 ---- 使用 Visual Studio.NET 開發知識管理網站, 作者 :MIS2000 Lab. 郵購價格 405 元 ( 打九折 ), 另外自行負擔本島郵資 80 元 ( 共計 485 元 )! 外島郵資 200 元! 團購一千元以上免郵資! 本書範例, 均採用 MS Visual Studio.NET 來進行開發! 測試版本為 MS Visual Studio.NET 2001 / 2003 兩個版本, 搭配 MS SQL Server 2000 來開發企業的知識管理網站 經過 Microsoft.NET Framework 1.0 與 1.1 實地測試無誤 VS.Net 2005 與 ASP.NET 2.0 因為更改幅度較大, 與下面的文章可能會有差異 上一章介紹的搜尋引擎, 算是最基本的陽春型態, 只能針對一個欄位來搜尋 如 果要同時搜尋多個欄位 ( 如下圖 ), 該怎麼辦? 倘若我要在資料庫裡面, 搜尋某一篇文章, 搜尋的條件是 ---- 文章標題有 電 這個關鍵字, 而且文章摘要裡面也有 電 這個字, 作者欄位裡面有 記者 二 字的文章 應該如同下圖的型態 :
圖 1 多重欄位 的搜尋引擎
圖 2 搜尋結果 29-1 多重欄位搜尋,SQL 指令的迷思 根據上一章的範例, 很多初學者會這麼撰寫 SQL 指令 : Select * from test where 鍵字 % and author like % 關鍵字 % title like % 關鍵字 % and summary like % 關 這種方式當然也可以讓程式正常執行, 只不過搜尋出來的結果往往不夠精確! 尤 其是資料量越多, 搜尋出來的結果就越不精準 這是為什麼呢? 想想看 : 既然是 多重欄位 的搜尋引擎, 使用者會輸入的搜尋條件就會有許多排列組合 例如 : 他可能只搜尋 標題 與 作者 兩個欄位, 或是只搜尋 作者 欄位而已 如果採用上面的 SQL 指令來作搜尋, 就會造成某些搜尋欄位的 關鍵字 變成空白
當使用者只輸入一個 作者 欄位的關鍵字來搜尋時, 會造成下面的結果 Select * from test where title like %% and summary like %% and author like % 關鍵字 % SQL 指令裡面, 欄位名稱 like %% 這個條件式, 表示 所有條件都符合 的情況, 會把所有的資料全部列出來 這種情況會導致資料越找越多, 越找越不精準 圖 3 執行 select * from test where title like %% 的指令, 就如同執行 select * from test 的結果一模一樣 要如何破解這樣的迷思呢? 道理很簡單, 當使用者不搜尋這個欄位時, 我們就該避免搜尋到這個欄位 因為 這是一個 多重欄位 的輸入與搜尋, 所以使用者輸入的狀態可能有各種排列組 合 從這個角度來思考, 數學上的排列組合, 會導致程式撰寫的難度倍增! 最好的方法便是 : 使用者要搜尋哪幾個欄位, 我們就拼湊成合適的 SQL 指令 無論如何, 絕不讓 SQL 指令裡面的條件式, 變成 欄位名稱 like %% 這 種狀態 29-2 程式的撰寫, 採用 DataReader
首先, 我們先將連結資料庫 (SqlConnection) 與 SQL 指令 (SqlCommand) 的部 份, 還有文字方塊 (TextBox 控制項 ) 與 DataGrid 控制項 ( 用來呈現搜尋引擎找 出來的資料庫 ) 的部份先設定好 圖 4 程式的先前準備工作 關於 DataGrid 的標題欄位與色彩調配, 可以分別採用 屬性產生器 與 自動 格式化 來完成之
圖 5 DataGrid 的設定 完成畫面的設定之後, 請按下 滑鼠右鍵 檢視程式碼, 開始撰寫後置程 式碼的部份 當使用者輸入搜尋欄位的關鍵字之後, 按下 (Click) 按鈕開始搜尋, 也就是執 行 Button1_Click( ) 副程式
圖 6 按下 搜尋 按鈕之後, 會執行這裡的 Button1_Clik( ) 副程式 我們利用 字串相連 的特色, 可以來解決這個問題 當使用者在這個欄位裡面, 有輸入 關鍵字, 我們才使其形成 SQL 指令的 條件式 舉例來說, 當使用者在 標題 欄位裡面輸入了關鍵字 ( 畫面上的欄位有輸入關 鍵字, 表示 這個欄位 的內容不是空白 程式寫成 :IF 標題欄位 <> ), 我 們就形成 SQL 指令的條件式字串 (and title like % 關鍵字 % ) Dim sqlstr As String If TextBox1.Text <> "" Then sqlstr = " and title like '%" & TextBox1.Text & "%' " If TextBox2.Text <> "" Then sqlstr = sqlstr & " and summary like '%" & TextBox2.Text & "%' "
If TextBox3.Text <> "" Then sqlstr = sqlstr & " and author like '%" & TextBox3.Text & "%' " 若撰寫成上面的 IF 判別式, 不管使用者想要搜尋哪個欄位? 都會精準地拼湊出 適當的 SQL 指令, 絕對不會出現 欄位名稱 like %% 這種情況 如此一 來, 搜尋引擎的精確能力就大大地提升了 這支程式還有另外一個小訣竅, 那就是 SQL 指令的開頭, 必須撰寫成 select * from test where 1=1, 這是為什麼呢? 想想看 : 如果使用者完全不輸入任何一個欄位, 便按下搜尋按鈕,SQL 指令的 Where 1=1 也可以正常執行, 並不會出現異樣 不相信的話, 請讀者使用各種排列組合, 輸入任何一個欄位, 我保證拼湊出來的 SQL 指令都是最精確的狀態 為此, 我故意在程式執行的畫面上, 呈現出 SQL 指令的原始碼給各位看 圖 7 搜尋的情況 ( 一 )
圖 8 搜尋的情況 ( 二 ) 完整的 Advance_search.aspx 後置程式碼 ( 檔名 Advance_search.aspx.vb) 如下 : Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load End Sub Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click Dim sqlstr As String If TextBox1.Text <> "" Then sqlstr = " and title like '%" & TextBox1.Text & "%' " If TextBox2.Text <> "" Then sqlstr = sqlstr & " and summary like '%" & TextBox2.Text & "%' "
If TextBox3.Text <> "" Then sqlstr = sqlstr & " and author like '%" & TextBox3.Text & "%' " SqlConnection1.Open() SqlCommand1.CommandText = "select * from test where 1=1 " & sqlstr Response.Write(SqlCommand1.CommandText) 註解 : 搜尋後的結果, 交由 DataGrid 呈現在畫面上 DataGrid1.DataSource = SqlCommand1.ExecuteReader DataGrid1.DataBind() End Sub SqlConnection1.Close() 29-2 程式的撰寫, 採用 DataSet 如果改用 DataSet 來寫就更簡單了, 只不過, 要將 SqlCommand 改成 SqlDataAdapter 並且使用 DataSet 只要在畫面設定之時, 稍做修改即可 請 看下列的程式
圖 9 設定為 DataSet 的步驟 Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ' 在這裡放置使用者程式碼以初始化網頁 End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim sqlstr As String If TextBox1.Text <> "" Then sqlstr = " and title like '%" & TextBox1.Text & "%' " If TextBox2.Text <> "" Then sqlstr = sqlstr & " and summary like '%" & TextBox2.Text & "%' " If TextBox3.Text <> "" Then sqlstr = sqlstr & " and author like '%" & TextBox3.Text & "%' " ' 註解 : 改用 DataSet 之後,SQL 指令的部分要改寫如下 : SqlDataAdapter1.SelectCommand.CommandText = "select * from test
where 1=1 " & sqlstr Response.Write(SqlDataAdapter1.SelectCommand.CommandText) End Sub SqlDataAdapter1.Fill(DataSet11, "test") DataGrid1.DataBind() 看看您是否能幫這個搜尋引擎, 加上 分頁 的功能了 給您一點點小提示 : DataSet 加上 DataGrid 就可以完成囉 29-3 初學者常見的邏輯錯誤 本章課後練習 -- 題目 : 利用 DataSet 來製作一個 多重欄位的搜尋引擎, 而且搜尋結果必須具備 分頁 功能! 這個小範例是我給學生的課後作業, 全部的內容, 上課通通教過, 但是卻考驗了 學生的 思考 能力 ( 常見的錯誤跟尤其是上一章最後一節的內容, 一模一樣 ) 這裡採用 DataSet 來進行分頁, 很容易發生相同的錯誤而不自知 初學者會發現 : 在他的 DataGrid 裡面的搜尋結果, 第二頁開始一定會出現錯誤 也就是 第一頁搜尋的結果是對的, 但第二頁 第三頁的搜尋結果都錯了 這也是因為初學者把目標放在 Visual Studio.NET 的操作上, 卻忘記深思程式執行的順序與流程 如果初學者的 DataGrid 分頁程式, 照本宣科地用以前教過的方式來撰寫如下, 一定會出現致命的錯誤! 錯誤範例!! Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged 註解 : 分頁必備的程式碼! DataGrid1.CurrentPageIndex() = e.newpageindex
End Sub SqlDataAdapter1.Fill(DataSet41, "test") DataGrid1.DataBind() 為什麼會錯? 能夠想通這一段錯誤, 我就能恭喜您 : 您已經出師了! 抱歉, 以下精華部分, 網路上並不公開 因為書本出版時, 這一段也還沒曝光, 是我後來補上的 請您買書之後, 跟我索取這一部份的補充文章!! 謝謝您 *********************************************** 版權所有, 非經允許, 請勿分享! 作者 :mis2000lab@yahoo.com.tw 本書網站 : http://www.taconet.com.tw/mis2000_aspnet/ *********************************************** 台科大圖書, 電話 :(02)2908-5945 郵購方式 ---- 帳號 :1913396-0, 帳戶 : 台科大圖書股份有限公司本書編號 93002, 書名 : ASP.NET 經典實務 ---- 使用 Visual Studio.NET 開發知識管理網站, 作者 :MIS2000 Lab. 郵購價格 405 元 ( 打九折 ), 另外自行負擔本島郵資 80 元 ( 共計 485 元 )! 外島郵資 200 元! 團購一千元以上免郵資! 本書範例, 均採用 MS Visual Studio.NET 來進行開發! 測試版本為 MS Visual Studio.NET 2001 / 2003 兩個版本, 搭配 MS SQL Server 2000 來開發企業的知識管理網站 經過 Microsoft.NET Framework 1.0 與 1.1 實地測試無誤 VS.Net 2005 與 ASP.NET 2.0 因為更改
幅度較大, 與下面的文章可能會有差異