来自nvarchar字段的计算列日期

时间:2012-04-13 11:46:23

标签: sql-server sql-server-2008

我有一个nvarchar(50)字段(DateHr),它以下列格式保存日期和时间:yy/mm/dd hh:mm:ss(例如12/04/11 16:49:23应转换为April 11, 2012 4:49 PM)。

我很难尝试以这种格式管理日期值。

我想知道是否可以将列创建为DateTime数据类型并使用此新字段。

3 个答案:

答案 0 :(得分:2)

为什么不只是一个观点?

CREATE VIEW dbo.View_MyTable
AS
  SELECT 
    DateHr, 
    DateHr2 = CONVERT(VARCHAR(24), CONVERT(DATETIME, '20' + DateHr), 100)),
    DateHrProper = CONVERT(DATETIME, '20' + DateHr)
  FROM dbo.MyTable;

现在您的查询可以是:

SELECT DateHr2 FROM dbo.View_MyTable
  WHERE DateHrProper >= '20120412'
  AND DateHrProper < '20120413';

这样您就不必弄乱表的架构,只有在需要时才可以调查持久计算列方法。如果你确实添加了一个计算列,我会将它添加为日期时间列,而不是作为同一日期的不同字符串表示。在输出上做“做得漂亮”的东西,而不是存储。

编辑如果您可以通过存储过程控制对表的写入(强烈推荐),并且您不允许用户运行即席插入/更新,那么您可以更改基本类型和不必担心他们可能进入的废话。例如:

UPDATE dbo.MyTable
    SET DateHr = CONVERT(DATETIME, '20' + DateHr);

-- assuming there are no rows left where `ISDATE(DateHr) = 0`, 
-- but you'll have to test that:

ALTER TABLE dbo.MyTable ALTER COLUMN DateHr DATETIME;
GO

ALTER PROCEDURE dbo.ProcThatUpdatesMyTable
  @key    INT,
  @DateHr NVARCHAR(50)
AS
BEGIN
  SET NOCOUNT ON;

  IF ISDATE('20' + @DateHr) = 0
  BEGIN
    RAISERROR('Please enter a valid date.', 11, 1);
    RETURN;
  END

  UPDATE dbo.MyTable 
    SET DateHr = CONVERT(DATETIME, '20' + @DateHr)
    WHERE key = @key;
END
GO

现在您的查询,您想要April 11, 2012 4:49 PM作为输出 - 遗憾的是,没有一种本机方式可以轻松地在SQL Server中转换为该格式。您可以使用各种字符串操作来执行此操作,例如:

;WITH x AS 
(
  SELECT 
    d = DATENAME(MONTH, DateHr) + ' ' 
      + CONVERT(VARCHAR(2), DAY(DateHr)) + ', ' 
      + CONVERT(CHAR(5), YEAR(DateHr)), 
    t = CONVERT(CHAR(26), DateHr, 109)
  FROM dbo.blab
)
SELECT d = d + LEFT('0' + RIGHT(t, 13), 5) + ' ' + RIGHT(t, 2) FROM x;

这非常接近您想要的输出:

April 11, 2012 04:49 PM

如果需要,您可以执行更多字符串操作以删除当前的0。

在客户端上格式化这个更好。从好的方面来说,您可以使用新的FORMAT()函数在SQL Server 2012中轻松完成此操作:

SELECT FORMAT(DateHr, 'MMMM dd, yyyy h:mm tt')
  FROM dbo.MyTable;

结果:

April 11, 2012 4:49 PM

当然,我再次提到最终的解决方案是让用户首先输入freetext日期格式。我保证有人会在2011年5月4日或12月他们意味着2012年11月时进入4月5日。让他们从下拉列表或日历控件中进行选择,您可以完全监督在安全的情况下传递给SQL Server的字符串格式而不是依赖于当天的人的心情,将确保您始终知道日期是用户选择的日期(即使他们的区域格式可能不是您所期望的)。

答案 1 :(得分:1)

这样做:

SELECT CONVERT(VARCHAR(20), cast('2012/04/11 16:49:23' as datetime), 100)

这很奇怪,但两个演员都是必要的

编辑:

create table test_date
(
DateHr varchar(50),
DateHr2  AS (CONVERT(VARCHAR(20), cast('20'+ DateHr as datetime), 100))
) 

insert into test_date values ('12/04/11 16:49:23')

select * from test_date


12/04/11 16:49:23   Apr 11 2012  4:49PM

答案 2 :(得分:1)

一个选项是计算列。例如,

declare @t table(s nvarchar(50), dt as convert(varchar(30),case isdate(s) when 1 then cast(s as datetime) end,121))
insert into @t(s) values ('12/04/11 16:49:23')
update @t set s='20'+s where ISDATE(s)=1 and LEN(s)<19 --prepend w/century
insert into @t(s) values ('john') --demonstrate bad date string handling here
select * from @t;

结果:

s                                                  dt
-------------------------------------------------- ------------------------------
2012/04/11 16:49:23                                2012-04-11 16:49:23.000
john                                               NULL

编辑:添加错误日期值的处理

编辑:自定义日期24小时格式 - yyyy-mm-dd hh:mi:ss.mmm(24小时)

编辑:根据需要在原始日期前加上世纪

或者,您可以在计算列中添加世纪:

declare @t table(s nvarchar(50), dt as convert(varchar(30),case isdate('20'+s) when 1 then cast('20'+s as datetime) end,121))
insert into @t(s) values ('12/04/11 16:49:23')
insert into @t(s) values ('john') --demonstrate bad date string handling here
select * from @t;

结果:

s                                                  dt
-------------------------------------------------- ------------------------------
12/04/11 16:49:23                                  2012-04-11 16:49:23.000
john                                               NULL