2011-10-17 42 views
2

獲取所有丟失的日期記錄我有一個數據庫表結構如下SQL:從數據庫

id | dateCreated | numOfUsers 

其中一個典型的行1,「2011-10-13 12:00:00」,4

我的行包含過去4個月的數據,但是有幾天不見了,我想找出使用​​SQL缺少的日子,任何想法如何去寫這個查詢?

我懷疑你通過某種方式獲取天數列表並將它們與數據庫中的值進行比較。

我知道你可以使用PHP或其他編程語言使用多個查詢來做到這一點,但是如果可能的話,我想在數據庫級別執行此操作。

在此先感謝

+2

請標記提供相應的數據庫你的問題,不是所有的人...... – RedFilter

+3

不同的數據庫,不同的答案 - 挑一個,雖然有對如此衆多的重複。 –

回答

0

輕鬆最有效的方法(在我看來),作爲你的狀態,開始與所有日期的表。你必須創建自己,假設你所做的一切,這裏有一對夫婦爲你的選擇......

SELECT 
    * 
FROM 
    calendar -- Your manually created table of dates 
LEFT JOIN 
    yourTable 
    ON yourTable.DateField = calendar.DateField 
WHERE 
    yourTable.DateField IS NULL 
    AND calendar.DateField >= @reportFirstDate 
    AND calendar.DateField <= @reportLastdate 

或者......

SELECT 
    * 
FROM 
    calendar -- Your manually created table of dates 
WHERE 
    NOT EXISTS (SELECT * FROM yourTable WHERE yourTable.DateField = calendar.DateField) 
    AND calendar.DateField >= @reportFirstDate 
    AND calendar.DateField <= @reportLastdate 

編輯

儘管維護這個日期列表可能會感到「不整潔」,但它對這種類型的查詢具有巨大的性能優勢。

隨着日期表,你正在看兩個索引,並檢查一個存在但不是另一個。

沒有你有一個更復雜的方法日期表...
1.抓住每一次記錄在表
2.自其加入到下一條記錄在表
3.如果是連續的日期,丟棄(保存記錄與他們之間的間隙)
4.遍歷每對,在缺少日期填寫
5.處理日期在您的報告期開始(無日期1在對失蹤)
6.處理報告期結束時遺失的日期(對中沒有日期2)

用日期創建臨時表可能實際上更快,以直接的方式創建臨時表,然後再次刪除表。如果是這樣的話,爲什麼不只是維護日期表?

  1. 只要有100年的表,而忘記了它
  2. 有代碼非常快一點,以保持日期最新的所有代碼


如果你不相信,我會建議試用不同的選項,並且自己看看索引日期表與其他選項比較有多快。

(更不用提多少短,可讀性和可維護性)

+0

感謝您的回答,但我不喜歡一個完整的日曆天表的想法,因爲這意味着我將不得不與新的日子,是不是在日曆中,每隔一段時間更新表。 – phpNutt

+0

谷歌創建日期維度,你會發現任何號碼您根據開始和結束日期將構建日期的表腳本。如果你願意,你可以在接下來的20年內填充它。 – OTTA

+0

SQL是一種基於SET的語言。爲了找到存在於一個集合中而不是另一個集合中的實體,以一種對SQL友好的方式,你需要兩個集合都存在。與其他方法相比,創建此表的開銷很小。 (有一天,通常要花4首或8個字節,所以大約100年的日期一兆字節的四分之一...) – MatBailie

1

AFAIK沒有一個語句來實現這一工作的所有數據庫...甲骨文,你可以做到這一點(MyTable是你想要的數據表檢查缺少的日期):

SELECT * FROM 
(
SELECT A.MinD + MyList.L TheDate FROM 
(SELECT MIN (dateCreated) MinD FROM MyTable) A, 
(SELECT LEVEL - 1 L FROM DUAL CONNECT BY LEVEL <= (SELECT Max (dateCreated) - MIN (dateCreated) + 1 FROM MyTable)) MyList 
) D WHERE D.TheDate NOT IN (SELECT dateCreated FROM MyTable T) 
1

假設MySQL,你可以在查詢結果中使用一個變量來進行狀態的每一行:

SELECT @last := 'date you want to start with'; 

SELECT id, dateCreated, DATE_DIFF(dateCreated, @last) AS diff, @last := dateCreated 
FROM yourtable 
ORDER BY dateCreated ASC 
HAVING diff > 1 

請注意,這不會返回實際丟失的日期,但它會返回丟失日期後的行以及丟失天數。

2

對於PostgreSQL的飛行產生的 「日期列表」 是使用generate_series很容易()函數:

with all_dates as (
    select cast((current_date - interval '4' month) as date) + i as the_date 
    from generate_series(0, extract(day from current_date - (current_date - interval '4' month))::int) as i 
) 
select ad.the_date, 
     y.id, 
     y.numOfUsers 
from all_dates t 
    left join your_table y ON y.dateCreated = t.the_date; 
0

的MySQL:

假設我們有表yourTable和日期字段d

set @day = 0; 

select v.y as `month`, v.m as `month`, v.d as `day` 
from 
(
    select y_m.y, Y_m.m, dd.d 
    from 
    (
    select distinct year(d) y, month(d) m, DAY(LAST_DAY(yourTable.d)) max_days from yourTable 
    ) y_m, 
    (
    select @day := @day+1 as `d` 
    from 
    information_schema.tables 
    limit 32 
    ) dd 
    where y_m.max_days >= dd.d 
) v 
left join 
    yourTable on (year(yourTable.d) = v.y and month(yourTable.d) = v.m and day(yourTable.d) = v.d) 
where yourTable.d is null 
; 
1

有沒有辦法做到這一點,沒有日期表,開始和結束日期或任何其他形式的迭代。

select DATEADD(day,1,left.dateCreated) as MissingDates 
from dbo.MyTable as left 
left outer join dbo.MyTable as right on DATEADD(day,1,left.dateCreated) = right.entry_time 
where right.dateCreated is null 

這將返回一列缺失日期跨度的開始日期。然後,您也可以創建另一列,通過減去1來返回缺失日期範圍中的最後日期,而不是將第一個日期添加到第二個比較表。