2010-09-07 17 views
6

Cuando se dan dos conjuntosTSQL comparación de dos conjuntos de

s1 = {a, b, c, d} s2 = {b, c, d, a}

(es decir)

TableA 

Item 
a 
b 
c 
d 

TableB 

Item 
b 
c 
d 
a 

Cómo escribir consultas SQL para mostrar "Los elementos en la tabla A y la tabla B son iguales". [Sin el uso de SP o UDF]

salida

Elements in TableA and TableB contains identical sets 
+0

¿No quieres que se cruzan ** ** ellos? –

+0

Por cierto, si necesita ** buscar ** conjuntos coincidentes dentro de un conjunto * colección *, ese es un problema diferente, y las soluciones aquí pueden no ser de mucha ayuda. –

Respuesta

8

Uso:

SELECT CASE 
     WHEN COUNT(*) = (SELECT COUNT(*) FROM a) 
      AND COUNT(*) = (SELECT COUNT(*) FROM b) THEN 'Elements in TableA and TableB contains identical sets' 
     ELSE 'TableA and TableB do NOT contain identical sets' 
     END 
    FROM (SELECT a.col 
      FROM a 
     INTERSECT 
     SELECT b.col 
      FROM b) x 

de prueba con:

WITH a AS (
    SELECT 'a' AS col 
    UNION ALL 
    SELECT 'b' 
    UNION ALL 
    SELECT 'c' 
    UNION ALL 
    SELECT 'd'), 
    b AS (
    SELECT 'b' AS col 
    UNION ALL 
    SELECT 'c' 
    UNION ALL 
    SELECT 'd' 
    UNION ALL 
    SELECT 'a') 
SELECT CASE 
     WHEN COUNT(*) = (SELECT COUNT(*) FROM a) 
      AND COUNT(*) = (SELECT COUNT(*) FROM b) THEN 'yes' 
     ELSE 'no' 
     END 
    FROM (SELECT a.col 
      FROM a 
     INTERSECT 
     SELECT b.col 
      FROM b) x 
+1

Información muy interesante sobre los costos del subárbol. –

+0

Eso es 2 lecturas por tabla + 1 unión. ¿Nadie sabe cómo usar 'FULL JOIN'? –

+0

@Peter: Ejecuté su opción FULL JOIN, hay un margen de rendimiento extremadamente amplio entre su FULL JOIN y el uso de INTERSECT o EXCEPT (en SS2005 de todos modos). Imagino que el costo ligeramente más alto para INTERSECT (en comparación con la versión EXCEPT de Nix) se debe a los recuentos para garantizar que se muestre el mensaje adecuado. –

3

Mi monstrocity:

;with SetA as 
(select 'a' c union 
select 'b' union 
select 'c') 
, SetB as 
(select 'b' c union 
select 'c' union 
select 'a' union 
select 'd' 
) 
select case (select count(*) from (
select * from SetA except select * from SetB 
union 
select * from SetB except select * from SetA 
)t) 
when 0 then 'Equal' else 'NotEqual' end 'Equality' 
+0

Costo del subárbol de 0.0178567 - un cabello mejor que la respuesta de cmsjr –

+0

Mi AEP dice que el STC es 0.01129. Pero, de nuevo, acabo de ejecutar la consulta como un todo, sin preparar esos conjuntos de antemano. –

+0

Ejecuto dos pasadas para verificar que la consulta devuelva resultados válidos para muestras falsas y positivas. No publicaría el costo si la consulta no supera las pruebas preliminares. –

2

podría hacerlo con SALVO y un caso

select 
    case 
    when count (1)=0 
     then 'Elements in TableA and TableB contains identical sets' 
    else 'Nope' end from (
     select item from s1 
     EXCEPT 
     select item from s2 
) b 
+0

Me gusta esta solución. :) –

+2

s2 podría tener más elementos que s1, pero esta consulta afirmaría que son idénticos. –

+0

Algunos argumentarían que los conjuntos siguen siendo los mismos, entonces podrías hacer los recuentos si lo deseas, o podrías hacer sumas de verificación si estás realmente aburrido. – Nix

3

Cuidado, que voy a usar una cruz de Ingreso.

Declare @t1 table(val varchar(20)) 
Declare @t2 table(val varchar(20)) 


