【问题标题】:name variable from oracle sql string value in c#c#中来自oracle sql字符串值的名称变量
【发布时间】:2017-07-13 02:45:50
【问题描述】:

这是我在 C# 中的第一个项目。我在 Access VBA 方面有一点经验。我想将我的应用程序移至独立程序。我正在查询一个包含培训类型和日期的表。我想根据执行日期来比较一些类型的培训。三种训练类型分别是 RWT010、RWP000 和 RWT010BP。如果 RWT010BP 存在并且更新,它是我唯一需要的。否则我需要 RWT010 和 RWP000。我已经想出了如何将值加载到变量中,但我需要能够使用它们。我希望 dateTime 值的名称是同一行的 trainType。这样我就可以比较它们并输出正确的组合。

我的旧访问逻辑如下所示:

LABEL_DATE: IIf(IsNull([RWT010]),"RWT010BP: " & _
     Format([RWT010BP],"Short Date"),IIf([RWT010BP]>[RWT010],"RWT010BP: " & _
     Format([RWT010BP],"Short Date"),"RWT010: " & _
     Format([RWT010],"Short Date") & " & " & "RWP000: " & _
     Format([RWP000],"Short Date")))

这是我在 c# 中的进展:

Console.Write("Enter ID: ");
        int idnum = Convert.ToInt32(Console.ReadLine());
        string sql = "SELECT EXPID, TYPE, DATE_LATEST FROM TRAINING_TABLE where expid =" + idnum;



        OracleCommand cmd = new OracleCommand();

       cmd.Connection = conn;

        cmd.CommandText = sql;

        using (DbDataReader reader = cmd.ExecuteReader())
        {
            if (reader.HasRows)
            {

                while (reader.Read())
                {

                    int expid = reader.GetInt32(0);
                    string trainType = reader.GetString(1);
                    DateTime trainDate = reader.GetDateTime(2); 

【问题讨论】:

  • 你是说你想让你的C#变量名trainDate根据trainType的值改变?如果可能的话,那将是一个糟糕的主意,但事实并非如此。还是我误会了你?
  • 我想我真的应该问一下比较不同培训类型的日期最有效的方法是什么。抱歉,我真的很陌生。
  • 我不会担心效率。清晰度更为重要。我对这里发生的事情的第一个猜测是,在 Access 中,RWT010 等都是单行中的日期字段,但在 Oracle 中,您有多行,每行都有一个名称字段和一个日期字段。而name字段是一个字符串,可以是"RWT010""RWT010BP""RWP000",对吗?

标签: c# sql oracle vba


【解决方案1】:

看起来原始的 Access 逻辑有一个 DB 行,其中包含三个日期字段 [RWT010][RWT010BP][RWP000]。但在 Oracle 中,这已被规范化,因此您将返回多行,每行都有一个名为 [DATE_LATEST] 的日期时间字段,然后是名为 [TYPE] 的名称字段,它等于 "RWT010""RWT010BP""RWP000" .

您在想,您想按名称处理那些 RWP000 日期值,就像在 Access 中一样。你是对的,这是最清晰的方法,我会告诉你怎么做。我误解了你在问什么。

一种方法是编写一个复制 Access 逻辑的 Oracle 存储过程。这不是你问的问题,但这是一种合法的方式。但是,由于数据库的变化,它会比 Access 版本更复杂,而且无论如何我已经多年没有编写 Oracle SQL,而且我没有方便的 Oracle 服务器来给我关于分号的任意、神秘的语法错误和空白。

所以我要做的是在 C# 中编写一个循环,以从 DB 行中获取日期时间并将它们放入局部变量中,然后使用这些变量而不是字段在 C# 中复制 Access 逻辑。与 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}", ...) 中的“:d”相同。

还有一件事: idnum 是一个 int,但永远不要将字符串值连接到 SQL 字符串中。这是一个巨大的安全漏洞,这里的人们(恐怕是正确的)会让你很难考虑它。

请改用OracleCommand.Parametersas shown in this answer。即使在这种情况下,我也会将其用作条件反射。

【讨论】:

  • 哇,这是对我的代码的一个非常好的解释和解决方案。我对如何获得培训类型和日期感到困惑,然后意识到我已经编写了子查询来处理每种类型。关于注入漏洞的好点。有人可以做很多事情。
  • @OryWeaver 谢谢。如果它解决了问题,您可以将其标记为答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-23
  • 2016-03-24
  • 2017-01-02
  • 2015-04-10
  • 2013-06-11
相关资源
最近更新 更多