当日期格式变量为'M / d / yy'并且月份或日期为两位数值时,TO_DATE()函数将给出错误

时间:2018-08-15 11:53:39

标签: c# sql oracle to-date

我的日期格式根据用户的日期格式而有所不同。 如果日期格式为“ M / d / yy”,则会出现错误,ORA-01821:日期格式无法识别。

sDateFormat = CultureInfo.DateTimeFormat.ShortDatePattern;

SELECT * FROM xxx WHERE yyy <= TO_DATE('" + sScheduleDate + "','"+sDateFormat+"')";

// sScheduleDate例如:“ 11/15/18” // sDateFormat“ M / d / yy”

2 个答案:

答案 0 :(得分:1)

我看到两个问题:

  1. 就像HoTTab1CH所说:如果要构建查询(https://en.wikipedia.org/wiki/SQL_injection),则应始终使用OracleParameters

  2. 您正在使用Oracle的C#模式。这可能会起作用(不变文化),而bot通常不会(分钟)。

// This will get you the Pattern "MM/dd/yyyy"
string invariantPattern = CultureInfo.InvariantCulture.DateTimeFormat.ShortDatePattern;

// This will get me in a German-Environment the Pattern "dd.MM.yyyy"
string invariantPattern = CultureInfo.InvariantCulture.DateTimeFormat.ShortDatePattern;

两种模式都与Oracle无关。它们可能起作用,但是您不知道。您不得在.Net环境之外使用它们!

这是允许的:

OracleCommand cmd = null; // You should have this one already initialized..

// Your Idea:
DateTime date = new DateTime(2018, 12, 31, 23, 59, 59);
string csharpPattern = "dd.MM.yyyy HH:mm:ss";
string oraclePattern = "dd.mm.yyyy HH24:MI:SS";
string toDateQuery = "to_date('" + date.ToString(csharpPattern) + "','" + oraclePattern + "')";
string sqlQuery = "SELECT * FROM mytable t WHERE t.mydate = " + toDateQuery;
cmd.CommandText = sqlQuery;
var reader = cmd.ExecuteReader();
// Do something...

// But... Better, shorter and correcter(?)
DateTime date2 = new DateTime(2018, 12, 31, 23, 59, 59);
cmd.CommandText = "SELECT * FROM mytable t WHERE t.mydate = :MYDATE";
cmd.Parameters.Add(new OracleParameter(":MYDATE", date2));

其他说明

表格

CREATE TABLE TEST
(
  TESTDATE               DATE,
  TESTTIMESTAMP          TIMESTAMP(6),
  TESTTIMESTAMPTIMEZONE  TIMESTAMP(6) WITH TIME ZONE
)

C#-App

DateTime d = DateTime.Now;

// Let OPD.Net do the work..
OracleCommand  cmd = con.CreateCommand();
cmd.CommandText = "INSERT INTO TEST VALUES(:TESTDATE, :TESTTIMESTAMP, :TESTTIMESTAMPTIMEZONE)";
cmd.Parameters.Add(new OracleParameter("TESTDATE", d));
cmd.Parameters.Add(new OracleParameter("TESTTIMESTAMP", d));
cmd.Parameters.Add(new OracleParameter("TESTTIMESTAMPTIMEZONE", d));
cmd.ExecuteNonQuery();

// Try to manually hit the OracleTypes - and loose the milliseconds..
cmd = con.CreateCommand();
cmd.CommandText = "INSERT INTO TEST VALUES(:TESTDATE, :TESTTIMESTAMP, :TESTTIMESTAMPTIMEZONE)";
cmd.Parameters.Add(new OracleParameter("TESTDATE", OracleDbType.Date, d, System.Data.ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("TESTTIMESTAMP", OracleDbType.Date, d, System.Data.ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("TESTTIMESTAMPTIMEZONE", OracleDbType.Date, d, System.Data.ParameterDirection.Input));
cmd.ExecuteNonQuery();

// Set everything correct (and redundant..)
cmd = con.CreateCommand();
cmd.CommandText = "INSERT INTO TEST VALUES(:TESTDATE, :TESTTIMESTAMP, :TESTTIMESTAMPTIMEZONE)";
cmd.Parameters.Add(new OracleParameter("TESTDATE", OracleDbType.Date, d, System.Data.ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("TESTTIMESTAMP", OracleDbType.TimeStamp, d, System.Data.ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("TESTTIMESTAMPTIMEZONE", OracleDbType.TimeStampTZ, d, System.Data.ParameterDirection.Input));
cmd.ExecuteNonQuery();

Db-Data

| TESTDATE            | TESTTIMESTAMP              | TESTTIMESTAMPTIMEZONE             |
| 16/08/2018 11:07:23 | 16/08/2018 11:07:23,079714 | 16/08/2018 11:07:23,079714 +02:00 |
| 16/08/2018 11:07:23 | 16/08/2018 11:07:23,000000 | 16/08/2018 11:07:23,000000 +02:00 | 
| 16/08/2018 11:07:23 | 16/08/2018 11:07:23,079714 | 16/08/2018 11:07:23,079714 +02:00 |

如您所见。示例程序确实选择了错误的类型。在cmd中没有显式类型的情况下,ODP.Net可以正常工作。

OPD.Net具有每个C#-Type到OracleDbTypes的映射。您不必告诉Oracle日期时间是什么!

https://docs.oracle.com/cd/B28359_01/win.111/b28375/featTypes.htm

如果您开始在C#代码中设置类型,则会有一个双重声明。您的数据库告诉您的客户如何转换变量。

如果将Db列从“日期”更改为“时间戳”,则也必须更改C#-App!如果您有多个Apps访问您的Db,那么您将需要进行大量工作。

在某些情况下,例如使用具有可为null的类型的数组,应在其中设置类型,但通常不必这样做。

答案 1 :(得分:0)

由于没有这样的“ M”参数而无法识别,这里是TO_DATE()https://www.techonthenet.com/oracle/functions/to_date.php

的完整文档

尝试此操作,正确的格式掩码应为to_date('11/15/18', 'MM/DD/YY')

编辑:

为避免此问题,您最好在查询中使用参数。这是一个小例子:

 DateTime date = //get your date here

 string myQuery= "SELECT * FROM xxx WHERE yyy <= :pDate";

 OracleCommand oraCmd = new OracleCommand();
 oraCmd.CommandType = CommandType.Text;
 oraCmd.Connection = OracleConnectionSource; // your connection

 OracleParameter oraParam = new OracleParameter();
 oraParam = oraCmd.Parameters.Add("pDate", OracleDbType.Date, date, ParameterDirection.Input);

 oraCmd.CommandText = myQuery;
 OracleDataReader oraDataReader = oraCmd.ExecuteReader();