2011-09-30 99 views
2

我試圖爲報告應用程序建模DateRange概念。某些日期範圍需要是絕對的,2011年3月1日至2011年3月31日。其他日期範圍相對於當前日期,過去30天,下週等。什麼是將數據存儲在SQL表中的最佳方式是什麼?如何在SQL數據庫中存儲絕對和相對日期範圍?

顯然對於絕對範圍,我可以有一個BeginDate和EndDate。對於相對範圍,具有InceptionDate和整數RelativeDays列是有意義的。如何將這兩個想法合併到一個表中,而不需要實現上下文,即提及所有四個列,並使用異或邏輯來填充4中的2個。

由於具有上下文驅動而被拒絕的兩種可能模式列:

CREATE TABLE DateRange 
(
    BeginDate DATETIME NULL, 
    EndDate DATETIME NULL, 
    InceptionDate DATETIME NULL, 
    RelativeDays INT NULL 
) 

OR

CREATE TABLE DateRange 
(
    InceptionDate DATETIME NULL, 
    BeginDaysRelative INT NULL, 
    EndDaysRelative INT NULL 
) 

感謝您的諮詢!

回答

2

我不明白爲什麼你的第二個設計不符合你的需求,除非你在「沒有NULL從不」的陣營。只需保留InceptionDate NULL爲「相對於當前日期」選項,以便您的應用程序可以告訴它們與固定日期範圍分開。 (注意:不知道你的數據庫引擎,我用日期代碼保留了日期數學和當前日期問題。同樣,在你的問題中,我省略了任何文本描述和主鍵列)。

然後,可以創建這樣一個觀點:

CREATE VIEW DateRangesSolved (Inception, BeginDays, EndDays) AS 
    SELECT CASE WHEN Inception IS NULL THEN Date() ELSE Inception END, 
      BeginDays, 
      EndDays, 
    FROM DateRanges 

或只使用該邏輯,當你從表中直接選擇。

你甚至可以把它一步:

CREATE VIEW DateRangesSolved (BeginDate, EndDate) AS 
    SELECT (CASE WHEN Inception IS NULL THEN Date() ELSE Inception END + BeginDays), 
      (CASE WHEN Inception IS NULL THEN Date() ELSE Inception END + EndDays) 
    FROM DateRanges 
+0

我對NULL沒有宗教信仰,但是我討厭RDBS中的上下文列,即「列A只在列B爲空,而列C代表不同的事情取決於A或B被填充時填充。」 – ant

+1

那麼,在這裏,您將看到兩個不同且相同的實體。不同之處在於其中一個具有與之相關的額外數據。你要麼需要一個具有這種細微變化的表格,要麼需要兩個不同的表格。 –

+0

我喜歡將存儲表與空表示當前日期的NULL結合起來,然後使用適當呈現這些日期的'Solved'視圖。謝謝! – ant

0

將它們放在單獨的表格中。絕對沒有理由將它們放在一張表中。

對於相對日期,我會去那麼遠,只是讓表你需要的日期函數的參數,即

CREATE TABLE RelativeDate 
(
    Id INT Identity, 
    Date_Part varchar(25), 
    DatePart_Count int 
) 

然後你就可以知道它是-2 WEEK30 DAY方差在你的邏輯中使用它。

如果您需要同時查看它們,則可以將它們邏輯地組合到一個查詢或視圖中,而無需通過將不同數據元素填充到同一個表中來搞亂數據結構。

+0

嗯,我想以此爲FK的報告表包含佈局和定義。在這種情況下使用兩個表格變得更加複雜,不是嗎? – ant

+0

@ant - 不是真的,只需將它作爲您的其他表中的2部分FK即可。 「範圍」或「相對」,以及ID。然後,您仍然可以執行關係,但不必將所有內容都放在一張表中。 – JNK

0

創建一個包含begindate和偏移量的表格。偏移的精度取決於你自己決定。

CREATE TABLE DateRange(
    BeginDate DATETIME NOT NULL, 
    Offset int NOT NULL, 
    OffsetLabel varchar(100) 
) 

插入到它:

INSERT INTO DateRange (BeginDate, Offset, OffsetLabel) 
select '20110301', DATEDIFF(sec, '20110301', '20110331'), 'March 1, 2011 - March 31, 2011' 

最近30天

INSERT INTO DateRange (BeginDate, Duration, OffsetLabel) 
select '20110301', DATEDIFF(sec, current_timestamp, DATEADD(day, -30, current_timestamp)), 'Last 30 Days' 

以後要顯示的值:

select BeginDate, EndDate = DATEADD(sec, Offset, BeginDate), OffsetLabel 
from DateRange 

如果你想能夠解析你將擁有「原始」模糊的描述e尋找「模糊日期」或「近似」功能。 (有存在於Git的源代碼,類似this。)

1

其他都是相對於當前日期,最近30天,下週等 什麼是存儲在SQL表中數據的最佳方式?

如果您將這些範圍存儲在表中,則必須每天更新它們。在這種情況下,你必須每天更新每一行。這可能是一個大問題;它可能不會。

該類表中通常沒有多少行,通常少於50個。表結構很明顯。更新應該由一個cron工作(或者它的等價工作)來驅動,並且你應該每天運行非常挑剔的異常報告來確保事情已經被正確更新。

通常情況下,如果事情沒有問題,這些報告應該不會輸出。如果cron不運行,那麼從cron驅動這樣的報告會產生無輸出的額外複雜性。這不好。

您還可以創建一個視圖,該視圖不需要任何維護。有幾十行,它可能比物理錶慢,但它可能仍然足夠快。它消除了全部這些範圍的維護和管理工作。 (檢查是否有關閉的情況的一個錯誤,因爲我不知道。)

create view relative_date_ranges as 
select 'Last 30 days' as range_name, 
     (current_date - interval '30' day)::date as range_start, 
     current_date as range_end 
union all 
select 'Last week' as range_name, 
     (current_date - interval '7' day)::date as range_start, 
     current_date as range_end 
union all 
select 'Next week' as range_name, 
     (current_date + interval '7' day)::date as range_start, 
     current_date as range_end 

根據不同的應用程序,你可能能夠把你的「絕對」的範圍相同的方式。

... 
union all 
select 'March this year' as range_name, 
     (extract(year from current_date) || '-03-01')::date as range_start, 
     (extract(year from current_date) || '-03-31')::date as range_end