1

我在 C# 中使用 t-sql 选择查询时遇到了一些问题。查询如下:

@"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;

该方法有四个参数:skip count、take count、showedPhotos(逗号分隔的字符串,包含照片 ID)、years(逗号分隔的字符串,包含显示照片的年份)

所以基本上我希望它从我的数据库中返回与逗号分隔字符串中的任何年份相匹配且尚未显示的照片。

问题(我认为)是我的参数是字符串,因此它们被解释为“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();                        
                }
4

3 回答 3

2

您对问题的评估是正确的 - @shownphotos 和 @years 将被解释为单个字符串。

表值参数就是答案

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

(在参数化 SQL 语句方面做得很好 - 不要试图通过连接字符串中的 SQL 语句来解决这个问题!)

于 2012-10-18T12:40:29.460 回答
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,等等。

于 2012-10-18T12:44:41.450 回答
-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

于 2012-10-18T12:47:05.593 回答