我在sql server 2014中有一个View View_Booking
:
bkID bkSlot bkStatus
---- ------ --------
2 Lunch 1
4 Lunch 1
6 Dinner 0
7 Lunch 1
在c#中,我使用了gridview并将bkStatus
转换为字符串,如:
<asp:Label ID="lblStatus" Text='<%# (Eval("bkStatus")+"" == "1") ? "Booked" : "Pending" %>'
... ></asp:Label>
bkID bkSlot bkStatus
---- ------ --------
2 Lunch Booked
4 Lunch Booked
6 Dinner Pending
7 Lunch Booked
现在我正在使用此查询搜索View:
SELECT * FROM View_Booking
WHERE CAST(bkID AS NVARCHAR(MAX)) LIKE '%" + keyword + "%'
OR bkSlot LIKE '%"+keyword+"%'
OR bkStatus LIKE << ? >>
但是不知道如何搜索从c#传递为 string 的bkStatus
,而在sql中它是 int ?
答案 0 :(得分:11)
您提供的查询需要进行优化:
首先,使用CAST(bkID AS NVARCHAR(MAX))
会影响查询的性能,因为它不会使用任何索引,同时转换为NVARCHAR(MAX)
也会降低性能。
bkStatus
是一个数字列,因此您必须使用=
运算符并与数值(0 or 1 or ...)
进行比较,所提供的文本值也会在{{1}中定义} tag不在数据库中,因此它们用于应用程序级别而不是数据级别。
如果您使用asp
搜索包含特定数字的CAST(bkID AS NVARCHAR(MAX))
列(例如:搜索bkid
- &gt;结果{{1 }},1
,1
,...),然后尝试转换为特定尺寸(例如:10
)
建议使用参数化查询以获得更好的性能并防止 Sql注入攻击。 看看@ un-lucky答案
您可以使用字典对象来存储与关键字
注意:使用CAST和Like不会使用任何索引,此示例基于您的要求(我尝试将我提供的建议与其他建议结合起来)
11
此外,如果BkID是整数列,最好使用
CAST(bkID as NVARCHAR(10)
答案 1 :(得分:7)
因此,您需要一个搜索框,用户可以使用bkID
,bkSlot
或bkStatus
进行搜索,如果搜索文字为Booked
或Pending
我们必须添加bkStatus
的过滤器,它将是数据库中的整数字段。对?我在这里要提到的更多事情是using
的用法以及用于查询更智能和更安全的执行方式的参数化。所以我建议建立并执行如下所示的查询:
int statusCode = -1;
if(keyword.ToLower() == "booked")
statusCode = 1;
else if(keyword.ToLower() == "pending")
statusCode = 0;
string querySql = " SELECT * FROM View_Booking" +
" WHERE CAST(bkID AS NVARCHAR(MAX)) LIKE @bkID" +
" OR bkSlot LIKE @bkSlot" +
" OR bkStatus = @status";
using (SqlConnection dbConn = new SqlConnection("connectionString here"))
{
dbConn.Open();
using (SqlCommand sqlCommand = new SqlCommand(querySql, dbConn))
{
sqlCommand.Parameters.Add("@bkID", SqlDbType.VarChar).value ="%" + keyword + "%";
sqlCommand.Parameters.Add("@bkSlot", SqlDbType.VarChar).value ="%" + keyword + "%";
sqlCommand.Parameters.Add("@status", SqlDbType.int).value = statusCode;
sqlCommand.ExecuteNonQuery();
}
}
请注意以下事项:
book
,Pend
等bkStatus过滤器,那么您必须使用.Contains()
或.StartsWith()
代替{更改条件{1}} .ToLower()
进行初始化,以避免基于-1
的所有其他值的过滤器答案 2 :(得分:4)
您可以使用declare
函数创建一个列表为bkStatus
的临时表。
使用bkstatus
作为外键创建查询会更容易。之后,您不必再使用cast
或like
功能了。这将是一个有点低效的。
您可以尝试以下代码:
declare @bkstatus table (number int primary key , bkstatus varchar(10) )
insert into @bkstatus (number , bkstatus)
values ( 0 , 'Pending'), (1 , 'Booked')
然后使用此查询:
SELECT * FROM View_Booking v
INNER JOIN @bkstatus b on v.bkstatus = b.number
WHERE b.bkstatus = @keyword
答案 3 :(得分:4)
使用CHOOSE()解码bkStatus和TRY_CONVERT()以测试bkID的另一个选项。
示例强>
Declare @KeyWord varchar(50) = 'Pending';
Select *
From View_Booking
Where bkID = try_convert(int,@KeyWord)
or bkSlot like '%'+@KeyWord+'%'
or choose(bkStatus+1,'Pending','Booked')=@KeyWord
<强>返回强>
bkID bkSlot bkStatus
6 Dinner 0
答案 4 :(得分:3)
如果keyword
是状态名称而不是状态ID,我会创建BookingStatus
表,在那里有bkStatus
和bkStatusTitle
列并将其加入{{1 }}。你可以轻松地在View_Booking
上做点赞。
bkStatusTitle
如果SELECT * FROM View_Booking
WHERE CAST(bkID AS NVARCHAR(16)) LIKE '%' + @keyword + '%'
OR bkSlot LIKE '%' + @keyword + '%'
OR bkStatusTitle LIKE '%' + @keyword + '%'
是keyword
的字符串表示形式,我只会看看这些值是否相同。
作为旁注,构建SQL查询将用户输入连接到bkStatus
之类是一个坏主意。这对SQL注入攻击是开放的。最好使用SQL参数将用户输入传递给SQL查询。 1}}在SQL位和C#中使用下面的例子会更加安全。
'%' + keyword + '%'
参数化查询还为多个请求提供相同查询文本的好处,这反过来又允许SQL Server缓存SQL执行计划并重用它们,从而提供稍好的性能。
答案 5 :(得分:3)
你的bkStatus是整数。在视图中,您将整数值转换为用户有意义的字符串。到目前为止一切都好。现在,对于用户搜索所有你需要做的是将你的翻译从字符串转换为整数并搜索整数。
保持简单
searchStatusKey = yourVariableHodingTheString == "Booked" ? 1 : 0;
但是,为了避免在多个地方出现繁琐的错误和无痛的代码升级(比如因为他们决定在那里添加另一个状态),我建议在这里使用转换表。类似于HashMap(关联数组)。
var statusMap = new Dictionary<int, string> {
{ 0, "Pending" },
{ 1, "Booked" },
/* can always add more pairs in the future as needed */
};
现在,假设您的参数位于名为searchStatus
searchStatusKey = statusMap.FirstOrDefault(x => x.Value == searchStatus).Key;
现在在searchStatusKey
值的where部分提供bkStatus参数并完成。
select * from View_Booking where bkStatus = << ? >>
答案 6 :(得分:2)
我将只关注你问题的这一部分(这是问题本身吗?):
但是不知道如何搜索bkStatus,它是从c#中作为字符串传递的,而它在sql中是一个int?
在 SQL 中处理它的一种方法是在CASE子句的帮助下。在你的具体情况下,你可以(并不意味着应该)做类似的事情:
SELECT * FROM View_Booking
WHERE CAST(bkID AS NVARCHAR(MAX)) LIKE '%" + keyword + "%'
OR bkSlot LIKE '%"+keyword+"%'
OR bkStatus = CASE '%"+keyword+"%' WHEN 'Booked' THEN CAST(1 AS INT) WHEN 'Pending' THEN CAST(0 AS INT) WHEN ... THEN ... ELSE ... END'
但我建议使用 @ un-lucky 答案中指出的参数。我们可以在这里讨论最佳实践,所以我建议您查看以下文章:
bkStatus
类型为INT
大豆我认为您可以拥有比预订或待定更多的选项例如:保留或已取消。在这种情况下,您添加的每个选项的实际代码可能会变得越来越不整洁。 希望它有所帮助。
答案 7 :(得分:2)
为enum
创建BookingStatus
并创建一个接受字符串并返回枚举值的函数。请参阅以下代码。
public enum BookingStatus {
[Description("Pending")]
Pending = 0,
[Description("Booked")]
Booked = 1
}
现在功能如下,
public static T GetValueFromDescription<T>(string p_description)
{
var type = typeof(T);
if (!type.IsEnum) throw new InvalidOperationException();
foreach (var field in type.GetFields())
{
var attribute = Attribute.GetCustomAttribute(field,
typeof(DescriptionAttribute)) as DescriptionAttribute;
if (attribute != null)
{
if (attribute.Description == p_description)
return (T)field.GetValue(null);
}
else
{
if (field.Name == p_description)
return (T)field.GetValue(null);
}
}
throw new ArgumentException("Not found.", "description");
// or return default(T);
}
现在在sql查询的参数中,使用参数"Booked"
或"Pending"
调用此函数,它将返回枚举BookingStatus.Booked
。您可以轻松地从中提取int
值。
(int)BookingStatus.Booked // will give 1
答案 8 :(得分:2)
看起来您正试图在多个列中自由搜索。这是一个非常常见的问题,在动态搜索条件下www.Sommarskog.se可以找到真实解决方案。
您的解决方案看起来好像容易受到SQL注入攻击。我可以建议你实现类似于存储过程search_orders_3的东西吗?