2010-06-12 15 views
5

Ich habe eine Tabelle mit:SQL Count einzigartige Objekte durch Parameter definiert

id | parameter 
1 | A 
1 | B 
2 | A 
3 | A 
3 | B 

, die Objekte definiert mit den Werten darstellen als:

1 -> A,B 
2 -> A 
3 -> A,B 

Ich möchte die Anzahl der Objekte mit unterschiedlichen Parametern zählen mit einer SQL-Abfrage, so in diesem Fall wäre es 2 eindeutige Objekte wie 1 und 3 haben die gleichen Parameter.

Es gibt keine Beschränkung für die Anzahl der Parameter, es kann 0 oder eine andere Zahl sein.

Die Datenbank ist ein Microsoft SQL Server 2000. Aber ich weiß nicht, die Lösung für andere Datenbanken zu kennen.

+0

Wie stellen Sie Null-Parameter? Ein NULL in der 'Parameter'-Spalte und eine Einschränkung oder ein Auslöser, um irgendwelche Nicht-NULL für dieselbe 'ID' zu verhindern? – pilcrow

+0

@pilcrow: Sicher, es gibt eine andere Tabelle mit der Objekt-ID als Primärschlüssel. – Eduardo

Antwort

0

können Sie eine having-Klausel für zwei eindeutige Parameter filtern:

select count(*) 
from YourTable 
group by 
     id 
having count(distinct parameter) > 1 
+0

Ich habe die Question bearbeitet, um dies zu verdeutlichen: Es gibt keine Beschränkung für die Anzahl der Parameter, die 0 oder irgendeine andere Zahl sein kann. – Eduardo

3

Wenn ich richtig verstehe, wollen Sie die Anzahl der unterschiedlichen Kombinationen von parameter s pro id in der Tabelle dargestellt, möglicherweise mit die Anzahl der Entitäten, die jede dieser unterschiedlichen Kombinationen aufweisen.

Ich kann nicht für SQL Server sprechen, aber unter MySQL Sie so etwas wie dies tun könnte:

SELECT parameter_set, COUNT(*) AS entity_count 
    FROM (
      -- Here we "flatten" the different parameter combinations per id 
      SELECT id, 
        GROUP_CONCAT(parameter ORDER BY parameter) AS parameter_set 
       FROM tbl 
      GROUP BY id 
     ) d 
GROUP BY parameter_set; 

, die Ihnen dies:

parameter_set | entity_count 
---------------+-------------- 
A,B   |   2 -- two entities have params A, B 
A    |   1 -- one entity has param A 

und SELECT COUNT(DISTINCT parameter_set FROM (... flattening query ...)) d geben Sie die Nummer von verschiedenen Parametersätzen.

+0

Ja, das würde für MySQL funktionieren, aber ich brauche die Lösung für Microsoft SQL Server 2000 – Eduardo

+0

