2013-08-13 22 views
5

データベーステーブルに存在しない日付を取得するためのクエリがあります。日付範囲から欠落している日付を見つけよう

私はデータベースに以下の日付があります。私は、クエリ

の下に試してみました

2013-08-02 
2013-08-02 
2013-08-02 
2013-08-03 
2013-08-05 
2013-08-08 
2013-08-08 
2013-08-09 
2013-08-10 
2013-08-13 
2013-08-13 
2013-08-13

と私は以下のように予想される結果が欲しい、

2013-08-01 
2013-08-04 
2013-08-06 
2013-08-07 
2013-08-11 
2013-08-12

あなたは結果がデータベースに存在しない6日を持って見ることができるように、

SELECT 
    DISTINCT DATE(w1.start_date) + INTERVAL 1 DAY AS missing_date 
FROM 
    working w1 
LEFT JOIN 
    (SELECT DISTINCT start_date FROM working) w2 ON DATE(w1.start_date) = DATE(w2.start_date) - INTERVAL 1 DAY 
WHERE 
    w1.start_date BETWEEN '2013-08-01' AND '2013-08-13' 
AND 
    w2.start_date IS NULL;

ただし、上記の結果は次のようになります。あなたはその必要はありませんその14から4つのバックの日付を私に与えて見るが、そのまだその理由は、左の参加の3日を含めることはできませんよう

2013-08-04 
2013-08-14 
2013-08-11 
2013-08-06

私の質問に目を通して、私がこれを行うための最善の方法を教えてください。

お時間をいただきありがとうございます。

+0

"結果には、データベースに存在しない6つの日付が表示されます。"これは私を笑わせる。データには何百万もの日付がありません(少なくとも、人間は日付が何であるかを認識しています)。どのように開始値と終了値が分かっていますか? –

+0

関係代数の性質上、DBに不特定の*欠損データの数を推論させることは不可能です。あなたのテーブルにすでに存在する2つの日付の間に、空でない日付*範囲*を見つけるのが最善です。 –

+3

@GordonLinoffあなたがクエリを見るのを忘れたと思う...私はすでに 'w1.start_date BETWEEN '2013-08-01'と '2013-08-13''を設定しているので、6つの日付が失われていると言うことができます... –

答えて

14

私はあなたがことができると思います常に日付シーケンスを生成し、ちょうどNOT INを使用して、実際にexi st。これは1024日の範囲で最大になりますが、縮小または伸長が容易で、日付列は「mydate」と呼ばれ、テーブル「table1」にあります。

SELECT * FROM (
    SELECT DATE_ADD('2013-08-01', INTERVAL t4+t16+t64+t256+t1024 DAY) day 
    FROM 
    (SELECT 0 t4 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 ) t4, 
    (SELECT 0 t16 UNION ALL SELECT 4 UNION ALL SELECT 8 UNION ALL SELECT 12) t16, 
    (SELECT 0 t64 UNION ALL SELECT 16 UNION ALL SELECT 32 UNION ALL SELECT 48) t64,  
    (SELECT 0 t256 UNION ALL SELECT 64 UNION ALL SELECT 128 UNION ALL SELECT 192) t256,  
    (SELECT 0 t1024 UNION ALL SELECT 256 UNION ALL SELECT 512 UNION ALL SELECT 768) t1024  
) b 
WHERE day NOT IN (SELECT mydate FROM Table1) AND day<'2013-08-13'; 

「SQLfiddleがダウンしていない場合は追加します。ここで助けを

おかげで私が終わる午前クエリとその作業である

SELECT * FROM 
(
    SELECT DATE_ADD('2013-08-01', INTERVAL t4+t16+t64+t256+t1024 DAY) missingDates 
     FROM 
    (SELECT 0 t4 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 ) t4, 
    (SELECT 0 t16 UNION ALL SELECT 4 UNION ALL SELECT 8 UNION ALL SELECT 12) t16, 
    (SELECT 0 t64 UNION ALL SELECT 16 UNION ALL SELECT 32 UNION ALL SELECT 48) t64,  
    (SELECT 0 t256 UNION ALL SELECT 64 UNION ALL SELECT 128 UNION ALL SELECT 192) t256,  
    (SELECT 0 t1024 UNION ALL SELECT 256 UNION ALL SELECT 512 UNION ALL SELECT 768) t1024  
) b 
WHERE 
    missingDates NOT IN (SELECT DATE_FORMAT(start_date,'%Y-%m-%d') 
      FROM 
       working GROUP BY start_date) 
    AND 
    missingDates < '2013-08-13'; 
