我在C#中使用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;
该方法有四个参数:跳过计数,计数,显示照片(包含照片ID的逗号分隔字符串),年份(逗号分隔的字符串,其中包含显示照片的年份)
所以基本上我希望它能从我的数据库中返回照片,这些照片与逗号分隔的字符串中的任何年份相匹配,并且尚未显示。
问题(我认为)是我的参数是字符串,因此它们被解释为'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();
}
答案 0 :(得分:2)
您对问题的评价是对的 - @shownphotos和@years将被解释为单个字符串。
表值参数是答案
http://msdn.microsoft.com/en-us/library/bb675163.aspx
(在完成SQL语句参数化方面做得很好 - 不要试图通过连接字符串中的SQL语句来解决这个问题!)
答案 1 :(得分: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
等。
答案 2 :(得分:-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