2013-08-20 14 views
6

Mam tabeli jak poniżej:MySQL odjąć dwie kolumny count

client msg_type msg_body id 
------ -------- -------- --- 
123  typeA  success abc 
123  typeB  success abc 
456  typeA  success abc 
456  typeB  failure abc 
123  typeA  success abc 
123  typeA  success abc 
789  typeA  success def 
789  typeB  success def 

itp

chciałbym wyjście tak:

client diff id 
------ ---- --- 
123  2  abc 
456  1  abc 
789  0  def 

gdzie diff jest liczba typeA:success wiadomości - typeB:success wiadomości. Mogę liczyć na sukces TypeA używając coś takiego:

select client, count(*) from mytable 
where msg_type="typeA" and msg_body="success" 

Jednak nie mogę dowiedzieć się, jak umieścić inną liczbę tam (na TypeB), a także odejmować. Próbowałem coś takiego:

select client, count(*) from mytable 
where msg_type="typeA" and msg_body="success" - count(*) 
from mytable where msg_type="typeB" and msg_body="success" 

Ale oczywiście to nie działa, albo nie będę tu pytać. :) Jakakolwiek rada?

Edytuj: dodano kolejną kolumnę. Próbowałem dwie podane sugestie, ale wydaje się, że zwracają wyniki tylko dla jednego z identyfikatorów, a nie dla obu.

Edit # 2: Próbowałem owijania zapytania SELECT z:

select id, count(*) from (select ...) as anothertable where count_a_minus_count_b = 0; 

Miałem nadzieję wyjście byłoby jak:

id count 
--- ----- 
abc 2 
def 1 

gdzie liczba to liczba klientów, gdy różnica między typeA: success i typeB: success to 0.

+0

Re: „Starałem dwie podane sugestie, ale wydaje się, że tylko zwracają wyniki jeden z nich, nie oba ": Wszystkie odpowiedzi pokazały, jak obliczyć różnicę między zliczeniami; i myślę, że wszyscy byli o tym całkiem jasni. Zamiast po prostu próbować sugestii, nie czytając ich, polecam ci próbę uczenia się od nich i zadawania pytań, jeśli istnieją części, których nie rozumiesz. : -/ – ruakh

+0

@ruakh Myślałem, że rozumiem zapytania, które prowadziłem, dlatego próbowałem różnych rzeczy. Myślę, że dostałem to z: wybierz identyfikator, policz (*) z (SELECT id, klient, \t COUNT (CASE WHEN msg_type = 'typeA' THEN 1 END) \t - COUNT (CASE WHEN msg_type = 'typeB' TO 1 End) jako count_a_minus_count_b \t Z mojatabela \t gDZIE msg_body = 'sukcesu' \t GROUP \t według klienta), a sometable gdzie count_a_minus_count_b <1 grupa o id; – user2406467

+0

powiązane z sumą http://stackoverflow.com/questions/826365/how-do-i-add-two-count-results-together –

Odpowiedz

3

zlicza wartości inne niż null, więc możesz skonstruować wyrażenie, które ma wartość inną niż null, gdy msg_type = 'typeA' i wyrażenie, które ma wartość inną niż null, gdy msg_type = 'typeB'. Na przykład:

SELECT client, 
     COUNT(CASE WHEN msg_type = 'typeA' THEN 1 END) AS count_a, 
     COUNT(CASE WHEN msg_type = 'typeB' THEN 1 END) AS count_b, 
     COUNT(CASE WHEN msg_type = 'typeA' THEN 1 END) 
     - COUNT(CASE WHEN msg_type = 'typeB' THEN 1 END) AS count_a_minus_count_b 
    FROM mytable 
WHERE msg_body = 'success' 
GROUP 
    BY client 
; 

(Zastrzeżenie:. Nie testowane)

+0

* "(Uwaga: nie testowano.)" * - Sprawdziło się dobrze dla mnie. Szukałem czegoś takiego i bardzo mi pomogłem. * Pozdrawiam * –

+0

@ Fred-ii-: Miło mi to słyszeć! :-) – ruakh

+0

Dzięki :-) Nie jestem guru MySQL, ale mam swoje chwile. Jednak znam dobrą składnię, gdy ją widzę i co miałem na myśli, co było CASE, ale nie wiedziałem, jak go użyć do tego, co chciałem osiągnąć. Musiałem zrobić drobną modyfikację, ale na końcu wszystko pięknie się skończyło. *Twoje zdrowie* –

0

Proszę bardzo:

select client, 
    (sum(case when msg_type='typeA' and msg_body='success' then 1 else 0 end) - 
    sum(case when msg_type='typeB' and msg_body='success' then 1 else 0 end)) as diff 
from your_table 
group by client 
0

Oto jeden ze sposobów, aby uzyskać wynik:

SELECT t.client 
    , SUM(t.msg_type<=>'typeA' AND t.msg_body<=>'success') 
    - SUM(t.msg_type<=>'typeB' AND t.msg_body<=>'success') AS diff 
    FROM mytable t 
GROUP BY t.client 

(wyrażeniach w tym zapytaniu są specyficzne dla MySQL, dla bardziej przenośnego zapytania użyj mniej zwięzłego wyrażenia CASE, aby uzyskać równoważny wynik.)


Jako bardziej zwięzły i ukrywane alternatywa do powrotu tego samego rezultatu:

SELECT t.client 
    , SUM((t.msg_body<=>'success')*((t.msg_type<=>'typeA')+(t.msg_type<=>'typeB')*-1)) AS diff 
    FROM mytable t 
GROUP BY t.client 
1

Innym sposobem:

SELECT 
    d.client, COALESCE(a.cnt, 0) - COALESCE(b.cnt, 0) AS diff, d.id 
FROM 
    (SELECT DISTINCT client, id 
     FROM mytable 
    ) AS d 

    LEFT JOIN 
    (SELECT client, COUNT(*) AS cnt, id 
     FROM mytable 
     WHERE msg_type = 'typeA' 
     AND msg_body = 'success' 
     GROUP BY client, id 
    ) AS a 
    ON d.client = a.client 
    AND d.id = a.id 

    LEFT JOIN 
    (SELECT client, COUNT(*) AS cnt, id 
     FROM mytable 
     WHERE msg_type = 'typeB' 
     AND msg_body = 'success' 
     GROUP BY client, id 
    ) AS b 
    ON d.client = b.client 
    AND d.id = b.id ; 

Testowane na SQL-Fiddle