SQL 正确地将整数格式化为日期

SQL correctly format integers as dates

我正在用 C# 编写程序,其中一部分是从 DB2 服务器获取日期。日期在服务器上存储为长度为 4 的整数值。日期只保留月份和日期我遇到的问题是它们的存储精度不同。 编辑: 数据类型是数字长度 4,没有精度(因此整数长度 4)但是当 Select 语句运行时,所有内容都作为字符串返回。这就是我使用 SubStr() 的原因。

示例

一个日期存储为1003表示日期10/03

另一个日期存储为 805 表示 8/05

我用来提取日期的 SQL 代码

(SubStr(ML2DDM,0,3) ||'/'|| SubStr(ML2DDM,3,2))as Due__Date

程序returns日期格式如下

10/03

80/5 <<<< 这就是问题所在

有没有办法每次都正确设置值的格式?

在 C# 中我会这样做:

var fullValue = ML2DDM;
var formattedDate = fullValue.Substring(0, fullValue.Length - 2) + "/" + fullValue.Substring(fullValue.Length - 2, 2);

我不知道任何 DB2,但也许同样的方法有效?类似于:

(SubStr(ML2DDM,0,length(ML2DDM)-2) ||'/'|| SubStr(ML2DDM,length(ML2DDM)-2,2))as Due__Date

如果它们是整数,那么做字符串函数似乎不是个好主意。我只是将整数拉回 "as is",并在 C# 中处理它,然后你有:

int month = val / 100;
int day = val % 100;

然后您可以随心所欲。我 期望 您的 RDBMS 具有内置的整数除法和模运算,因此您也可以在服务器上执行此操作。比如在SQL服务器(因为不懂DB2):

declare @v int = 805; -- obviously in real code this would be a column
select @v / 100 as [month], @v % 100 as [day]

显然您将整数存储为字符。因为您不能在整数列上使用 SUBSTR()

两个 SQL 解决方案

转换为 zoned/packed 十进制,然后使用 DIGITS() 转换回字符并包括前导零

select 
  (SubStr(digits(dec(ML2DDM,4)),1,2) 
    ||'/'|| SubStr(digits(dec(ML2DDM,4)),3,2))as Due__Date

添加一些前导零,然后取 RIGHT() 大多数字符...

select 
  (left(right(trim('0' || ML2DDM),4),2)
    ||'/'|| right(trim('0'|| ML2DDM),2) as Due__Date

如果列是定长字符而不是 VARCHAR,则需要 TRIM()

如何让坏数据可读。我主要使用此技术来制作开始和结束标记或在输出 html、xml 纯文本时添加换行符。都有办法。

select 
case when length(trim(ml2ddm)) = 4 
then substring(ml2ddm,1,2) || '/' || substring(ml2ddm,3)
when substring(trim(ml2ddm,4,1) = ' ' 
then substring(ml2ddm,1,1) || '/' || substring(ml2ddm,2) 
else substring(ml2ddm,2,1) || '/' || substring(ml2ddm,3)  
end as somefunkydate
from somereallyfunkydata
 select left(right(repeat('0', 4) || trim(ML2DDM), 4), 2) || '/' ||  
 right(right(repeat('0', 4) || trim(ML2DDM), 4), 2)  as Due__Date          

鉴于像很多帖子一样,没有给出 DDL,我可以提供:

无论 ML2DDM 的 DDL 是 CHAR(4)、VARCHAR(4)、SMALLINT、DECIMAL、NUMERIC、BIGINT 还是 INTEGER [数字类型,然后还确保任何精度不超过四位数实际值,虽然实际的列精度并不重要,但前提是该列也定义为零刻度;这当然是由各种 INT 类型暗示​​的],以下表达式应该足以在存储的每个 MMDD 数据的 MM 和 DD 组件之间插入一个 / 字符使用三位数字 ### 或四位数字 #### 的值 [其中 # 代表零到九的任何十进制数字];如果数字存储为字符串,则它们必须左对齐存储,并且任何非数字数据将被类似地编辑,尽管它们不是实际日期值的有效表示,但数字的编辑结果也不会以这种方式确保值有效:

   insert ( case length(rtrim(ML2DDM))  
             when 3 then '0' else '' end
            concat ML2DDM               
          , 3, 0, '/' ) as due__date_ins

了解实际的 DDL 可以使表达更简洁。

如果需要实际的 DATE 数据类型结果,则可以使用上面提供的表达式替换 TIMESTAMP_FORMAT 表达式的以下变体中的 expr,以生成具有以下内容的 TIMESTAMP当前年份值 TO_DATE( expr, 'MMDD' ),可以转换为 DATE;例如DATE( TO_DATE( expr, 'MMDD' ) ) 当然,此额外转换的结果 绝对要求 将数据值存储为合法的 MMDD [或 MDD] 值。

2016 年 9 月 30 日附录
如果 ML2DDM 的 DDL 是数字 [非浮点数],那么 IIRC 从数字到字符的隐式转换效果正在转换为 VARCHAR,因此以下将是一个非常简单的表达式来影响 MMDD 到 "MM/DD" 和 MDD 到"MM/DD":

 insert ( LPAD( ML2DDM , 4, '0' ) , 3, 0, '/' ) as Due__Date