私は誰もが(1024以上の日を希望する場合Dipeshことにより、優れた答えにこれを追加している
+0

ヒントとコードをありがとう....私はあなたのクエリを使用し、いくつかのパラメータを変更し、問題を解決しました。私は他の人に役立つように私のクエリを追加しています。 –

+1

非常に巧妙な答え! –

+0

私は1つの質問を持っています...どうすれば個々のユーザーを確認するための条件を追加することができます..? –

2

これは、私はそれを行うだろうかです:

$db_dates = array (
'2013-08-02', 
'2013-08-03', 
'2013-08-05', 
'2013-08-08', 
'2013-08-09', 
'2013-08-10', 
'2013-08-13' 
); 
$missing = array(); 
$month = "08"; 
$year = "2013"; 
$day_start = 1; 
$day_end = 14 
for ($i=$day_start; $i<$day_end; $i++) { 
    $day = $i; 
    if ($i<10) { 
     $day = "0".$i; 
    } 
    $check_date = $year."-".$month."-".$day; 
    if (!in_array($check_date, $db_dates)) { 
     array_push($missing, $check_date); 
    } 
} 
print_r($missing); 

私はちょうどその間隔にそれを作ったが、あなただけの別の間隔を定義するか、それは全体の年のために働くことができます。

+0

のrownumの数字のリストのいずれかに基づいて 'ddd'と比較することを検討するかもしれません。 –

+0

質問は、まだ十分な担当者、ごめんなさい、ごめんなさい。 – Tiago

+0

+1私の問題を解決しようとしています...ありがとう –

0

私はデータウェアハウス型の状況で、この中で解決するような方法は、適切な期間にわたって日付で「静的」の表を移入することです(googleからeasyあるもののこのタイプのためのサンプル・スクリプトがあります)、その後left outer joinまたはright outer joinあなたのテーブル:一致するものがない行は欠落した日付です。

3

おそらくLEFT JOINでそれを使用できるように専用のCalendarテーブルを作成するのがよいでしょう。

テーブルを必要に応じて作成することもできますが、そのような大量のデータを表すわけではないため、以下のストアドプロシージャを使用してすべてを一度作成するのが最も簡単で、 :おおよそ推定以下その15キロバイトで表し

この例で
-- 
-- Create a dedicated "Calendar" table 
-- 
CREATE TABLE Calendar (day DATE PRIMARY KEY); 

DELIMITER // 
CREATE PROCEDURE init_calendar(IN pStart DATE, IN pEnd DATE) 
BEGIN 
    SET @theDate := pStart; 
    REPEAT 
     -- Here I use *IGNORE* in order to be able 
     -- to call init_calendar again for extend the 
     -- "calendar range" without to bother with 
     -- "overlapping" dates 
     INSERT IGNORE INTO Calendar VALUES (@theDate); 
     SET @theDate := @theDate + INTERVAL 1 DAY; 
    UNTIL @theDate > pEnd END REPEAT; 
END; // 
DELIMITER ; 

CALL init_calendar('2010-01-01','2015-12-31'); 

、カレンダーホールド2191日間連続して、。そして、21世紀のすべての日付を保存することは、その300KB未満を表すでしょう...

質問で説明したように今、これはあなたの実際のデータテーブルである:

-- 
-- *Your* actual data table 
-- 
CREATE TABLE tbl (theDate DATE); 
INSERT INTO tbl VALUES 
    ('2013-08-02'), 
    ('2013-08-02'), 
    ('2013-08-02'), 
    ('2013-08-03'), 
    ('2013-08-05'), 
    ('2013-08-08'), 
    ('2013-08-08'), 
    ('2013-08-09'), 
    ('2013-08-10'), 
    ('2013-08-13'), 
    ('2013-08-13'), 
    ('2013-08-13'); 

そして最後にクエリ:

-- 
-- Now the query to find date not "in range" 
-- 

SET @start = '2013-08-01'; 
SET @end = '2013-08-13'; 

SELECT Calendar.day FROM Calendar LEFT JOIN tbl 
    ON Calendar.day = tbl.theDate 
    WHERE Calendar.day BETWEEN @start AND @end 
    AND tbl.theDate IS NULL; 

生産:

+------------+ 
| day  | 
+------------+ 
| 2013-08-01 | 
| 2013-08-04 | 
| 2013-08-06 | 
| 2013-08-07 | 
| 2013-08-11 | 
| 2013-08-12 | 
+------------+ 
0
DECLARE @date date; 
declare @dt_cnt int = 0; 
set @date='2014-11-1'; 
while @date < '2014-12-31' 
begin 
    select @dt_cnt = COUNT(att_id) from date_table where [email protected] ; 

     if(@dt_cnt = 0) 
     BEGIN 
     print @date 
     END 
     set @date = DATEADD(day,1,@date); 
end 
0

または時間)。私は2015年から2046年にかけて279936時間以内に生成しました。

SELECT 
DATE_ADD('2015-01-01', INTERVAL 
POWER(6,6)*t6 + POWER(6,5)*t5 + POWER(6,4)*t4 + POWER(6,3)*t3 + POWER(6,2)*t2 + 
POWER(6,1)*t1 + t0 
HOUR) AS period 
FROM 
(SELECT 0 t0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t0, 
(SELECT 0 t1 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t1, 
(SELECT 0 t2 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t2, 
(SELECT 0 t3 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t3, 
(SELECT 0 t4 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t4, 
(SELECT 0 t5 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t5, 
(SELECT 0 t6 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) t6 
ORDER BY period 

これを回答クエリにプラグインするだけです。

関連する問題