2016-11-11 33 views
0

的SQL Server 2016的.Net 4.5.2 C#檢查變量exists..inline SQL

我說這方面,我使用Northwind數據庫,以顯示我想要實現的。請不要評論Northwind數據庫。這只是我將要做的一個例子。

我正在使用ADO.Net來執行內聯SQL。我的困境是我將有可能傳遞給sql查詢的可選參數。下面是C#:

var city = ""; 
var state = "tx"; 
var sqlQuery = " 
     if exists @City 
     begin 
     select * from Customers where city = @City and [email protected]; 
     end 
     else 
     begin 
     select * from Customers where [email protected]; 
     end 
    "; 

var conn = new SqlConnection("Server=(local);DataBase=Northwind;Integrated Security=SSPI"); 
conn.Open(); 
SqlCommand cmd = new SqlCommand(sqlQuery, conn); 

if (!string.IsNullorEmpty(city)) 
{ 
    SqlParameter param = new SqlParameter(); 
    param.ParameterName = "@City"; 
    param.Value   = city; 
    cmd.Parameters.Add(param); 
} 

if (!string.IsNullorEmpty(state)) 
{ 
    SqlParameter param = new SqlParameter(); 
    param.ParameterName = "@State"; 
    param.Value   = state; 
    cmd.Parameters.Add(param); 
} 

var reader = cmd.ExecuteReader(); 

正如你所看到的,可變的城市是空白的,因此參數@city不會傳遞到SQL查詢,但該變量狀態不爲空,以便@state參數將被傳遞到查詢。請記住,@City不會一直是空白的。我在sql中檢查了是否存在@City,但這不起作用。如何檢查sql查詢是否存在@City,@State或其他可能傳遞的參數?如果我能弄清楚那部分,我可以處理sql中需要做的事情。感謝任何和所有的幫助。

P.S.我無法使用存儲過程。

+0

爲什麼你不能使用存儲過程?這是一個奇怪的限制。 –

+0

我同意。我的工作把我的手銬。我們使用所有內聯sql。我不確定這是可能的他們想要什麼 – BoundForGlory

+0

這是完全有可能的。看到我的答案。我對你在這樣荒謬的限制下工作的地方感到不好。我以前聽說過這種事情,總是歸結爲一些誤導並能夠做出如此徹底的授權的人。最糟糕的部分是,同一個人也通常死定了他們的誤導信念,並拒絕理性。你要麼處理這種廢話,要麼清理你的簡歷。 –

回答

2
select * 
from 
    Customers 
where 
    [email protected] 
    AND (city = @City 
     OR ISNULL(@City,'') = '') 

我會推薦以上,你可以在1選擇語句而不必使用IF控制方法。它會測試城市,但它也會說@City是否爲空,然後返回它,因爲只有其中一個條件可以是真實的,一次你永遠不會得到你不想要的結果。要使用控制方法,你可以不喜歡以下,

IF ISNULL(@City,'') <> '' 
BEGIN 
    select * from Customers where city = @City and [email protected]; 
END 
ELSE 
BEGIN 
    select * from Customers where [email protected]; 
END 

但是又是第一個例子是更標準,更是更少的代碼,所以我會建議。

編輯: 你必須每次傳遞參數。否則,你會改變你的C#代碼中的SQL語句,而不是在你的SQL代碼中。

接下來,您將實際傳遞一個空字符串,而不是一個NULL值,查看您的作業var city = "";,因此您可以切換到測試。

根本不傳遞參數的問題是您的SQL語句將使用您沒有聲明的變量,如果您不添加參數值。因此,標準的方法是始終傳遞變量並使用上面第一個SQL語句。如果你真的想以不同的方式做到這一點,那麼你將需要使用C#控制流以不同的方式構建你的SQL字符串。

標準方式:

var city = ""; 
var state = "tx"; 
var sqlQuery = " 
    select * 
    from 
     Customers 
    where 
     [email protected] 
     AND (city = @City 
      OR ISNULL(@City,'') = '') 
"; 

var conn = new SqlConnection("Server=(local);DataBase=Northwind;Integrated Security=SSPI"); 
conn.Open(); 

SqlCommand cmd = new SqlCommand(sqlQuery, conn); 

SqlParameter param = new SqlParameter(); 
param.ParameterName = "@City"; 
param.Value   = city; 
cmd.Parameters.Add(param); 

SqlParameter param = new SqlParameter(); 
param.ParameterName = "@State"; 
param.Value   = state; 
cmd.Parameters.Add(param); 

