根据字符串值搜索int列

时间:2017-12-28 19:32:27

标签: c# sql sql-server tsql sql-server-2014

我在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

9 个答案:

答案 0 :(得分:11)

一些建议

您提供的查询需要进行优化:

  1. 首先,使用CAST(bkID AS NVARCHAR(MAX))会影响查询的性能,因为它不会使用任何索引,同时转换为NVARCHAR(MAX)也会降低性能。

  2. bkStatus是一个数字列,因此您必须使用=运算符并与数值(0 or 1 or ...)进行比较,所提供的文本值也会在{{1}中定义} tag不在数据库中,因此它们用于应用程序级别而不是数据级别。

  3. 如果您使用asp搜索包含特定数字CAST(bkID AS NVARCHAR(MAX))列(例如:搜索bkid - &gt;结果{{1 }},11,...),然后尝试转换为特定尺寸(例如:10

  4. 建议使用参数化查询以获得更好的性能并防止 Sql注入攻击。 看看@ un-lucky答案

  5. 您可以使用字典对象来存储与关键字

  6. 相关的ID值

    实施例

    注意:使用CAST和Like不会使用任何索引,此示例基于您的要求(我尝试将我提供的建议与其他建议结合起来)

    11

    此外,如果BkID是整数列,最好使用

    CAST(bkID as NVARCHAR(10)

    参考文献&amp;有用的链接

答案 1 :(得分:7)

因此,您需要一个搜索框,用户可以使用bkIDbkSlotbkStatus进行搜索,如果搜索文字为BookedPending我们必须添加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();
     }
}

请注意以下事项:

  • 如果您想要包含bookPend等bkStatus过滤器,那么您必须使用.Contains().StartsWith()代替{更改条件{1}}
  • statusCode使用.ToLower()进行初始化,以避免基于-1的所有其他值的过滤器

答案 2 :(得分:4)

您可以使用declare函数创建一个列表为bkStatus的临时表。

使用bkstatus作为外键创建查询会更容易。之后,您不必再使用castlike功能了。这将是一个有点低效的。

您可以尝试以下代码:

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表,在那里有bkStatusbkStatusTitle列并将其加入{{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查询。

'%' + 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 答案中指出的参数。我们可以在这里讨论最佳实践,所以我建议您查看以下文章:

  1. Lookup tables:您声明bkStatus类型为INT大豆我认为您可以拥有比预订待定更多的选项例如:保留已取消。在这种情况下,您添加的每个选项的实际代码可能会变得越来越不整洁
  2. Best practices for using ADO.NET:您没有指定 如何从前端访问数据库。即使这篇文章已存在多年,但其大部分内容仍然是最新的。我认为这可能会有所帮助。
  3. Building Better Entity Framework:如果您使用Entity Framework访问数据库。
  4. 希望它有所帮助。

答案 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的东西吗?