2009-04-25 9 views
18

Estoy construyendo una aplicación que genera dinámicamente sql para buscar filas de una Tabla particular (esta es la clase de dominio principal, como un Empleado).Obteniendo filas distintas de una combinación externa izquierda

Hay tres tablas Table1, Table2 y Table1Table2Map. Table1 tiene una relación muchos a muchos con Table2, y se asigna a través de la tabla Table1Table2Map. Pero como Table1 es mi mesa principal, la relación es virtualmente como una a muchas.

Mi aplicación genera un sql que básicamente da un conjunto de resultados que contiene filas de todas estas tablas. La cláusula de selección y las uniones no cambian, mientras que la cláusula where se genera en función de la interacción del usuario. En cualquier caso, no quiero filas duplicadas de Table1 en mi conjunto de resultados, ya que es la tabla principal para la visualización de resultados. En este momento la consulta que está siendo generada es así:

select distinct Table1.Id as Id, Table1.Name, Table2.Description from Table1 
left outer join Table1Table2Map on (Table1Table2Map.Table1Id = Table1.Id) 
left outer join Table2 on (Table2.Id = Table1Table2Map.Table2Id) 

Para simplificar he excluido la cláusula where. El problema es cuando hay varias filas en Table2 para Table1 aunque he dicho distinto de Table1.Id el conjunto de resultados tiene filas duplicadas de Table1, ya que tiene que seleccionar todas las filas coincidentes en Table2.

Para obtener más información, considere que para una fila en la Tabla 1 con Id = 1 hay dos filas en Table1Table2Map (1, 1) y (1, 2) que mapean Table1 a dos filas en Table2 con ids 1, 2. la consulta mencionada anteriormente devuelve filas duplicadas para este caso. Ahora quiero que la consulta devuelva la fila de Table1 con Id 1 solo una vez. Esto se debe a que solo hay una fila en Table2 que es como un valor activo para la entrada correspondiente en Table1 (esta información se encuentra en la tabla de asignación). ¿Hay alguna manera de evitar filas duplicadas de Table1?

Creo que hay un problema básico en la forma en que trato de resolver el problema, pero no puedo averiguar de qué se trata. Gracias por adelantado.

+0

¿Cómo distingue qué fila está "activa" en la Tabla2? – Sung

Respuesta

22

Probar:

left outer join (select distinct YOUR_COLUMNS_HERE ...) SUBQUERY_ALIAS on ... 

En otras palabras, no se unen directamente contra la mesa, se unen en contra de un sub-consulta que limita las filas que usted ensambla en contra.

+2

¿Podría dar un ejemplo completo para que quede más claro, porque estoy perdido aquí ... gracias :) – iSafa

+1

Aquí hay un ejemplo más completo con un filtro adicional por descripción: 'SELECT t1.Id, t1.Name, tAlias. Descripción FROM t1 LEFT JOIN ( SELECT ID, Nombre De T2 DONDE descripción como 'Hola%' GRUPO POR ID, Nombre ) COMO EN Talias t1.Id = tAlias.Id Y t1.Name = tAlias.Name ' –

+0

gracias esto funciona !! :) – kirti

1

Si desea visualizar varias filas de la tabla 2, se mostrarán los datos duplicados de la tabla1. Si quisiera, podría usar una función agregada (IE Max, Min) en la tabla 2, esto eliminaría las filas duplicadas de la tabla 1, pero también ocultaría algunos de los datos de la tabla2.

Véase también mi respuesta a la pregunta #70161 explicaciones adicionales

3

Para más detalles sobre un punto: usted ha dicho que sólo hay una fila "activa" en la Tabla 2 por fila en la Tabla 1. ¿Esa fila no está marcada como activa para que pueda ponerla en la cláusula where? ¿O hay algo mágico en las condiciones dinámicas que proporciona el usuario que determina qué está activo y qué no?

Si no necesita seleccionar nada de Table2, la solución es relativamente simple, ya que puede usar la función EXISTS, pero como ha puesto TAble2.Description en la cláusula, supongo que ese no es el caso.

Básicamente, ¿qué separa las filas relevantes en Table2 de las irrelevantes? ¿Es una bandera activa o una condición dinámica? ¿La primera fila? Así es como debería eliminar los duplicados.

DISTINCT clauses tend to be overused.Puede que ese no sea el caso aquí, pero parece que es posible que intente piratear los resultados que desea con DISTINCT en lugar de resolver el problema real, que es un problema bastante común.

+0

Tiene razón, aunque solo hay una fila activa en Table2 por fila en Table1, debo incluir la cláusula where en función de la selección del usuario. – Nazgul

1

tiene que incluir cláusula de la actividad en su unirse a (y sin necesidad de distinta):

select Table1.Id as Id, Table1.Name, Table2.Description from Table1 
left outer join Table1Table2Map on (Table1Table2Map.Table1Id = Table1.Id) and Table1Table2Map.IsActive = 1 
left outer join Table2 on (Table2.Id = Table1Table2Map.Table2Id) 
+0

Table1Table2Map.IsActive = 1 cláusula no siempre se puede incluir en la consulta, se incluye en función de la selección del usuario. – Nazgul

6

Se puede volver a escribir su izquierda se une a ser externa se aplica, por lo que se puede utilizar una tapa 1 y una orden por la manera siguiente:

select Table1.Id as Id, Table1.Name, Table2.Description 
from Table1 
outer apply (
    select top 1 * 
    from Table1Table2Map 
    where (Table1Table2Map.Table1Id = Table1.Id) and Table1Table2Map.IsActive = 1 
    order by somethingCol 
) t1t2 
outer apply (
    select top 1 * 
    from Table2 
    where (Table2.Id = Table1Table2Map.Table2Id) 
) t2; 

Tenga en cuenta que se aplica una capa exterior sin un "superior" o una "orden por" es exactamente equivalente a una combinación externa izquierda, sólo se le da un poco más de control. (la aplicación cruzada es equivalente a una unión interna).

También puede hacer algo similar con el row_number() Función:

select * from (
     select distinct Table1.Id as Id, Table1.Name, Table2.Description, 
     rowNum = row_number() over (partition by table1.id order by something) 
     from Table1 
     left outer join Table1Table2Map on (Table1Table2Map.Table1Id = Table1.Id) 
     left outer join Table2 on (Table2.Id = Table1Table2Map.Table2Id) 
) x 
where rowNum = 1; 

La mayor parte de esto no se aplica si la bandera IsActive puede reducir las otras tablas a una fila, pero podría venir en útil para ti

+1

Usar una aplicación externa como muestra John aquí es útil si no solo necesita filtrar en, por ej. Indicador IsActive pero también necesita hacer coincidir algunas columnas de la tabla izquierda con la derecha en una cláusula where (que no se puede hacer en una combinación externa simple). –

11

Puede usar GROUP BY en Table1.Id, y eso eliminará las filas adicionales. No necesitarás preocuparte por ninguna mecánica en el lado de unión.

Se me ocurrió esta solución en una gran consulta y esta solución no tuvo mucho efecto en el tiempo de consulta.

NOTA: Estoy respondiendo esta pregunta 3 años después de haberla formulado, pero esto puede ayudar a alguien a quien creo.

+0

Con el servidor SQL, esto generalmente significa que tendrá que agruparse bastante bien cerca de cada columna que seleccione. – Amalgovinus

Cuestiones relacionadas