2010-06-12 19 views
5

Ho una tabella con:SQL Count oggetti unici definiti dai parametri

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

che rappresentano oggetti definiti con i valori come:

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

voglio contare il numero di oggetti con parametri diversi usando una query SQL, quindi in questo caso sarebbe 2 oggetti unici come 1 e 3 hanno gli stessi parametri.

Non c'è alcun vincolo sul numero di parametri, ci può essere 0 o qualsiasi altro numero.

Il database è un Microsoft SQL Server 2000. Ma non mi interessa conoscere la soluzione per altri database.

+0

Come si fa a rappresentare a zero i parametri? Un NULL nella colonna 'parameters' e un vincolo o trigger per impedire qualsiasi non NULL per lo stesso' id'? – pilcrow

+0

@pilcrow: certo, c'è un'altra tabella con l'id oggetto come chiave primaria. – Eduardo

risposta

0

è possibile utilizzare una clausola di having per filtrare per due parametri unici:

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

Ho modificato la ricerca per chiarire che: Non vi è alcun vincolo sul numero di parametri che possono essere 0 o qualsiasi altro numero. – Eduardo

3

Se ho capito bene, si desidera che il numero di distinte combinazioni di parameter s per id rappresentato nella tabella, possibilmente con il numero di entità che esibiscono ciascuna di queste combinazioni distinte.

Non posso parlare per SQL Server, MySQL ma sotto si potrebbe fare qualcosa di simile:

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; 

che vi darà questa:

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

e SELECT COUNT(DISTINCT parameter_set FROM (... flattening query ...)) d vi darà il numero di set di parametri distinti.

+0

Sì, questo funzionerebbe per MySQL ma ho bisogno della soluzione per Microsoft SQL Server 2000 – Eduardo

+0

Se possibile, suggerirei di implementare la propria funzione di concatenazione di gruppo (http://sqlblog.com/blogs/adam_machanic/archive/2006 /07/12/rowset-string-concatenation-which-method-is-best.aspx, ad esempio, anche se la ricerca di "concatenazione di righe" ne darebbe altri). Penso che questa soluzione sia semplice e intuitiva. –

+0

Potrebbe non funzionare come l'OP desidera. Dice che un ID può avere zero parametri - che di solito significa un valore nullo direttamente nella tabella o in un join di sinistra. Ma "GROUP_CONCAT' ignora i valori nulli. Dovrebbe dare un risultato non valido. (Dico "dovrebbe" verus "sarà" solo perché non ho un server MySQL a portata di mano al momento, per verificare). –

2

Ok, ecco il mio tentativo. Potrebbe essere possibile implementare questa logica in un modo che non richiede 5 accessi alla stessa tabella, ma non riesco a pensarci adesso.

La logica qui è quella di eliminare prima gli oggetti duplicati, quindi contare gli ID rimanenti. La sottoquery NOT IN rappresenta oggetti con un oggetto corrispondente con un ID più piccolo. La sottoquery unisce i parametri di due oggetti t1 e t2, quindi conta quanti parametri corrispondono per ciascuna coppia t1/t2. Se il numero di parametri corrispondenti è uguale al numero di parametri in t1 e in t2, allora t2 e t1 sono corrispondenze e dovremmo escludere t1 dal set di risultati.

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) 
     ); 

Risultato su SQL Server 2008 R2:

num_groups 
3 

Per quanto riguarda gli oggetti con 0 parametri, dipende da come questi sono memorizzati, ma in generale, si avrebbe solo bisogno di aggiungere uno al rispondi sopra se ci sono oggetti con 0 parametri.

+0

In realtà questo non funziona. Fornirà valori errati se più di un ID ha zero parametri. –

1

Non esiste un metodo infallibile per eseguire questa operazione in SQL Server 2000, con le condizioni specificate, ma quanto segue funzionerà per la maggior parte delle situazioni e ti avviserà se non funzionerà.

tabella riportata, "TBL":

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

.
Creare questa funzione:

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 

.
Poi questa query:

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 

.
Darà quello che hai chiesto.
Risultati:

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