Это выглядит как оригинальный логики доступа имеет один DB ряд с тремя поля даты, [RWT010]
, [RWT010BP]
и [RWP000]
. Но в Oracle это нормализовано, поэтому вы возвращаете несколько строк, каждая из которых имеет поле datetime с именем [DATE_LATEST]
, а затем поле с именем [TYPE]
, которое равно "RWT010"
, "RWT010BP"
или "RWP000"
.
И вы думали, что хотите использовать эти значения даты по имени, как в Access. Вы были правы, это самый ясный способ сделать это, и я покажу вам, как это сделать. Я неправильно понял то, что вы просили.
Один из способов сделать это - написать хранимую процедуру Oracle, которая дублирует логику доступа. Это не вопрос, который вы задали, но это законный способ сделать это. Тем не менее, это было бы сложнее, чем версия Access из-за изменения в базе данных, и в любом случае я не писал Oracle SQL в течение многих лет, и у меня нет сервера Oracle, который может дать мне произвольные критические синтаксические ошибки о точках с запятой и пробелы.
То, что я собираюсь сделать, это написать цикл в C#, чтобы захватить данные из строк DB и поместить их в локальные переменные, а затем дублировать логику доступа на 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
Первые две ветви сделать то же самое, так что мы можем сконденсировать их обоих в одну ветвь.
«Не повторяйте себя», как говорится. Вы не хотите возвращаться к этому коду через год, задайтесь вопросом, должны ли эти две строки быть одинаковыми, а затем угадать неправильно или не заметить, что они одинаковы и только меняют одно или другое. Это просто беспорядок.
Если вы не familiar with String.Format(), там много чего. В строке первого аргумента {0}
означает «вставить здесь второй аргумент»; {1}
означает «вставить третий» и т. Д. «: D» внутри фигурных скобок необязателен; это означает передать «d» в качестве информации о формате в значение его вставки. DateTime
будет интерпретировать, что «d» означает «короткая дата».Вы также можете сделать это следующим образом:
dateLabel = String.Format("RWT010BP: {0}", RWT010BP.Value.ToShortDateString());
Или так:
dateLabel = "RWT010BP: " + RWT010BP.Value.ToShortDateString();
Я должен использовать RWT010BP.Value
в этой строке вместо просто RWT010BP
потому RWT010BP
объявлен с ?
после него. Это делает его «нулевым» значением. Обычный DateTime
не может быть нулевым, но здесь нам нужно разместить нули.
Если вы используете C# 6, вы можете сделать это так, что я предпочитаю. Я не использовал его выше, потому что я не знаю, какую версию C# вы используете. Всегда предпочитайте наименьшее количество «шума», загромождающего код.
dateLabel = $"RWT010BP: {RWT010BP:d}";
Это тот же ": д", как в String.Format("{0:d}", ...)
выше.
Еще одна вещь:idnum
- это int, но никогда не объединяет строковое значение в строку SQL. Это серьезная уязвимость в плане безопасности, и люди здесь (по правде говоря, я боюсь) дают вам очень тяжелое время даже для размышлений.
Использовать OracleCommand.Parameters
вместо, as shown in this answer. Я бы использовал это, даже в этом случае, лично, как условный рефлекс.
Вы хотите, чтобы ваше имя переменной C# 'trainDate' изменилось в соответствии со значением' trainType'? Это было бы ужасной идеей, если бы это было возможно, но это не так. Или я неправильно понимаю вас? –
Наверное, я действительно должен был спросить, что будет самым эффективным способом сравнения дат разных типов обучения. Прошу прощения, я действительно новичок в этом. –
Я бы не стал беспокоиться об эффективности. Ясность гораздо важнее. Мое первое предположение о том, что происходит здесь, заключается в том, что в Access, RWT010 и т. Д. Все поля даты в одной строке, но в Oracle у вас несколько строк, и каждая строка имеет поле имени плюс одно поле даты. И поле имени - это строка, которая может быть «RWT010», «RWT010BP» или «RWP000», «Правильно ли это? –