ビューがありますView_Booking
SQL Server 2014の場合:
bkID bkSlot bkStatus
---- ------ --------
2 Lunch 1
4 Lunch 1
6 Dinner 0
7 Lunch 1
C#では、グリッドビューを使用して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
今、私はこのクエリを使用してビューを検索しています:
SELECT * FROM View_Booking
WHERE CAST(bkID AS NVARCHAR(MAX)) LIKE '%" + keyword + "%'
OR bkSlot LIKE '%"+keyword+"%'
OR bkStatus LIKE << ? >>
しかし、SQLでintであるときに、c#からstringとして渡されるbkStatus
を検索する方法がわかりませんか?
指定したクエリは最適化する必要があります:
まず、CAST(bkID AS NVARCHAR(MAX))
を使用するとクエリのパフォーマンスに影響します。インデックスを使用しないため、NVARCHAR(MAX)
にキャストするとパフォーマンスが低下します。
bkStatus
は数値列であるため、=
演算子を使用して数値(0 or 1 or ...)
と比較する必要があります。また、提供されるテキスト値は、データベースではなくasp
タグで定義されているため、データレベルではなく、アプリケーションレベル。
特定の数字を含むbkid
列を検索するためにCAST(bkID AS NVARCHAR(MAX))
を使用している場合(例:1
の検索->結果1
、10
、11
,. ..)、特定のサイズにキャストしてみます(例:CAST(bkID as NVARCHAR(10)
)
パフォーマンスを向上させ、Sqlインジェクション攻撃を防ぐために、パラメーター化されたクエリを使用することをお勧めします。 @ un-lucky answerを見てください
辞書オブジェクトを使用して、キーワードに関連するID値を保存できます
注:CASTやLikeを使用してもインデックスは使用されません。この例は要件に基づいています(私が提供した推奨事項を他の推奨事項と組み合わせようとしました)
var dicStatus = new Dictionary<int, string> {
{ 0, "Pending" },
{ 1, "Booked" },
{ 2, "Cancelled" }
// ...
};
string querySql = " SELECT * FROM View_Booking" +
" WHERE CAST(bkID AS NVARCHAR(10)) LIKE @bkID" +
" OR bkSlot LIKE @bkSlot" +
" OR bkStatus = @status";
using (SqlConnection dbConn = new SqlConnection(connectionString))
{
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 = dicStatus.FirstOrDefault(x => x.Value == keyword).Key;
sqlCommand.ExecuteNonQuery();
}
}
また、BkIDが整数列の場合は、使用することをお勧めします
sqlCommand.Parameters.Add("@bkID", SqlDbType.Int).value = (Int)keyword ;
したがって、ユーザーが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()
を使用して、それに応じて条件を変更する必要があります。代わりに.ToLower()
-1
_で初期化され、他のすべての値に対するbkStatus
ベースのフィルターを回避します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
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
keyword
がステータス名であり、ステータスIDではない場合、BookingStatus
テーブルを作成し、そこにbkStatus
列とbkStatusTitle
列を作成して、_View_Booking
_。その後、bkStatusTitle
でLIKEを簡単に実行できます。
_SELECT * FROM View_Booking
WHERE CAST(bkID AS NVARCHAR(16)) LIKE '%' + @keyword + '%'
OR bkSlot LIKE '%' + @keyword + '%'
OR bkStatusTitle LIKE '%' + @keyword + '%'
_
keyword
がbkStatus
の文字列表現になる場合、値が同じかどうかを確認します。
補足として、_'%' + keyword + '%'
_のようにユーザー入力を連結してSQLクエリを作成することはお勧めできません。これはSQLインジェクション攻撃にさらされています。 SQLパラメータを使用して、ユーザー入力をSQLクエリに渡すことをお勧めします。 SQLビットとC#で_'%' + @keyword + '%'
_を使用すると、以下の例のようなものがはるかに安全になります。
_sqlCommand.Parameters.Add("@keyword", SqlDbType.VarChar, 1000);
sqlCommand.Parameters["@keyword"].Value = searchText;
_
パラメータ化されたクエリには、複数の要求に対して同じクエリテキストを使用できるという利点もあります。これにより、SQL ServerはSQL実行プランをキャッシュして再利用できるため、パフォーマンスがわずかに向上します。
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 = << ? >>
私はあなたの質問のこの部分にのみ焦点を当てます(それ自体が質問ですか?):
しかし、それがSQLのintであるときにc#から文字列として渡されるbkStatusを検索する方法がわかりませんか?
[〜#〜] sql [〜#〜]でこれに対処する1つの方法は、 [〜#〜 ] 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'sの回答に示されているように、パラメータの使用をお勧めします。ここでは、ベストプラクティスに関して説明できることはまだまだたくさんあるため、次の記事をご覧になることをお勧めします。
bkStatus
のタイプはINT
であると述べましたが、Bookedよりも多くのオプションがあると思いますまたは保留、例:予約済みまたはキャンセル。その場合、実際のコードは、追加するオプションごとにますます乱雑になります。それが役に立てば幸い。
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
複数の列を自由に検索しようとしているように見えます。これは非常に一般的な問題であり、実際のソリューションは、動的検索条件の www.Sommarskog.se にあります。
ソリューションは、SQLインジェクションに対して脆弱であるかのように見えます。ストアドプロシージャsearch_orders_3に似たものを実装することを提案できますか?