日付フィールド、[RWT010]
、[RWT010BP]
、および[RWP000]
です。しかし、Oracleでは正規化されているため、複数の行が返されるようになりました。それぞれのフィールドには、、"RWT010BP"
、または"RWP000"
に等しい[TYPE]
という名前のフィールドがあります。
あなたは考えていたので、Accessの場合と同様に、RWP000
の日付値を名前で処理したいと考えていました。あなたは正しかった、それはそれを行うための最も明白な方法です、そして私はあなたに方法を教えます。私はあなたが求めていたものを誤解しました。
これを行う1つの方法は、Accessロジックを複製するOracleストアドプロシージャを作成することです。それはあなたが尋ねた質問ではありませんが、それを行う正当な方法です。しかし、データベースが変更されてAccessバージョンよりも複雑になります。とにかくOracle SQLを何年も書いていないし、セミコロンについての恣意的な、暗黙の構文エラー空白。
だから私は、DB行からdatetimesを取得してローカル変数に入れて、C#でフィールドの代わりにそれらの変数を使ってAccessロジックを複製するC#でループを書くことです。 Accessバージョンと比較して少し冗長になりますが、時にはそれがどのようになっているのでしょうか。
int idnum = Convert.ToInt32(Console.ReadLine());
string sql = "SELECT EXPID, TYPE, DATE_LATEST FROM TRAINING_TABLE where expid =" + idnum;
// I don't know how you're using this so I'll just declare it here
// and leave that to you.
String dateLabel = "";
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = sql;
using (DbDataReader reader = cmd.ExecuteReader())
{
DateTime? RWT010 = null;
DateTime? RWT010BP = null;
DateTime? RWP000 = null;
// No need to check reader.HasRows. If it has no rows, reader.Read()
// will return false the first time, that's all.
while (reader.Read())
{
// Doesn't look to me like expid is used
//int expid = reader.GetInt32(0);
string trainType = reader.GetString(1);
DateTime trainDate = reader.GetDateTime(2);
switch (trainType) {
case "RWT010":
RWT010 = trainDate;
break;
case "RWT010BP":
RWT010BP = trainDate;
break;
case "RWP000":
RWP000 = trainDate;
break;
}
}
if (RWT010 == null || RWT010BP > RWT010) {
dateLabel = String.Format("RWT010BP: {0:d}", RWT010BP);
} else {
dateLabel = String.Format("RWT010: {0:d} & RWP000: {1:d}", RWT010, RWP000);
}
}
オリジナルのロジックは、このでした:
If RWT010 isn't null,
Do A
Otherwise, if RWT010BP > RWT010
ALSO do A
But if none of the above,
Do B
最初の二つの分岐はまったく同じことを行うので、私たちは1本の枝にそれらの両方を凝縮することができます。
「Do not Repeat Yourself」と言われています。今年からこのコードに戻って、2本の線が同じであることが必要かどうか疑問に思ったり、同じであることに気付かずにどちらか一方のみを変更したりするのは不思議です。それはちょうど混乱です。
あなたがfamiliar with String.Format()ではない場合は、それにたくさんあります。最初の引数文字列の{0}
は、「2番目の引数をここに挿入する」ことを意味します。 {1}
は「3番目を挿入する」などを意味します。中括弧の中の ":d"はオプションです。フォーマット情報として "d"をその値に渡すことを意味します。 DateTime
は "d"を "Short Date"と解釈します。
dateLabel = String.Format("RWT010BP: {0}", RWT010BP.Value.ToShortDateString());
またはこのよう:
dateLabel = "RWT010BP: " + RWT010BP.Value.ToShortDateString();
私はRWT010BP
がそれ後?
で宣言されているため、そのラインではなく、単にRWT010BP
RWT010BP.Value
を使用する必要があります。また、このようにそれを行うことができます。それはそれを "nullable"値にします。通常のDateTime
はnullにはできませんが、ここではnullを処理する必要があります。
あなたがC#6を使用している場合は、私が好むれ、このようにそれを行うことができます。私は上記のC#のバージョンがわからないので、これを使用しませんでした。コードを乱雑にする「ノイズ」を最小限に抑えてください。
dateLabel = $"RWT010BP: {RWT010BP:d}";
上記のString.Format("{0:d}", ...)
と同じ ":d"です。
もう1つ:idnum
はintですが、文字列値をSQL文字列に連結することはありません。これは大規模なセキュリティ上の脆弱性であり、ここの人々は(正しく、私は恐れている)あなたにそれを考えさえするのは非常に困難な時間を与えるでしょう。代わりに
使用OracleCommand.Parameters
、as shown in this answer。私はこの場合でも、条件付き反射と同じように、個人的に使用したでしょう。
は、あなたがあなたのC#の変数名は 'trainDate'は' trainType'の値に応じて変更したいと言っていますか?可能であれば、それはひどい考えですが、そうではありません。それとも私はあなたを誤解していますか? –
私は実際に、異なるトレーニングタイプの日付の比較を行う最も効率的な方法が何であるか尋ねたはずです。私は本当にこれで新しいことを謝ります。 –
私は効率について心配しません。クラリティははるかに重要です。ここで何が起こっているのかについての私の最初の推測では、アクセス、 'RWT010'などで、単一の行のすべての日付フィールドですが、オラクルでは、あなたが複数の行があり、各行は名前フィールドに加えて、単一の日付フィールドを持っているということです。名前フィールドは '' RWT010 "'、 '' RWT010BP ''、または '' RWP000 "'の文字列です。正しいですか? –