2013-02-26 9 views
5

davon aus, dass ich eine db haben, die eine horizontale Struktur wie dieses:Wie kann man horizontale Werte in einer Datenbank zählen?

ID | NAME | DATA1 | DATA2 | DATA3 | DATA4 | DATA5 | DATA6 | DATA7 
1 | mmm | 0 | 1 | 0 | 3 | 5 | 1 | 0 
2 | bbb | 0 | 0 | 0 | 1 | 0 | 1 | 1 

die Informationen die Datenfelder sind, und ich möchte alle Male zählen, dass eine bestimmte Diskriminante, wie „mehr als 0 "

die Art und Weise habe ich es Schleife trought alle Felder ist, und zählen, oder COUNT() jedes DATA Feld, so SUM() diese 7 Anfragen ... jemand eine andere Idee?

in diesem Fall das Ergebnis, so würde "count every DATA field with a value over 0" = 7

+2

Haben Sie diese dynamisch tun müssen, oder die Spalten festgelegt sind? –

+0

Nun, nehmen wir an, die Spalte ist fest, so dass die Coulmn sind von DATA1 bis DATA7 in der Tat eine dynamische Lösung sollte nett sein. –

+1

zuerst normalisieren Sie Ihre Daten – Strawberry

Antwort

5

Es gibt keinen eingebauten Syntax, die Sie auf eine Reihe von Spalten dynamisch beziehen würde es ermöglichen, das heißt, ohne sie explizit zu benennen. Wenn Sie die Dynamik wünschen, müssen Sie Metadaten abfragen, um die erforderlichen Spaltennamen zu erhalten, und dann die endgültige Abfrage dynamisch erstellen.

Aber zuvor müssten Sie noch eine Idee haben, wie genau die dynamische Abfrage ausgeführt werden sollte, um den Job selbst auszuführen. So müssen Sie zuerst das Problem auf einem endlichen Spaltensatz lösen.

Es gibt mehr als eine Möglichkeit, dieses Problem zu lösen. Die method suggested by @bluefeet ist wahrscheinlich eine der klareren und weniger effizienten. Sie könnten mindestens zwei Alternativen versuchen:

  1. Count jede Spalte separat bedingte Aggregation verwenden und alle Ergebnisse in einem Ausdruck aufaddieren: (. Der OR NULL Trick ist here erklärt)

    SELECT 
        COUNT(DATA1 > 0 OR NULL) + 
        COUNT(DATA2 > 0 OR NULL) + 
        COUNT(DATA3 > 0 OR NULL) + 
        COUNT(DATA4 > 0 OR NULL) + 
        COUNT(DATA5 > 0 OR NULL) + 
        COUNT(DATA6 > 0 OR NULL) + 
        COUNT(DATA7 > 0 OR NULL) AS TOTAL 
    FROM yourtable 
    ; 
    

  2. Entsperren Sie die DATA Spalten mithilfe einer Kreuzverbindung zu einer virtuellen Tabelle, und wenden Sie dann die Bedingung auf die nicht gespaltene Spalte an:

    SELECT 
        COUNT(*) AS TOTAL 
    FROM (
        SELECT 
        CASE s.col 
         WHEN 'DATA1' THEN DATA1 
         WHEN 'DATA2' THEN DATA2 
         WHEN 'DATA3' THEN DATA3 
         WHEN 'DATA4' THEN DATA4 
         WHEN 'DATA5' THEN DATA5 
         WHEN 'DATA6' THEN DATA6 
         WHEN 'DATA7' THEN DATA7 
        END AS DATA 
        FROM yourtable 
        CROSS JOIN (
        SELECT 'DATA1' AS col 
        UNION ALL SELECT 'DATA2' 
        UNION ALL SELECT 'DATA3' 
        UNION ALL SELECT 'DATA4' 
        UNION ALL SELECT 'DATA5' 
        UNION ALL SELECT 'DATA6' 
        UNION ALL SELECT 'DATA7' 
    ) s 
    ) s 
    WHERE DATA > 0 
    ; 
    

    (In gewisser Weise ist dies ähnlich wie @ bluefeet Vorschlag, es funktioniert einfach keine UNIONs beschäftigen.)

+0

sehr elegant und gut erklärt, vielen Dank, der OR NULL Trick ist wirklich nett! –

3

werden, da Ihre Daten, die Sie Entpivotisierung die Daten, um das Ergebnis zu erhalten nicht normalisiert sollte. MySQL hat keine Unpivot-Funktion, so dass Sie mit einer UNION ALL-Abfrage Ihre Spalten in Zeilen konvertieren können. Sobald sich die Daten in den Zeilen befinden, können Sie die Anzahl der Werte einfach zählen. Ich würde etwas Ähnliches wie diese verwenden:

select count(*) total 
from 
(
    select id, name, 'data1' col, data1 as value 
    from yourtable 
    union all 
    select id, name, 'data2' col, data2 as value 
    from yourtable 
    union all 
    select id, name, 'data3' col, data3 as value 
    from yourtable 
    union all 
    select id, name, 'data4' col, data4 as value 
    from yourtable 
    union all 
    select id, name, 'data5' col, data5 as value 
    from yourtable 
    union all 
    select id, name, 'data6' col, data6 as value 
    from yourtable 
    union all 
    select id, name, 'data7' col, data7 as value 
    from yourtable 
) src 
where value > 0 

Siehe SQL Fiddle with Demo

+0

Union alle - was ist mit Leistung? – VAV

+0

@VAV 'UNION ALL' ist besser als' UNION', da doppelte Datensätze nicht entfernt werden. – Taryn

+1

ja, und machen Sie keine "Sortierung", aber meine Frage über 7-fache "Union" und Aggregation der resultierenden Datensatz für große Tabellen - ist es Produktionslösung? – VAV

Verwandte Themen