2012-10-18 48 views
1

我在C#中使用t-sql select查詢時遇到了一些麻煩。查詢如下:當使用IN時,T-SQL Select語句返回零行

@"SELECT * FROM 
(SELECT *, ROW_NUMBER() OVER (ORDER BY id) as row_number 
FROM [mytable]) t0 
WHERE row_number BETWEEN @skip and @take 
AND 
uploadDate IN (@years) 
AND NOT photoId IN (@shownPhotos) 
ORDER BY NEWID()"; 

cmd.Parameters.Add("@skip", SqlDbType.Int).Value = skip; 
cmd.Parameters.Add("@take", SqlDbType.Int).Value = take; 
cmd.Parameters.Add("@shownPhotos", SqlDbType.VarChar).Value = shownPhotos; 
cmd.Parameters.Add("@years", SqlDbType.VarChar).Value = years; 

該方法採用四個參數:跳過計數,取數,shownPhotos(其中包含這些年來,以顯示從照片逗號分隔字符串)(其中包含有照片的身份證逗號分隔字符串),年

所以基本上我希望它從我的數據庫返回的照片匹配任何從逗號分隔的字符串中的任何年份,並沒有顯示。

問題(我認爲)是我的參數是字符串,所以它們被解釋爲'1234,567,890'和'2011,2012'。在SQL服務器管理工​​具中運行查詢時,如果沒有,它工作正常。

任何人都有解決這個問題嗎? :-)

非常感謝!

更新代碼:

// Create datatables 
      DataTable yearsTable = new DataTable(); 
      yearsTable.Columns.Add("YearID", typeof(string)); 
      yearsTable.Columns.Add("Year", typeof(string)); 

      foreach(string year in years.Split(',')) 
       yearsTable.Rows.Add(new object[] { year, year }); 

      using (var conn = new SqlConnection(GlobalSettings.DbDSN)) 
      { 
       conn.Open(); 
       using (var cmd = conn.CreateCommand()) 
       { 
        cmd.CommandType = CommandType.Text; 
        cmd.CommandText = 
         @"SELECT * FROM 
          (SELECT *, ROW_NUMBER() OVER (ORDER BY id) as row_number 
          FROM [mytable]) t0 
          WHERE row_number BETWEEN @skip and @take 
          AND 
          uploadedDate IN (@years)        
          ORDER BY NEWID()"; 

        SqlParameter skipParam = cmd.Parameters.AddWithValue("@skip", skip); 
        skipParam.SqlDbType = SqlDbType.Int; 

        SqlParameter takeParam = cmd.Parameters.AddWithValue("@take", take); 
        takeParam.SqlDbType = SqlDbType.Int; 

        SqlParameter yearsParam = cmd.Parameters.AddWithValue("@years", yearsTable); 
        yearsParam.SqlDbType = SqlDbType.Structured; 
        yearsParam.TypeName = "dbo.MyTableType"; 


        var reader = cmd.ExecuteReader();       
       } 

回答

1

事實上,你的IN被解釋爲「在這組1值」,即你有什麼是相同的:

AND uploadDate = @years 
AND NOT photoId = @shownPhotos 

評估爲字符串'1234,567,890''2011,2012'上的常規字符串相等。在TSQL級別,一個常見的技巧是編寫一個「分割」UDF,將單個varchar分隔成多個行值。許多圖書館也有這方面的工具。例如,在"dapper"我們添加一個語法技巧來預展開它們,即

int[] years = {2011,2012}; 
int[] shownPhotos = {1234,567,890}; 
int skip = 0, take = 10; 
var rows = connection.Query<RowType>(
    @"SELECT * FROM 
    (SELECT *, ROW_NUMBER() OVER (ORDER BY id) as row_number 
    FROM [mytable]) t0 
    WHERE row_number BETWEEN @skip and @take 
    AND uploadDate IN @years 
    AND NOT photoId IN @shownPhotos 
    ORDER BY NEWID()", new {skip,take,years,shownPhotos}).ToList(); 

注缺乏旁邊IN,我們解釋爲括號「這出自己」到圖書館,然後做正是你想要的。這實際上將被評估爲:

AND uploadDate IN (@years0,@years1) 
    AND NOT photoId IN (@shownPhotos0,@shownPhotos1,@shownPhotos2) 

其中@years0具有價值2011@years1具有價值2012

+0

我喜歡Marc的解決方案,但問題是我在這裏使用字符串而不是int: - /所以我想這不是一個選項? – bomortensen

+0

@bomortenson不是問題 - 使用字符串[]而不是int [] - 它會正常工作。 –

+0

哦,所以我必須安裝精簡版來做到這一點? :) – bomortensen

2

你是對你的問題的評價 - @shownphotos和@years將被解釋爲一個字符串。

表值參數就是答案

http://msdn.microsoft.com/en-us/library/bb675163.aspx

(在參數化的SQL語句幹得好 - 不通過連接字符串的SQL語句被誘惑解決這個問題!)

+1

** **如果他使用SQL Server ** 2008或更新** - 然後是... –

+0

podiluska您好,感謝您的投入:-)我不確定從目前的參數化到鏈接中的示例有什麼不同,但我現在可能只是累了眼睛;-) – bomortensen

+0

@bomortensen關鍵是參數數據類型'SqlDbType.Structured' - 請參閱部分「將表值參數傳遞給參數化SQL語句」 – podiluska

-1

你看上去比較針對一組年整個日期。

爲什麼不提取只是一年和比較?

@"SELECT * FROM 
(SELECT *, ROW_NUMBER() OVER (ORDER BY id) as row_number 
FROM [mytable]) t0 
WHERE row_number BETWEEN @skip and @take 
AND 
DATEPART(yyyy,uploadDate) IN (@years) 
AND NOT photoId IN (@shownPhotos) 
ORDER BY NEWID()"; 

瞭解更多關於DATEPART這裏:http://www.w3schools.com/sql/func_datepart.asp

+0

您可能需要鍵入將DATEPART結果轉換爲VARCHAR以使其工作。 – tempidope