SQL 多條件查詢去掉影響效率的where 1=1
網上有不少人提出過類似的問題:“看到有人寫了WHERE 1=1這樣的SQL,到底是什麼意思?”。其實使用這種用法的開發人員一般都是在使用動態組裝的SQL。讓我們想像如下的場景:用戶要求提供一個靈活的查詢界麵來根據各種複雜的條件來查詢員工信息,界麵如下圖:
界麵中列出了四個查詢條件,包括按工號查詢、按姓名查詢、按年齡查詢以及按工資查詢,每個查詢條件前都有一個複選框,如果複選框被選中,則表示將其做為一個過濾條件。比如上圖就表示“檢索工號介於DEV001和DEV008之間、姓名中含有J並且工資介於3000元到6000元的員工信息”。如果不選中姓名前的複選框,比如下圖表示“檢索工號介於DEV001和DEV008之間並且工資介於3000元到6000元的員工信息”:
如果將所有的複選框都不選中,則表示表示“檢索所有員工信息”,比如下圖:
如果想學習java可以來這個群,首先是二二零,中間是一四二,最後是九零六,裏麵有大量的學習資料可以下載。
這裏的數據檢索與前麵的數據檢索都不一樣,因為前邊例子中的數據檢索的過濾條件都是確定的,而這裏的過濾條件則隨著用戶設置的不同而有變化,這時就要根據用戶的設置來動態組裝SQL了。當不選中年齡前的複選框的時候要使用下麵的SQL語句:
SELECT * FROM T_Employee
WHERE FNumber BETWEEN 'DEV001' AND 'DEV008'
AND FName LIKE '%J%'
AND FSalary BETWEEN 3000 AND 6000
而如果不選中姓名和年齡前的複選框的時候就要使用下麵的SQL語句:
SELECT * FROM T_Employee
WHERE FNumber BETWEEN 'DEV001' AND 'DEV008'
AND FSalary BETWEEN 3000 AND 6000
而如果將所有的複選框都不選中的時候就要使用下麵的SQL語句:
SELECT * FROM T_Employee
要實現這種動態的SQL語句拚裝,我們可以在宿主語言中建立一個字符串,然後逐個判斷各個複選框是否選中來向這個字符串中添加SQL語句片段。這裏有一個問題就是當有複選框被選中的時候SQL語句是含有WHERE子句的, 而當所有的複選框都沒有被選中的時候就沒有WHERE子句了,因此在添加每一個過濾條件判斷的時候都要判斷是否已經存在WHERE語句了,如果沒有WHERE語句則添加WHERE語句。 在判斷每一個複選框的時候都要去判斷, 這使得用起來非常麻煩,“聰明的程序員是會偷懶的程序員”,因此開發人員想到了一個捷徑:為SQL語句指定一個永遠為真的條件語句(比如“1=1”),這樣就不用考慮WHERE語句是否存在的問題了。偽代碼如下:
String sql = " SELECT * FROM T_Employee WHERE 1=1";
if(工號複選框選中)
{
sql.appendLine("AND FNumber BETWEEN '"+工號文本框1內容+"' AND '"+工號文本框2內容+"'");
}
if(姓名複選框選中)
{
sql.appendLine("AND FName LIKE '%"+姓名文本框內容+"%'");
}
if(年齡複選框選中)
{
sql.appendLine("AND FAge BETWEEN "+年齡文本框1內容+" AND "+年齡文本框2內容);
}
executeSQL(sql);
這樣如果不選中姓名和年齡前的複選框的時候就會執行下麵的SQL語句:
SELECT * FROM T_Employee WHERE 1=1
AND FNumber BETWEEN 'DEV001' AND 'DEV008'
AND FSalary BETWEEN 3000 AND 6000
而如果將所有的複選框都不選中的時候就會執行下麵的SQL語句:
SELECT * FROM T_Employee WHERE 1=1
這看似非常優美的解決了問題,殊不知這樣很可能會造成非常大的性能損失,因為使用添加了“1=1”的過濾條件以後數據庫係統就無法使用索引等查詢優化策略,數據庫係統將會被迫對每行數據進行掃描(也就是全表掃描)以比較此行是否滿足過濾條件,當表中數據量比較大的時候查詢速度會非常慢。因此如果數據檢索對性能有比較高的要求就不要使用這種“簡便”的方式。下麵給出一種參考實現,偽代碼如下:
private void doQuery()
{
Bool hasWhere = false;
StringBuilder sql = new StringBuilder(" SELECT * FROM T_Employee");
if(工號複選框選中)
{
hasWhere = appendWhereIfNeed(sql, hasWhere);
sql.appendLine("FNumber BETWEEN '"+工號文本框1內容+"' AND '"+工號文本框2內容+"'");
}
if(姓名複選框選中)
{
hasWhere = appendWhereIfNeed(sql, hasWhere);
sql.appendLine("FName LIKE '%"+姓名文本框內容+"%'");
}
if(年齡複選框選中)
{
hasWhere = appendWhereIfNeed(sql, hasWhere);
sql.appendLine("FAge BETWEEN "+年齡文本框1內容+" AND "+年齡文本框2內容);
}
executeSQL(sql);
}
private Bool appendWhereIfNeed(StringBuilder sql,Bool hasWhere)
{
if(hasWhere==false)
{
sql. appendLine("WHERE");
}
else
{
sql. appendLine("AND");
}
}
以上內容由博主摘自《程序員的SQL金典》。
模煳查詢時:
[java] view plain copy
String name = request.getParameter("name"); //姓名
String rank= request.getParameter("age"); //年齡
String address= request.getParameter("address"); //地址
String sql = "select * from student where 1=1 ";
if(name!=null && !name.equals("")){
sql += "t.name like '%"+name+"%'";
}
if(rank!=null && !rank.equals("")){
sql += "t.age like '%"+age+"%'";
}
if(address!=null && !address.equals("")){
sql += "t.address like '%"+address+"%'";
最後更新:2017-04-07 21:05:50