2010-06-12 16 views
5

que tienen una mesa con:SQL contar objetos únicos definidos por los parámetros

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

que representan objetos definidos con los valores como:

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

Quiero contar el número de objetos con diferentes parámetros usando una consulta SQL, entonces en este caso serían 2 objetos únicos ya que 1 y 3 tienen los mismos parámetros.

No hay restricción en el número de parámetros, puede haber 0 o cualquier otro número.

La base de datos es un Microsoft SQL Server 2000. Pero no me importa saber la solución para otras bases de datos.

+0

¿Cómo se representan los parámetros de cero? Un NULL en la columna 'parameters' y una restricción o disparador para evitar cualquier valor no NULL para ese mismo' id'? – pilcrow

+0

@pilcrow: seguro, hay otra tabla con el identificador de objeto como clave principal. – Eduardo

Respuesta

0

Se puede utilizar una cláusula de having filtrar por dos parámetros únicas:

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

He editado la búsqueda para aclarar que: No hay ninguna restricción en el número de parámetros que puede ser 0 o cualquier otro número. – Eduardo

3

Si he entendido bien, desea que el número de distintas combinaciones de parameter s por id representados en su mesa, posiblemente con el número de entidades que exhiben cada una de esas combinaciones distintas.

No puedo hablar en nombre de SQL Server, MySQL, pero bajo que podía hacer algo como esto:

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; 

que le dará la siguiente:

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

y SELECT COUNT(DISTINCT parameter_set FROM (... flattening query ...)) d le dará el número de conjuntos de parámetros distintos.

+0

Sí, esto funcionaría para MySQL pero necesito la solución para Microsoft SQL Server 2000 – Eduardo

+0

Si es posible, sugeriría implementar su propia función de concatenación de grupo (http://sqlblog.com/blogs/adam_machanic/archive/2006 /07/12/rowset-string-concatenation-which-method-is-best.aspx, por ejemplo, aunque buscar "concatenación de fila" arrojaría otros). Creo que esta solución es simple e intuitiva. –

+0

Esto puede no funcionar como lo desea el OP. Él dice que una ID puede tener cero parámetros, lo que generalmente significa un valor nulo, ya sea directamente en la tabla o en una combinación de la izquierda. Pero 'GROUP_CONCAT' ignora los nulos. Debería dar un resultado inválido. (Digo "debería" verus "will" solo porque no tengo un servidor MySQL a mano en este momento, para verificarlo). –

2

Bien, este es mi intento. Podría ser posible implementar esta lógica de una manera que no requiera 5 accesos a la misma tabla, pero no puedo pensarlo ahora.

La lógica aquí es eliminar primero los objetos duplicados, luego contar los ID restantes. La subconsulta NOT IN representa objetos que tienen un objeto coincidente con un ID más pequeño. La subconsulta se une a los parámetros de dos objetos t1 y t2, y luego cuenta cuántos parámetros coinciden para cada par t1/t2. Si el número de parámetros coincidentes es el mismo que el número de parámetros en t1 y en t2, entonces t2 y t1 son equivalentes y debemos excluir t1 del conjunto de resultados.

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

resultado en SQL Server 2008 R2:

num_groups 
3 

En cuanto a los objetos con parámetros 0, que depende de cómo se almacenan, pero en general, que había sólo tiene que añadir una a la Responda arriba si hay algún objeto con 0 parámetros.

+0

En realidad, esto no funciona. Proporcionará valores incorrectos si más de un ID tiene cero parámetros. –

1

No hay una forma infalible de hacerlo en SQL Server 2000, con las condiciones especificadas, pero lo siguiente funcionará para la mayoría de las situaciones y le avisará si no funciona.

tabla dada, "TBL":

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

.
Crear esta función:

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 

.
Entonces esta consulta:

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á lo que pidió.
Resultados:

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