转换日期存储为NUMERIC到DATETIME

sha*_*hat 1 t-sql sql-server datetime

我目前正在处理一个需要计算两个不同日期之间的天数差异的查询.我以前在DATE列中遇到过问题,因为它们都被存储为numeric列,这是一个彻底的痛苦.

我试着CONVERT像过去那样尝试使用不同的DATETIME字符串构建,但我没有运气.

注释行--convert(datetime,)是我遇到问题的地方.基本上,我需要转换PO_DATELINE_DOCK_DATE使用可用的格式,因此我可以计算两者之间的差异.

USE BWDW

GO

SELECT 

  [ITEM_NO]
  ,[ITEM_DESC]
  ,[HEADER_DUE_DATE]
  ,[BWDW].[dbo].[DS_tblDimWhs].WHS_SHORT_NAME AS 'Warehouse'
  ,[BWDW].[dbo].[DS_tblFactPODtl].[PO_NO] AS 'PO NUMBER'
  ,[BWDW].[dbo].[DS_tblFactPODtl].[PO_DATE] AS 'Start'
  ,[BWDW].[dbo].[DS_tblFactPODtl].[PO_STATUS] AS 'Status'
  ,[BWDW].[dbo].[DS_tblFactPODtl].[LINE_DOCK_DATE] AS 'End'
  --,(SELECT CONVERT(DATETIME, CONVERT(CHAR(8), [BWDW].[dbo].[DS_tblFactPODtl].[PO_DATE])) FROM dbo.DS_tblFactPODtl)


FROM [BWDW].[dbo].[DS_tblFactPODtl] 
INNER JOIN [BWDW].[dbo].[DS_tblDimWhs] ON [BWDW].[dbo].[DS_tblFactPODtl].WAREHOUSE = [BWDW].[dbo].[DS_tblDimWhs].WAREHOUSE
INNER JOIN [BWDW].[dbo].[DS_tblFactPO] ON [BWDW].[dbo].[DS_tblFactPODtl].PO_NO = [BWDW].    [dbo].[DS_tblFactPO].PO_NO
WHERE [BWDW].[dbo].[DS_tblFactPODtl].[PO_STATUS] = 'Closed'
AND [BWDW].[dbo].[DS_tblFactPODtl].[LINE_DOCK_DATE] <> 0
Run Code Online (Sandbox Code Playgroud)

我有一个我之前从事过的项目保存的片段,只需要显示从今天到另一年的结果.其中有一堆CAST和CONVERTS,但我尝试了相同的方法,没有成功.

从长远来看,我想为每个数据库表添加一个列,以包含datetime将来可用的正确列...但这是另一个故事.我已经在stackoverflow上阅读了很多关于转换为NUMERIC等的帖子,但是没有任何关于NUMERIC的回复DATETIME.

示例数据:

Start    | End      | Difference
--------------------------------
20110501 | 20111019 | 171
20120109 | 20120116 | 7
20120404 | 20120911 | 160
Run Code Online (Sandbox Code Playgroud)

只是想计算差异..

每个修改过的AARON:

SELECT
  FPODtl.[ITEM_NO] AS [Item]
  ,FPODtl.[ITEM_DESC] AS [Description] 
  ,D.WHS_SHORT_NAME AS [Warehouse]
  ,FPODtl.[PO_NO] AS [PO NUMBER]
  ,FPODtl.[PO_DATE] AS [Start]
  ,FPODtl.[PO_STATUS] AS [Status]
  ,FPODtl.[LINE_DOCK_DATE] AS [End]
  ,DATEDIFF
  (
    DAY,
    CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.PO_DATE)) = 1
      THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.PO_DATE)) END,
    CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) = 1
      THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) END
  )
    FROM [dbo].[DS_tblFactPODtl] AS FPODtl 
    INNER JOIN [dbo].[DS_tblDimWhs] AS D 
  ON FPODtl.WAREHOUSE = D.WAREHOUSE
    INNER JOIN [dbo].[DS_tblFactPO] AS FPO 
  ON FPODtl.PO_NO = FPO.PO_NO
    WHERE FPODtl.[PO_STATUS] = 'Closed'
    AND FPODtl.[LINE_DOCK_DATE] <> 0;
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 7

DECLARE @x NUMERIC(10,0);

SET @x = 20110501;

SELECT CONVERT(DATETIME, CONVERT(CHAR(8), @x));
Run Code Online (Sandbox Code Playgroud)

结果:

2011-05-01 00:00:00.000
Run Code Online (Sandbox Code Playgroud)

比较两个:

DECLARE @x NUMERIC(10,0), @y NUMERIC(10,0);

SELECT @x = 20110501, @y = 20111019;

SELECT DATEDIFF
(
  DAY, 
  CONVERT(DATETIME, CONVERT(CHAR(8), @x)),
  CONVERT(DATETIME, CONVERT(CHAR(8), @y))
);
Run Code Online (Sandbox Code Playgroud)

结果:

171
Run Code Online (Sandbox Code Playgroud)

更重要的是,修复表格.停止将日期存储为数字.将它们存储为日期.如果您在此转换时遇到错误,那是因为您的糟糕数据选择已将错误数据放入表中.你可以得到周围-可能-写旧版本的TRY_CONVERT():

SELECT DATEDIFF
(
  DAY, 
  CASE WHEN ISDATE(col1)=1 THEN CONVERT(DATETIME, col1) END,
  CASE WHEN ISDATE(col2)=1 THEN CONVERT(DATETIME, col2) END
)
FROM 
( 
  SELECT 
    col1 = CONVERT(CHAR(8), col1), 
    col2 = CONVERT(CHAR(8), col2)
  FROM dbo.table
) AS x;
Run Code Online (Sandbox Code Playgroud)

这将为任一行中存在垃圾的任何行生成空值.以下是对原始查询的修改:

SELECT
  [ITEM_NO] -- what table does this come from?
  ,[ITEM_DESC] -- what table does this come from?
  ,[HEADER_DUE_DATE] -- what table does this come from?
  ,D.WHS_SHORT_NAME AS [Warehouse] -- don't use single quotes for aliases!
  ,FPODtl.[PO_NO] AS [PO NUMBER]
  ,FPODtl.[PO_DATE] AS [Start]
  ,FPODtl.[PO_STATUS] AS [Status]
  ,FPODtl.[LINE_DOCK_DATE] AS [End]
  ,DATEDIFF
  (
    DAY,
    CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.PO_DATE)) = 1
      THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.PO_DATE)) END,
    CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) = 1
      THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) END
  )
FROM [dbo].[DS_tblFactPODtl] AS FPODtl 
INNER JOIN [dbo].[DS_tblDimWhs] AS D 
  ON FPODtl.WAREHOUSE = D.WAREHOUSE
INNER JOIN [dbo].[DS_tblFactPO] AS FPO 
  ON FPODtl.PO_NO = FPO.PO_NO
WHERE FPODtl.[PO_STATUS] = 'Closed'
AND FPODtl.[LINE_DOCK_DATE] <> 0;
Run Code Online (Sandbox Code Playgroud)