2010-04-16 17 views
5

ich MySQL-Tabelle haben Benutzer (id, name, join_on) kommen auf ein Datumsfeld Ich möchte ist, was man in jeden Tag zu zeigen, wie viele Anwendungen erstellt wurde ich Gruppe verwenden kann aber es wird mir nur die Daten geben, wenn Benutzer wie noch hinzukommen, wenn Datumwollte alle Termine in mysql Ergebnis erhalten

4/12/10 5 users added 
4/13/10 2 users added 
4/15/10 7 users added 

hier heute 4/14/10 fehlt und ich möchte Auflistung aller Termine in einem Monat. Ich habe eine Lösung dafür, indem ich eine andere Tabelle nur für das Hinzufügen von Datum erstellt habe und diese Tabelle links in meine Benutzertabelle auf join_on einfügt und das Gesamtergebnis ergibt, aber ich möchte das nicht so machen wie das, das ich erstellen und hinzufügen muss Einträge in der Datumstabelle weisen auf einen anderen Ansatz hin.

Vielen Dank.

+0

+1 Ich habe es in Code getan (außerhalb von SQL), aber sehr interessant zu sehen, ob einige sauberen SQL-only Lösungen – Tomas

+0

Pop-up Dies ist ein häufig gestellte und beantwortete Frage auf SO (Suche nach 'date 'und' [sql] 'oder' [mysql] '). Siehe zB http://stackoverflow.com/questions/1046865/mysql-select-all-dates-in-a-range-even-if-no-records-present – pilcrow

+0

@pilcrow: es ist eine häufig gestellte Frage, aber die verknüpfte Antwort ist in den Details nicht besonders erschöpfend. @OP: normalerweise ist diese Art von Sache nicht so einfach in Datenbanken, die rekursives SQL nicht unterstützen; noch habe ich etwas SQL geposted (mit einigen Problemen, aber es könnte nützlich sein) – Unreason

Antwort

2

Es ist ein Ansatz, das kann dies in reinem SQL tun, aber es hat Einschränkungen.

Zuerst müssen Sie eine Zahlenfolge 1,2,3 haben ... n als Zeilen (select row from rows Rückkehr annehmen kann).

Dann können Sie linken beitreten und zu Daten basierend auf Anzahl der Tage zwischen min und max konvertieren.

select @min_join_on := (select min(join_on) from user); 
select @no_rows := (select datediff(max(join_on), @min_join_on) from user)+1; 

geben Sie die gewünschte Anzahl der Zeilen, die dann können Sie

select adddate(@min_join_on, interval row day) from rows where row <= @no_rows; 

zu

verwenden eine erforderliche Folge von Daten, an denen zurückkehren, dann können Sie einen linken trete zurück an den Benutzer-Tabelle .
Die Verwendung von Variablen kann vermieden werden, wenn Sie Unterabfragen verwenden, die ich aus Gründen der Lesbarkeit abbrach.

Nun ist das Problem, dass die Anzahl der Zeilen in der Tabelle rows dann @no_rows größer sein muss. Für 10.000 Zeilen können Sie mit Datumsbereichen von bis zu 27 Jahren arbeiten, mit 100.000 Zeilen können Sie mit Datumsbereichen von bis zu 273 Jahren arbeiten (das fühlt sich wirklich schlecht an, aber ich befürchte, wenn Sie nicht gespeichert verwenden möchten Verfahren wird es peinlich aussehen und fühlen müssen).

Also, wenn Sie mit einer solchen festen Termin arbeiten kann, reicht Ihnen auch die Tabelle mit der Abfrage ersetzen können, wie diese

SELECT @row := @row + 1 as row FROM (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t, (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2, (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3, (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4, (SELECT @row:=0) r 

, die von 1 bis 10.000 gehen 10.000 Zeilen erzeugen, und es wird nicht sein furchtbar ineffizient.

So am Ende ist es in einer einzigen Abfrage machbar.

create table user(id INT NOT NULL AUTO_INCREMENT, name varchar(100), join_on date, PRIMARY KEY(id)); 

mysql> select * from user; 
+----+-------+------------+ 
| id | name | join_on | 
+----+-------+------------+ 
| 1 | user1 | 2010-04-02 | 
| 2 | user2 | 2010-04-04 | 
| 3 | user3 | 2010-04-08 | 
| 4 | user4 | 2010-04-08 | 
+----+-------+------------+ 
4 rows in set (0.00 sec) 

insert into user values (null, 'user1', '2010-04-02'), (null, 'user2', '2010-04-04'), (null, 'user3', '2010-04-08'), (null, 'user4', '2010-04-08') 


SELECT date, count(id) 
FROM (
SELECT adddate((select min(join_on) from user), row-1) as date 
FROM ( 
SELECT @row := @row + 1 as row FROM (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t, (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2, (SELECT @row:=0) r) n 
WHERE n.row <= (select datediff(max(join_on), min(join_on)) from user) + 1 
) dr LEFT JOIN user u ON dr.date = u.join_on 
GROUP BY dr.date 

+------------+-----------+ 
| date  | count(id) | 
+------------+-----------+ 
| 2010-04-02 |   1 | 
| 2010-04-03 |   0 | 
| 2010-04-04 |   1 | 
| 2010-04-05 |   0 | 
| 2010-04-06 |   0 | 
| 2010-04-07 |   0 | 
| 2010-04-08 |   2 | 
+------------+-----------+ 
7 rows in set (0.00 sec) 
4

Es könnte einfacher sein, einfach GROUP BY zu verwenden und dann in Ihrem tatsächlichen Code die fehlenden Daten hinzuzufügen (oder den gesamten Datumsbereich zu durchlaufen und eine Null auszugeben, wenn das Datum in den Abfrageergebnissen fehlt).

Nicht alles muss in SQL gelöst werden, und viele Dinge sind anderswo leichter zu lösen. :)

+0

danke für die Antwort, aber ich möchte es nur in SQL tun, da ich noch ein paar Dinge damit machen will, und außerdem werde ich noch mehr lernen Thins auch :) –

1
SELECT * FROM TABLE WHERE DATE LIKE '4/%/10' 

Diese geben u alle Daten für den Monat April 2010

Ebenso kann u jeden Monat Daten erhalten, indem Monat numerischen Wert, dh 4 in diesem Fall die Angabe

+0

es ist nicht wie ich Datum nur aus Reichweite bekommen möchte Ich möchte auch alle anderen Daten, die nicht in meinen Aufzeichnungen ist –

+1

Sie sollten mit Daten als Termine, keine Zeichenfolgen arbeiten. Der obige Code könnte Ihnen Daten für den Monat April liefern, oder es könnte Ihnen den 4. eines jeden Monats geben, oder schließlich könnte es Ihnen einen Fehler geben. – Unreason

+0

@ PankajK: In diesem Fall können Sie den Code in Ihrem Programm a/c müssen müssen. Es könnte durch Abfragen erfolgen, aber das wird die Ausführungszeit erhöhen – nik