在数据库中更新 Oracle TIMESTAMP(0) WITH TIME ZONE 值的正确方法
Posted
技术标签:
【中文标题】在数据库中更新 Oracle TIMESTAMP(0) WITH TIME ZONE 值的正确方法【英文标题】:Proper method to update Oracle TIMESTAMP(0) WITH TIME ZONE value in database 【发布时间】:2016-11-28 16:29:49 【问题描述】:我正在尝试更新具有TIMESTAMP(0) WITH TIMEZONE
类型列的表。
我尝试了几种方法都没有成功,因为TIMESTAMP
写入数据库的方式没有偏移格式,例如美国东部时间的-05:00
。它使用AMERICA/NEW_YORK
作为时区保存,这会导致无法正确处理此问题的另一个应用程序出现问题。
当前:28-NOV-16 10.51.43.000000000 AM AMERICA/NEW_YORK
希望:28-NOV-16 10.51.43.000000000 AM -05:00
这里的许多帖子主要是在从数据库中检索数据时对其进行格式化;其他示例使用 SqlPlus 进行描述,而不是在 C# 中。
Using(OracleConnection conn = new OracleConnection(......))
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.BindByName = true;
cmd.CommandText = "update customer set email_addr = :EMAIL, modified_date= SYSDATE
where cust_id = :CUSTID";
conn.Open();
cmd.Parameters.Add("EMAIL", OracleDbType.Varchar2).Value = txtEmail.Text;
cmd.Parameters.Add("MODIFIED_DATE", OracleDbType.Varchar2).Value = OracleDate.GetSysDate().ToOracleTimeStamp();
cmd.Parameters.Add("CUSTID", OracleDbType.Decimal).Value =Convert.ToDecimal(Session["ID"]);
cmd.ExecuteNonQuery();
我也尝试过modified_date=to_timestamp(:modified_date, 'MM/DD/YYYY HH:mi:ss')
,但这会生成异常,因为时区格式不正确。
在 C# 中完成此任务的正确方法是什么?日期/时间戳列是否应该始终使用字符串转换来写入?
【问题讨论】:
【参考方案1】:您的代码中似乎有错字。您指定了 2 个绑定变量,但您尝试绑定 3 个值。
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.BindByName = true;
cmd.CommandText = "update customer set email_addr = :EMAIL, modified_date= :MODIFIED_DATE
where cust_id = :CUSTID";
conn.Open();
cmd.Parameters.Add("EMAIL", OracleDbType.Varchar2).Value = txtEmail.Text;
cmd.Parameters.Add("MODIFIED_DATE", OracleDbType.TimeStampTZ).Value = OracleDate.GetSysDate().ToOracleTimeStamp();
cmd.Parameters.Add("CUSTID", OracleDbType.Decimal).Value =Convert.ToDecimal(Session["ID"]);
cmd.ExecuteNonQuery();
OracleDbType
不是Varchar2
,必须是TimeStampTZ
。
但是,您似乎正在使用 DevArt 的 Oracle 数据提供程序。当我检查documentation 时,它们似乎不支持数据类型TIMESTAMP WITH TIME ZONE
。
我看到了几种解决方法。
在对数据库运行操作之前,将SESSIONTIMEZONE
设置为-05:00
,例如:
cmd.CommandText = "ALTER SESSION SET TIME_ZONE = '-05:00'";
cmd.ExecuteNonQuery();
那么你的C#代码可以是这样的:
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.BindByName = true;
cmd.CommandText = "update customer set email_addr = :EMAIL, modified_date= CURRENT_TIMESTAMP
where cust_id = :CUSTID";
conn.Open();
cmd.Parameters.Add("EMAIL", OracleDbType.Varchar2).Value = txtEmail.Text;
cmd.Parameters.Add("CUSTID", OracleDbType.Decimal).Value =Convert.ToDecimal(Session["ID"]);
cmd.ExecuteNonQuery();
CURRENT_TIMESTAMP 以TIMESTAMP WITH TIME ZONE
数据类型返回会话时区中的当前时间。
您也可以在SQL中指定时区,例如:
cmd.CommandText = "update customer set email_addr = :EMAIL,
modified_date= SYSTIMESTAMP AT TIME ZONE '-05:00'
where cust_id = :CUSTID";
当您使用TIMESTAMP
更新TIMESTAMP WITH TIME ZONE
值时,Oracle 将使用时区-05:00
隐式转换为TIMESTAMP WITH TIME ZONE
。
注意,America/New_York 有夏令时,即您必须使这些命令更加动态,并且每年两次在 -05:00
和 -04:00
之间切换(如果您将使用时区区域,例如America/New_York
)。
另一种解决方法是在您的应用程序中运行 ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'DD-MON-YY HH.MI:SS.FF AM TZH:TZM'
,它无法处理像 AMERICA/NEW_YORK
这样的时区名称。
【讨论】:
这正是我所需要的,它也回答了我关于设置会话参数的另一个问题。谢谢!顺便说一句,当我使用 SYSTIMESTAMP 时,我会自动获得正确的时区,所以我实际上不需要使用AT TIME ZONE
。再次感谢您。以上是关于在数据库中更新 Oracle TIMESTAMP(0) WITH TIME ZONE 值的正确方法的主要内容,如果未能解决你的问题,请参考以下文章