2010-12-30 3 views
3

können also sagen, dass ich einige Datensätze, die wie folgt aussehen:SQL-Abfrage, die alle Daten zurückgibt nicht in einer Tabelle verwendet

2011-01-01 Cat 
2011-01-02 Dog 
2011-01-04 Horse 
2011-01-06 Lion 

Wie kann ich eine Abfrage erstellen, die 2011-01-03 und 2011-01 zurückkehren -05, dh die ungenutzten Daten. Ich poste Blogs in die Zukunft und ich möchte eine Abfrage, die mir die Tage zeigen wird, an denen ich noch nichts gepostet habe. Es würde vom aktuellen Datum bis zu 2 Wochen in die Zukunft schauen.

Update:

Ich bin nicht allzu begeistert über eine permanente Tabelle der Daten aufzubauen. Nachdem ich darüber nachgedacht habe, scheint es, als wäre die Lösung, eine kleine gespeicherte Prozedur zu erstellen, die eine temporäre Tabelle erstellt. Etwas wie:

CREATE PROCEDURE MISSING_DATES() 
BEGIN 
    CREATE TABLE TEMPORARY DATES (FUTURE DATETIME NULL) 
    INSERT INTO DATES (FUTURE) VALUES (CURDATE()) 
    INSERT INTO DATES (FUTURE) VALUES (ADDDATE(CURDATE(), INTERVAL 1 DAY)) 
    ... 
    INSERT INTO DATES (FUTURE) VALUES (ADDDATE(CURDATE(), INTERVAL 14 DAY)) 

    SELECT FUTURE FROM DATES WHERE FUTURE NOT IN (SELECT POSTDATE FROM POSTS) 

    DROP TABLE TEMPORARY DATES 
END 

ich es nur erraten ist nicht möglich, die Abwesenheit von Daten auszuwählen.

+0

Große Frage. Ich freue mich auf Antworten, weil ich auch nicht weiß, wie das geht. – Corey

+1

Sie wären überrascht, wie praktisch eine dauerhafte Datumsanzeige sein kann. Wenn Sie einen Ersatzschlüssel hinzufügen, können Sie nicht nur das Problem lösen, sondern auch Probleme wie die Berechnung der Anzahl der Tage zwischen Daten, den Tag der Woche, den Tag usw. auf einfache Arithmetik reduzieren. IMO, die Temp-Tabellen-Lösung ist unelegant und spart Ihnen keine Arbeit. –

Antwort

3

Sie haben Recht - SQL es nicht leicht machen, fehlende Daten zu identifizieren.Die übliche Technik besteht darin, Ihre Sequenz (mit Lücken) mit einer vollständigen Sequenz zu verknüpfen und diese Elemente in der letzten Sequenz auszuwählen, ohne dass ein entsprechender Partner in Ihren Daten vorhanden ist.

Also, @ BenHoffstein suggestion, um eine permanente Tabelle zu halten ist ein guter. Sie können diesen Datumsbereich dynamisch mit einem integers table erstellen. Unter der Annahme der integers Tabelle hat eine Spalte i mit Zahlen mindestens 0-13, und dass Sie Ihren Tisch seine Datumsspalte hat datestamp genannt:

SELECT candidate_date AS missing 
    FROM (SELECT CURRENT_DATE + INTERVAL i DAY AS candidate_date 
      FROM integers 
      WHERE i < 14) AS next_two_weeks 
LEFT JOIN my_table ON candidate_date = datestamp 
    WHERE datestamp is NULL; 
+0

Erstellen einer Temp-Integer-Tabelle mit den Werten 1-14 und das Ausführen dieses Skripts produziert genau das, was ich ursprünglich wollte, eine Liste, die zwei Wochen ausgeht, die nur Daten ohne Comic auflistet. –

+0

@JackBNimble, das wird funktionieren. Ich würde empfehlen, einen Tisch oder eine Ansicht mit 0 - 999 auf der Hand zu halten, damit man drei Wochen oder sechs Monate zurückschauen kann. (Ich habe es in 'util'.integers' gesetzt.) – pilcrow

0

Sie wahrscheinlich nicht, dies gefallen gehen:

select '2011-01-03', count(*) from TABLE where postdate='2011-01-03' 
    having count(*)=0 union 
select '2011-01-04', count(*) from TABLE where postdate='2011-01-04' 
    having count(*)=0 union 
select '2011-01-05', count(*) from TABLE where postdate='2011-01-05' 
    having count(*)=0 union 
... repeat for 2 weeks 

ODER

erstellen Sie eine Tabelle mit allen Tagen im Jahr 2011, dann ein LEFT JOIN, wie

select a.days_2011 
from all_days_2011 
left join TABLE on a.days_2011=TABLE.postdate 
where a.days_2011 between date(now()) and date(date_add(now(), interval 2 week)) 
and TABLE.postdate is null; 
4

One Lösung wäre es, eine separate Tabelle mit einer Spalte zu erstellen, um alle Daten von jetzt bis zur Ewigkeit zu speichern (oder wann immer Sie mit dem Bloggen aufhören wollen). Zum Beispiel:

CREATE TABLE Dates (dt DATE); 
INSERT INTO Dates VALUES ('2011-01-01'); 
INSERT INTO Dates VALUES ('2011-01-02'); 
...etc... 
INSERT INTO Dates VALUES ('2099-12-31'); 

Sobald diese Referenztabelle eingerichtet ist, können Sie einfach Outer-Joins die ungenutzten Daten, um zu bestimmen, wie so:

SELECT d.dt 
FROM Dates d LEFT JOIN Blogs b ON d.dt = b.dt 
WHERE b.dt IS NULL 

Wenn Sie die Suche auf zwei Wochen in der begrenzen möchten künftig könnte man dies auf die WHERE-Klausel hinzufügen:

AND d.dt BETWEEN NOW() AND ADDDATE(NOW(), INTERVAL 14 DAY) 
+1

+1 Der Vorteil einer Kalendertabelle (im Gegensatz zur dynamischen Generierung der Datumsserie wie in meiner Antwort) ist die Lesbarkeit - es ist einfach zu sehen, was die Abfrage versucht zu tun. – pilcrow

0

die Art und Weise Reihen zu extrahieren aus der mySQL-Datenbank über SELECT ist. Daher können Sie keine Zeilen auswählen, die nicht existieren.

Was ich tun würde, ist meine Blog-Tabelle mit allen möglichen Daten füllen (für ein Jahr, dann wiederholen Sie den Vorgang)

create table blog (
    thedate date not null, 
    thetext text null, 
    primary key (thedate)); 

eine Schleife zu tun alle Termine Einträge für das Jahr 2011 zu erstellen (ein Programm, zB $ mydate ist das Datum, das Sie einfügen möchten)

insert IGNORE into blog (thedate,thetext) values ($mydate, null); 

(das Schlüsselwort IGNORE auf einen Fehler nicht zu erzeugen (thedate ein Primärschlüssel ist), wenn thedate bereits vorhanden ist).
Dann können Sie die Werte einfügen normalerweise

insert into blog (thedate,thetext) values ($mydate, "newtext") 
    on duplicate key update thetext="newtext"; 

Schließlich leere Einträge zu wählen, müssen Sie nur noch zu

select thedate from blog where thetext is null; 
Verwandte Themen