2013-06-21 129 views
1

我創建了一個表單,用戶可以使用它來搜索事務。這是形式的圖片:ASP.NET - 實現搜索功能和SQL

enter image description here

現在,總價下拉列表中有成員:

  1. 任何代價
  2. 確切數額
  3. 以下金額
  4. 以上金額

貨幣下拉列表中有成員:

  1. 任何貨幣
  2. EUR
  3. 美元
  4. GBP

交易日下拉列表中有成員:

  1. 任何日期
  2. 準確日期
  3. 以下日期
  4. 以上日期

交易狀態下拉列表中有成員:

  1. 任何狀態
  2. 有效
  3. 過期
  4. 付費

所有細節正在從表中取出名爲付款

有人可以幫我我怎麼去付款表中搜索?使用一條SQL語句可以滿足所有不同的可能性嗎?或者我必須使用多個SQL語句?有人可以給我一個可用於滿足不同可能性的SQL語句模板嗎?請幫忙,因爲SQL不是我最強的一點。謝謝:)

回答

1

UPDATE:修改下面的代碼,以允許範圍(包括無界範圍)

一個存儲過程可以很容易地處理的查詢,如此,如果正確地明白。只需檢查NULL即可使參數可選。如果參數是NULL,請不要根據它進行查詢。

CREATE PROCEDURE schema.FindPayments 
(
    @MinPrice double = NULL, 
    @MaxPrice double = NULL, 
    @Currency char(3) = NULL, 
    @MinTranDate datetime = NULL, 
    @MaxTranDate datetime = NULL, 
    @TranStatus int = NULL 
) 
AS BEGIN 

    SELECT  * 
    FROM  Payments 
    WHERE  (
         @MinPrice IS NULL 
        OR TotalPrice >= @MinPrice 
       ) 
      OR (
         @MaxPrice IS NULL 
        OR TotalPrice <= @MaxPrice 
       ) 
      OR (
         @Currency IS NULL 
        OR Currency = @Currency 
       ) 
      OR (
         @MinTranDate IS NULL 
        OR TranDate >= @MinTranDate 
       ) 
      OR (
         @MaxTranDate IS NULL 
        OR TranDate <= @MaxTranDate 
       ) 
      OR (
         @TranStatus IS NULL 
        OR TranStatus = @TranStatus 
       ) 
END 

現在您還可以從這個代碼存儲過程中無論是DBNull.Value通過爲未指定的參數,或者因爲我分配NULL爲默認爲所有paramters,你可以通過選定的參數。

SqlCommand l_findPayments = new SqlCommand("FindPayments", new SqlConnection("...")); 
l_findPayments.CommandType = CommandType.StoredProcedure; 

if (l_totalPriceComparison == "Exact Amount") 
{ 
    findPayments.Parameters.Add(new SqlParameter("@MinPrice", l_price)); 
    findPayments.Parameters.Add(new SqlParameter("@MaxPrice", l_price)); 
} 
else if (l_totalPriceComparison == "Below Amount") 
    findPayments.Parameters.Add(new SqlParameter("@MaxPrice", l_price)); 
else if (l_totalPriceComparison == "Above Amount") 
    findPayments.Parameters.Add(new SqlParameter("@MinPrice", l_price)); 
// "Any Price" will just leave the parameter 
// blank, so it will not filter on price 

// ... repeat for all params 

SqlDataReader l_result = l_findPayments.ExecuteReader(); 
+0

只有當用戶選擇「確切金額」,「確切日期」和除「任何狀態」以外的任何狀態時,這才起作用。例如,如果用戶選擇「低於金額」,則將無法返回準確的結果。 – HardCode

+0

@HardCode - 你是對的。一個簡單的修改將允許你指定範圍。一個確切的值'N'只會在'N到N'的範圍內。對於像「任何狀態」這樣的東西,您只需將參數留空即可(因此返回任何狀態)。 – JDB

3

最好的解決方案是根據在搜索表單中輸入的字段,動態地將SQL查詢字符串組裝到C#代碼中。

+0

我明白。它並沒有跨越我的想法。這將是一個很好的選擇。謝謝:) – Matthew

+0

並且不要忘記使用SQL參數來傳遞值。這避免了數據中的SQL注入攻擊和撇號等問題。 –

+1

爲什麼動態查詢參數化存儲過程?存儲的特效更快,對注入攻擊更有抵抗力。 – JDB

0

一個好方法是使用您的數據庫列名作爲文本框/下拉ID。這樣,您可以使用代碼背後的ID屬性,並且可以使用循環根據您的需要構建查詢。假設你有這些建立在一個HTML表格或可循環類似其他一些結構...

string sql = "SELECT * FROM payments "; 
string field = ""; 
string value = ""; 
int parameter_count = 0; 
foreach(HtmlTableRow row in table.Rows) 
{ 
    foreach(Control c in row.Cells[1].Controls) 
    { 
     if (c is Textbox) 
     { 
      TextBox txt = c as TextBox; 
      if (txt.Text.Length > 0) 
      { 
       field = txt.ID; 
       value = txt.Text.Trim(); 
       if (parameter_count == 0) 
       { 
        sql += string.Format(" WHERE {0}='{1}' ", field, value); 
        parameter_count++; 
       } 
       else 
       { 
        sql += string.Format(" AND {0}='{1}' ", field, value); 
        parameter_count++; 
       } 
      } 
     } 
     else if (c is DropDownList) 
     { 
      DropDownList ddl = c as DropDownList; 
      if (ddl.SelectedValue.Length > 0) 
      { 
       field = ddl.ID; 
       value = ddl.SelectedValue.Trim(); 
       if (parameter_count == 0) 
       { 
        sql += string.Format(" WHERE {0}='{1}' ", field, value); 
        parameter_count++; 
       } 
       else 
       { 
        sql += string.Format(" AND {0}='{1}' ", field, value); 
        parameter_count++; 
        } 
       } 
      } 
     } 
    } 

現在,有一個明顯的缺點簡單地使用的String.format來構建查詢,主要是您可以使用SQL注入。但是,我建議拋出string.Format部分,因爲它們純粹是爲了示例的目的,以便您可以看到可以捕獲字段/值的時刻,以便構建正確的參數化查詢。這個更重要的部分就是包含這些語句的所有邏輯。它使您能夠排除空白字段,並使其不會影響查詢結果,除非它們具有值。希望這可以幫助!

+1

那麼,您將如何構建一個具有動態列名稱的防注入攻擊解決方案? – JDB