Wenn möglich, würde ich vorschlagen, Ihre eigene Gruppenverkettungsfunktion zu implementieren (http://sqlblog.com/blogs/adam_machanic/archive/2006 /07/12/rowset-string-concatenation-which-method-is-best.aspx zum Beispiel, obwohl die Suche nach "Zeilenverkettung" andere ergeben würde. Ich denke diese Lösung ist einfach und intuitiv. –

+0

Dies funktioniert möglicherweise nicht, wie das OP wünscht. Er sagt, dass eine ID Null-Parameter haben kann - was normalerweise einen Null-Wert bedeutet, entweder direkt in der Tabelle oder in einem linken Join. Aber 'GROUP_CONCAT' ignoriert Nullen. Es sollte ein ungültiges Ergebnis geben. (Ich sage "sollte" verus "will" nur weil ich im Moment keinen MySQL-Server zur Hand habe, um das zu verifizieren). –

2

Okay, hier ist mein Versuch. Es könnte möglich sein, diese Logik auf eine Weise zu implementieren, die nicht 5 Zugriffe auf die gleiche Tabelle erfordert, aber ich kann nicht sofort daran denken.

Die Logik hier besteht darin, zuerst doppelte Objekte zu eliminieren und dann die verbleibenden IDs zu zählen. Die Unterabfrage NOT IN repräsentiert Objekte, die ein passendes Objekt mit einer kleineren ID haben. Die Unterabfrage verbindet die Parameter zweier Objekte t1 und t2 und zählt dann, wie viele Parameter für jedes t1/t2-Paar übereinstimmen. Wenn die Anzahl der übereinstimmenden Parameter mit der Anzahl der Parameter in t1 und in t2 übereinstimmt, dann sind t2 und t1 Übereinstimmungen und wir sollten t1 von der Ergebnismenge ausschließen.

DECLARE @tab TABLE (ID int, parameter varchar(2)); 

INSERT INTO @tab 
SELECT 1, 'A' UNION ALL 
SELECT 1, 'B' UNION ALL 
SELECT 2, 'A' UNION ALL 
SELECT 3, 'A' UNION ALL 
SELECT 3, 'B' UNION ALL 
SELECT 4, 'A' UNION ALL 
SELECT 5, 'C' UNION ALL 
SELECT 5, 'D'; 

SELECT 
    COUNT(DISTINCT t.ID) AS num_groups 
FROM 
    @tab AS t 
WHERE 
    t.ID NOT IN 
     (SELECT 
      t1.ID AS ID1 
     FROM 
       @tab AS t1 
      INNER JOIN 
       @tab AS t2 
      ON 
       t1.ID > t2.ID AND 
       t1.parameter = t2.parameter 
     GROUP BY 
      t1.ID, 
      t2.ID 
     HAVING 
      COUNT(*) = (SELECT COUNT(*) FROM @tab AS dupe WHERE dupe.ID = t1.ID) AND 
      COUNT(*) = (SELECT COUNT(*) FROM @tab AS dupe WHERE dupe.ID = t2.ID) 
     ); 

Ergebnis auf SQL Server 2008 R2:

num_groups 
3 

Wie für Objekte mit 0 Parametern, es hängt davon ab, wie sie gespeichert sind, aber im Allgemeinen, dann würden Sie brauchen nur eine zu dem hinzufügen Beantworten Sie oben, ob Objekte mit 0 Parametern vorhanden sind.

+0

Eigentlich funktioniert das nicht. Es gibt falsche Werte, wenn mehr als eine ID Nullparameter hat. –

1

Es gibt keinen idiotensicheren Weg, dies in SQL Server 2000 zu tun, mit den angegebenen Bedingungen, aber das Folgende wird für die meisten Situationen funktionieren und es wird Sie warnen, wenn es nicht funktioniert.

Bei Tisch "Tabl":

ID Parameter 
1  A 
1  B 
2  A 
3  A 
3  B 
4  A 
4  NULL 
5  C 
5  D 
6  NULL 

.
Erstellen Sie diese Funktion:

CREATE FUNCTION MakeParameterListFor_tblID (@ID INT) 
RETURNS VARCHAR(8000) 
AS 
BEGIN 
    DECLARE 
     @ParameterList VARCHAR(8000), 
     @ListLen  INT 
    SET 
     @ParameterList = '' 

    SELECT 
     @ParameterList = @ParameterList + COALESCE (Parameter, '*null*') + ', ' 
    FROM 
     tbl 
    WHERE 
     ID = @ID 
    ORDER BY 
     Parameter 


    SET @ListLen  = LEN (@ParameterList) 
    IF @ListLen > 7800 -- 7800 is a SWAG. 
     SET @ParameterList = '*Caution: overflow!*' + @ParameterList 
    ELSE 
     SET @ParameterList = LEFT (@ParameterList, @ListLen-1) -- Kill trailing comma. 

    RETURN @ParameterList 
END 
GO 

.
Dann ist diese Abfrage:

SELECT 
    COUNT (ID) AS NumIDs, 
    NumParams, 
    ParamList 
FROM 
    (
     SELECT 
      ID, 
      COUNT (Parameter)     AS NumParams, 
      dbo.MakeParameterListFor_tblID (ID) AS ParamList 
     FROM 
      tbl 
     GROUP BY 
      ID 
    ) AS ParamsByID 
GROUP BY 
    ParamsByID.ParamList, 
    ParamsByID.NumParams 
ORDER BY 
    NumIDs  DESC, 
    NumParams DESC, 
    ParamList ASC 

.
Geben Sie, was Sie gefragt haben.
Ergebnisse:

NumIDs NumParams ParamList 
    2   2   A, B 
    1   2   C, D 
    1   1   *null*, A 
    1   1   A 
    1   0   *null*