【问题标题】:How do I store date values partially?如何部分存储日期值?
【发布时间】:2009-09-01 12:31:15
【问题描述】:

我使用的是 MS SQL Server 2005,我需要部分存储日期值。例如,日期的日期部分实际上可能仍然未知,但 MS SQL Server 限制指定完整日期,如下所示:

INSERT foo(dt) VALUES('2001-10-31');

不过我想用这样的东西:

INSERT foo(dt) VALUES ('2001-10-??');

当然,MS SQL 不能接受这样的日期,我找到了一个将日期部分转换为乘数的粗略示例:

SET NOCOUNT ON 
CREATE TABLE foo ( 
    dt INT 
) 
INSERT foo VALUES ( 
    DATEPART(YEAR, GETDATE()) * 10000 
        + DATEPART(MONTH, GETDATE()) * 100 
        + DATEPART(DAY, GETDATE()) 
) 
SELECT dt FROM foo 
DROP TABLE foo

...嗯,我不敢相信这是否是解决问题的唯一方法,所以我想问:我如何以最好的方式解决这个问题?

提前致谢。


UPD 2014:
另见Storing partial dates in a database

【问题讨论】:

  • 你为什么不知道完整的日期?没有完整日期的日期字段有什么用?
  • 有时日期的日期部分确实是未知的。例如,我可以填写一张稀有的未发行音乐演示唱片,但该唱片的日期可能有误或部分日期未指明录制日期。所以我想保留延期填写备案信息的可能性

标签: sql sql-server sql-server-2005 datetime


【解决方案1】:

您可以在此处存储每个日期部分,并仍将它们限制为有效日期:

CREATE Table PartialDates
(
     YearPart       smallint --(2 bytes -32k to +32k)
    ,MonthPart      tinyint  --(1 byte 0 to 255)
    ,DayPart        tinyint  --(1 byte 0 to 255)
    ,CompleteDate  AS (CONVERT(datetime,CONVERT(varchar(10),YearPart)+'-'+CONVERT(varchar(10),MonthPart)+'-'+CONVERT(varchar(10),coalesce(DayPart,1))))
)
ALTER TABLE dbo.PartialDates ADD CONSTRAINT
    CK_PartialDates_IsDate CHECK (ISDATE(CONVERT(varchar(10),YearPart)+'-'+CONVERT(varchar(10),MonthPart)+'-'+CONVERT(varchar(10),coalesce(DayPart,1)))=1)
GO

insert into PartialDates (yearpart,monthpart,daypart) values(2009,91,1) --error
insert into PartialDates (yearpart,monthpart,daypart) values(2009,1,1)  --ok
insert into PartialDates (yearpart,monthpart,daypart) values(2009,1,51) --error
insert into PartialDates (yearpart,monthpart,daypart) values(2009,2,29) --error
insert into PartialDates (yearpart,monthpart,daypart) values(2009,2,28) --ok
insert into PartialDates (yearpart,monthpart,daypart) values(2009,2,null)--ok

select * from PartialDates

YearPart MonthPart DayPart CompleteDate
-------- --------- ------- -----------------------
2009     1         1       2009-01-01 00:00:00.000
2009     2         28      2009-02-28 00:00:00.000
2009     2         NULL    2009-02-01 00:00:00.000

(3 row(s) affected

【讨论】:

    【解决方案2】:

    您是否考虑将月、日和年存储在不同的列中?这将是一种非常原始和简单的方法,但有时这就是要走的路。这将允许您轻松查询特定月份和/或日期的值,而无需进行大量类型转换,这可能会使其他可能需要处理代码的人感到困惑。

    【讨论】:

    • 我通常不会推荐这个,但如果你不知道那一天,我不知道在没有可怕的操作的情况下如何做到这一点。如果三个字段之一发生更改并且仅当所有三个字段都构成有效日期时,您还可以添加一个从触发器填充的真实日期字段。然后,如果您有有效日期,您可以根据需要使用日期函数进行查询。
    【解决方案3】:

    智能日期键绝对是要走的路。不过,您的代码有点长,因为 SQL Server 确实提供了一种快速获取它的方法,使用 convert:

    select cast(convert(varchar, GETDATE(), 112) as int)
    

    您会认为您可以将convert 直接发送到int,但它不起作用。所以你必须先转换成varchar,然后再转换成int

    如果您希望它是当天的00,而不是实际日期:

    select cast(convert(varchar, getdate(), 112) as int) - day(getdate())
    

    希望这会有所帮助!

    【讨论】:

    • 感谢您的回复,埃里克。我正在仔细研究您目前的建议
    猜你喜欢
    • 1970-01-01
    • 2013-09-01
    • 2014-10-05
    • 1970-01-01
    • 2016-10-26
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    相关资源
    最近更新 更多