2016-04-20 2 views
1

ich die Zählung von verschiedenen Athleten von einem mal Tisch bekommen müssen wo Zeit weniger als einige andere-Zeit ist. Aber der schwierige Teil ist, dass , wenn es überhaupt keine Zeiten gibt (zum Vergleich, Ich brauche NULL im Gegenzug erhalten).MySQL eine Abfrage COUNT-ing DISTINCT Werte oder NULL optimieren, wenn keine Zeilen

Lassen Sie mich Ihnen ein Beispiel geben:

CREATE TABLE `teams` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) NOT NULL, 
    PRIMARY KEY (`id`) 
); 

INSERT INTO teams 
VALUES (NULL, 'Texas'), (NULL,'Oklahoma'); 

mysql> select * from teams; 
+----+----------+ 
| id | name  | 
+----+----------+ 
| 1 | Texas | 
| 2 | Oklahoma | 
+----+----------+ 


CREATE TABLE `times` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `team_id` int(11) NOT NULL, 
    `time` decimal(8,2) NOT NULL, 
    `athlete` varchar(255) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `team_id` (`team_id`) 
); 

INSERT INTO times VALUES 
    (NULL, 1, 19.10, 'Dave'), 
    (NULL, 1, 19.09, 'Dave'), 
    (NULL, 1, 19.07, 'Dave'), 
    (NULL, 1, 19.56, 'John'), 
    (NULL, 1, 19.60, 'John'), 
    (NULL, 1, 19.75, 'John'); 

mysql> select * from times; 
+----+---------+-------+---------+ 
| id | team_id | time | athlete | 
+----+---------+-------+---------+ 
| 1 |  1 | 19.10 | Dave | 
| 2 |  1 | 19.09 | Dave | 
| 3 |  1 | 19.07 | Dave | 
| 4 |  1 | 19.56 | John | 
| 5 |  1 | 19.60 | John | 
| 6 |  1 | 19.75 | John | 
+----+---------+-------+---------+ 

Bisher haben wir zwei Teams haben. Team 1 hat zwei Athleten mit 6 mal und Team 2 hat keine Athleten (und Zeiten jeweils).

Wenn ich will wissen, was ich tun kann:

SELECT COUNT(DISTINCT athlete) FROM times WHERE time < 19.50 and team_id = 1; 
+-------------------------+ 
| COUNT(DISTINCT athlete) | 
+-------------------------+ 
|      1 | 
+-------------------------+ 

was richtig ist.

Und wenn ich will How many Athletes from Texas are faster than 19.00

SELECT COUNT(DISTINCT athlete) FROM times WHERE time < 19.00 and team_id = 1; 
+-------------------------+ 
| COUNT(DISTINCT athlete) | 
+-------------------------+ 
|      0 | 
+-------------------------+ 

auch richtig ist zu überprüfen (denn wir haben zwei Athleten von Texas).

Aber wenn ich überprüfen möchten: How many Athletes from Oklahoma are faster than 19.00

SELECT COUNT(DISTINCT athlete) FROM times WHERE time < 19.00 and team_id = 2; 
+-------------------------+ 
| COUNT(DISTINCT athlete) | 
+-------------------------+ 
|      0 | 
+-------------------------+ 

ist nicht korrekt weil wir keine Zeiten von Oklahoma haben. Also hier muss ich NULL im Gegenzug bekommen.

ich es geschafft, eine Lösung mit einer Unterabfrage zu finden:

SELECT 
    IF(
    EXISTS(
     SELECT 1 FROM times WHERE team_id = 2 
    ), 
    COUNT(DISTINCT athlete), 
    NULL 
) as count 
FROM `times` 
WHERE 
    team_id = 2 AND time < 19.00; 
+-------+ 
| count | 
+-------+ 
| NULL | 
+-------+ 

was richtig ist, und wenn ich es Texas für testen, die ich erhalten:

SELECT 
    IF(
    EXISTS(
     SELECT 1 FROM times WHERE team_id = 1 
    ), 
    COUNT(DISTINCT athlete), 
    NULL 
) as count 
FROM `times` 
WHERE 
    team_id = 1 AND time < 19.00; 

+-------+ 
| count | 
+-------+ 
|  0 | 
+-------+ 

Es die richtige Antwort gibt.

Aber das Problem ist, dass ich ein sub-query verwendet, die haben alle Filter der Hauptabfrage zu imitieren mit Ausnahme der time < 19.00. In meiner realen Anwendung gibt es viel mehr Filter und ich suche nach einer Lösung ohne Unterabfrage.

Eine Sache, die den Sinn kam, war SUM zu verwenden (CASE)

SELECT SUM(CASE 
    WHEN time < 19.50 
    THEN 1 
    ELSE 0 
    END) as count 
FROM `times` 
WHERE team_id = 2; 

+-------+ 
| count | 
+-------+ 
| NULL | 
+-------+ 

Das Problem ist, dass dies Zählen mal nicht unterscheidbar Athleten, also für Texas ich die falsche Zahl erhalten;

SELECT SUM(CASE 
    WHEN time < 19.50 
    THEN 1 
    ELSE 0 
    END) as count 
FROM `times` 
WHERE team_id = 1; 

+-------+ 
| count | 
+-------+ 
|  3 | 
+-------+ 

ich 3-mal schneller dass 19.50 statt 1 Athlet schneller als 19.50.

+0

'19 .50' bekommen, ist eine Zeichenfolge. 19.50 ist eine Zahl – Strawberry

+0

'MySQL' wirft richtig '19 .50 'auf Nummer. Wie auch immer. – Todor

Antwort

0

über Wie ...

SELECT a.name 
    , MAX(b.athlete < 19.50) faster 
    FROM teams a 
    LEFT 
    JOIN times b 
    ON b.team_id = a.id 
GROUP BY a.name; 
+0

Netter Trick, aber wenn ich "19.50" mit "20.00" ändere, muss ich "2" als Zahl erhalten, weil es zwei Athleten gibt, die schneller sind als "20.00". – Todor

+0

Ah, ok- ein paar Optimierungen nötig ... – Strawberry

+0

Ich denke, ich habe eine Lösung gefunden, die ich in wenigen Minuten veröffentlichen werde. – Todor

0

OK Ich glaube, ich eine Lösung gefunden, wieder eine Unterabfrage hat, aber zumindest muss ich gewohnt der Filter alle zweimal wiederholen (was mir jetzt erfüllen kann wenn es nicht besser ist). Hier ist es:

SELECT 
    SUM(CASE WHEN a.time < 19.00 THEN 1 ELSE 0 END) as count 
FROM (
    SELECT athlete, min(time) as time 
    FROM times 
    WHERE team_id = 2 group by athlete 
) a; 

So kann ich NULL für Spieler 2 und 0 für Spieler 1

Verwandte Themen