insert into @t1 values ('a') 
insert into @t1 values ('b') 
insert into @t1 values ('c') 
insert into @t1 values ('d') 


insert into @t2 values ('c') 
insert into @t2 values ('d') 
insert into @t2 values ('b') 
insert into @t2 values ('a') 

select 
    case when 
    count(1) = 
    (((Select count(1) from @t1) 
    + (Select count(1) from @t2))/2.0) 
    then 1 else 0 end as SetsMatch from 
@t1 t1 cross join @t2 t2 
where t1.val = t2.val 
+0

Costo del subárbol de 0.0178713 - las alternativas 'INTERSECT' y' EXCEPT' funcionan de manera más eficiente. –

+0

parece una unión interna para mí. –

+0

@cmsjr: [CROSS JOIN es compatible con SQL Server 2000] (http://msdn.microsoft.com/en-us/library/aa259187%28SQL.80%29.aspx), así que supongo que te refieres a cómo [ INTERSECT y EXCEPT] (http://msdn.microsoft.com/en-us/library/ms188055.aspx) son la funcionalidad 2005+? Actualización =) –

5

Algo como esto, utilizando FULL JOIN:

SELECT 
    CASE 
    WHEN EXISTS (
     SELECT * FROM s1 FULL JOIN s2 ON s1.Item = s2.Item 
     WHERE s1.Item IS NULL OR s2.Item IS NULL 
    ) 
    THEN 'Elements in tableA and tableB are not equal' 
    ELSE 'Elements in tableA and tableB are equal' 
    END 

Esto tiene la virtud de un cortocircuito en la primera no partido, a diferencia de otras soluciones que requieren 2 scans completos de cada tabla (una vez para el COUNT (*), una vez para JOIN/INTERSECT).

El costo estimado es significativamente menor que otras soluciones.

+0

Mi enfoque inicial. ¡Supongo que no es lo suficientemente divertido! :) –

+0

Costo del Subárbol real (para mí) de 0.0178565 - * apenas * menor que la respuesta de Denis, una alternativa ligeramente mejor que la respuesta de cmsjr ... [Consideración para la pregunta de cmsjr sobre las alternativas de SS2000] (http://msdn.microsoft.com/ en-us/library/aa259187% 28SQL.80% 29.aspx). –

+0

¡Vaya @Peter! +1 para ti. – cmsjr

1

Como este hilo fue muy útil para mí, pensé en compartir mi solución.

Tuve un problema similar, quizás de aplicación más general que esta comparación específica de un solo conjunto. Estaba tratando de encontrar la identificación de un elemento que tenía un conjunto de elementos secundarios de elementos múltiples que coincidían con un conjunto de elementos de varios elementos.

La información de esquema relevante es:

table events, pk id 
table solutions, pk id, fk event_id -> events 
table solution_sources, fk solutionid -> solutions 
    columns unitsourceid, alpha 

Consulta: encontrar la solución para el evento con id 110 que tiene el conjunto de solution_sources que coinciden con el conjunto de (unitsourceid, alfa) en ss_tmp. (Esto también se puede hacer sin la tabla tmp, creo.)

Solución:

with solutionids as (
    select y.solutionid from (
    select ss.solutionid, count(ss.solutionid) x 
     from solutions s, solution_sources ss 
     where s.event_id = 110 and ss.solutionid = s.id 
     group by ss.solutionid 
) y where y.x = (select count(*) from ss_tmp) 
) 
select solutionids.solutionid from solutionids where 
(
select case 
    when count(*) = (select count(*) from ss_tmp) then true 
    else false 
    end 
    from 
     (SELECT unitsourceid, alpha FROM solution_sources 
      where solutionid = solutionids.solutionid 
      INTERSECT 
     SELECT unitsourceid, alpha FROM ss_tmp) x 
) 

analiza una consulta de prueba de 4 elementos y una base de datos de prueba que tenía una solución coincidente (mismo número de niños elementos, cada uno que coincidía), varias soluciones completamente incompatibles, y 1 solución que tenía 3 elementos secundarios coincidentes, 1 solución que tenía los 4 elementos secundarios coincidentes, más un elemento adicional y 1 solución que tenía 4 elementos secundarios, de los cuales 3 de los 4 coincide con la consulta. Solo se devolvió la identificación del emparejamiento verdadero.

muchas gracias -Linus

Cuestiones relacionadas