var reader = cmd.ExecuteReader(); 

這樣做沒有通過參數的方式是通過C#控制流動態生成SQL語句:

var city = ""; 
var state = "tx"; 
var sqlQuery = " 
    select * 
    from 
     Customers 
    where 
     [email protected] 
"; 

if (!string.IsNullorEmpty(city)) 
{ 
    sqlQuery += " 
      AND [email protected]"; 
} 

var conn = new SqlConnection("Server=(local);DataBase=Northwind;Integrated Security=SSPI"); 
conn.Open(); 

SqlCommand cmd = new SqlCommand(sqlQuery, conn); 

if (!string.IsNullorEmpty(city)) 
{ 
    SqlParameter param = new SqlParameter(); 
    param.ParameterName = "@City"; 
    param.Value   = city; 
    cmd.Parameters.Add(param); 
} 

SqlParameter param = new SqlParameter(); 
param.ParameterName = "@State"; 
param.Value   = state; 
cmd.Parameters.Add(param); 

var reader = cmd.ExecuteReader(); 

要展開一個多一點,爲什麼你有must declare scalar variable @city當你沒有傳遞參數時,是因爲c#中的參數定義是什麼定義了SQL中的變量。所以:如果你省略這一步,你正在使用,如果在城市無功控制流程省略了變量定義和SQL將會失敗做

DECLARE @City VARCHAR(50) 
SET @City = value of city var. 

所以:

SqlParameter param = new SqlParameter(); 
param.ParameterName = "@City"; 
param.Value   = city; 
cmd.Parameters.Add(param); 

基本上做到這一點的SQL 。因此,雖然參數的值可以是可選的,但如果參數在SQL語句中被引用,則參數本身不是選項。

另請注意,您在參數定義中使用隱式數據類型,您應該明確定義數據類型!

+0

必須聲明標量變量「@City」。 – BoundForGlory

+0

@BoundForGlory你應該總是將可變天氣傳遞給Null或Not。你有另一個問題,雖然你傳遞一個空字符串不是一個空,所以我更新,以反映如何檢查。 – Matt

+0

我的要求是如果變量爲null,則不傳遞參數。那就是爲什麼我按照自己的方式編寫代碼。我甚至嘗試過嘗試,但失敗了。 – BoundForGlory

0

當你通過sql進行傳遞時,使用可選參數是一項挑戰。它確實無助於讓你的代碼更好。選項參數在存儲過程中非常有用,但在傳遞查詢中,它比付出更多的努力。處理這個問題的最好方法是始終傳遞參數。但是你可以傳遞一個DBNull並在你的查詢中處理它。

我也強烈建議你開始用USING語句包裝你的iDisposable對象。尤其是連接和命令等。您不想連接您的連接池,因爲您錯過了Dispose通話。

這裏有一種方法可以很乾淨地管理這種類型的東西。

var sqlQuery = "select * 
from Customers 
where 
(
    state = @State 
    OR 
    @state is null 
) 
AND 
(
    city = @City 
    OR 
    @City is null 
)"; 

using (SqlConnection conn = new SqlConnection("Server=(local);DataBase=Northwind;Integrated Security=SSPI")) 
{ 
    conn.Open(); 
    using(SqlCommand cmd = new SqlCommand(sqlQuery, conn)) 
    { 
     SqlParameter param = new SqlParameter(); 
     param.ParameterName = "@City"; 
     if (string.IsNullorEmpty(city)) 
     { 
      param.value = DBNull.Vale; 
     } 
     else 
     { 
      param.Value = city; 
     } 
     cmd.Parameters.Add(param); 

     SqlParameter param = new SqlParameter(); 
     param.ParameterName = "@State"; 
     if(string.IsNullorEmpty(state)) 
     { 
      param.value = DBNull.Vale; 
     } 
     else 
     { 
      param.Value = state; 
     } 
     cmd.Parameters.Add(param); 
     } 

    } 
} 
+0

感謝您的意見,並相信我,如果我擁有我工作的公司,我會這樣做。這是一項工作要求,我不確定他們希望我做什麼。 – BoundForGlory

+0

這是一項工作要求,您不能每次都將參數傳遞給您的傳遞查詢。這完全沒有意義。我感覺到你的痛苦,感受到你的挫敗感,這是來自一個掌權者的一些愚蠢的授權,幾乎沒有理解這是如何運作的。唯一我能看到使你的參數可選的是在c#中爲每個可能的組合創建一個分支,並且只包含與該路徑相關的參數。談論噩夢! –