2009-04-21 10 views
9

Necesito seleccionar solo la primera fila de una consulta que une las tablas A y B. En la tabla B existen múltiples registros con el mismo nombre. No hay identificadores en ninguna de las dos tablas. Tampoco puedo cambiar el esquema porque no tengo el DB.Seleccione la primera fila en una combinación de dos tablas en una declaración

TABLE A 
NAME 

TABLE B 
NAME 
DATA1 
DATA2 

Select Distinct A.NAME,B.DATA1,B.DATA2 
From A 
Inner Join B on A.NAME = B.NAME 

Esto me da

NAME  DATA1 DATA2 
sameName 1  2 
sameName 1  3 
otherName 5  7 
otherName 8  9 

pero necesito recuperar sólo una fila por nombre

NAME  DATA1 DATA2 
sameName 1  2 
otherName 5  7 

yo era capaz de hacer esto añadiendo el resultado en una tabla temporal con una columna de identidad y luego seleccione el id. mínimo por nombre.

El problema aquí es que necesito hacer esto en una sola declaración.

Respuesta

0

No estoy seguro si esto resolverá su problema o no, pero podría intentar usar la cláusula GROUP BY y agruparlo en una de las columnas de nombre.

DB2 Group by tutorial

7

El uso de un GROUP BY puede obtener separe camino, pero ten cuidado. Si haces algo como esto:

Select A.NAME, min(B.DATA1), min(B.DATA2) 
From A Inner Join B on A.NAME = B.NAME 
Group by A.NAME; 

Usted conseguirá el resultado que busca:

NAME  DATA1 DATA2 
    sameName 1  2  
    otherName 5  7 

Pero sólo debido a los datos que se está probando con. Si cambia los datos, por lo que en lugar de:

otherName 8  9 

que tenía:

otherName 8  4 

volvería:

NAME  DATA1 DATA2 
    sameName 1  2  
    otherName 5  4 

Tenga en cuenta que otherName no vuelve datos1 y DATOS2 de la mismo récord!

Actualización: Un auto-unirse con una comparación en uno de los valores de los datos puede ayudar a usted, como:

SELECT a.*, b.* FROM a,b 
    LEFT JOIN b b2 ON b.name = b2.name AND b.data2 < b2.data2 
    WHERE a.name = b.name AND b2.data2 IS NOT NULL; 

Sin embargo, esto sólo funcionará si los valores de DATOS2 son únicos por cada nombre.

+0

Hay un pequeño error tipográfico en la última afirmación. Debería ser "IS NOT NULL" en lugar de "IN NOT NULL". – mbp

+0

+1 eres un salvador. Su autocomunicación editada funciona incluso con SQL CE, donde otras soluciones para esta pregunta no se deben a las limitaciones de SQL CE. –

0

Si puede agregar a una tabla temporal y luego consultar desde allí, puede hacerlo de una vez.

WITH T AS (temp table select), RN AS (select min row-numbers from T) SELECT T.NAME, T.DATA1, T.DATA2 FROM T INNER JOIN RN on T.row_number = RN.row_number 

Hay muchas otras maneras de escribir esto, pero así es como he estado haciendo cosas similares.

0

Trate de Dedupe B de la siguiente

SELECT A.NAME, bb.DATA1, bb.DATA2 
FROM A 
JOIN B bb 
ON  A.NAME = B.NAME 
WHERE NOT EXISTS (SELECT * 
        FROM B 
        WHERE NAME = bb.NAME 
          AND (DATA1 > bb.DATA1 
           OR DATA1 = bb.DATA1 AND DATA2 > bb.DATA2))

Añadir más o cláusulas si existen más columnas DATAX.

Si A contiene también duplicados, simplemente use DISTINCT como en el OP.

10

Esto funcionará:

with temp as (
    select A.NAME, B.DATA1, B.DATA2, 
     row_number() over (partition by A.NAME order by A.NAME) as rownum 
    from TABLEA A inner join TABLEB B 
    on A.NAME = B.NAME 
) 
select NAME, DATA1, DATA2 from temp where rownum = 1 

Si desea seleccionar el menor valor de datos1 y dentro de ella data2, a continuación, utilizar esta variación:

with temp as (
    select A.NAME, B.DATA1, B.DATA2, 
     row_number() over (partition by A.NAME order by B.DATA1, B.DATA2) as rownum 
    from TABLEA A inner join TABLEB B 
    on A.NAME = B.NAME 
) 
select NAME, DATA1, DATA2 from temp where rownum = 1 

Tanto las consultas dará una fila por cada nombre.

+0

Sería mejor hacer la partición por 'B.name', para que pueda usar un índice (si existe). Ni siquiera tendrías que molestarte en reportar 'A.name' (debido a la comparación). –

+1

Gran solución. Gracias. –

+1

@KobyDouek me alegro de que haya ayudado :) ¡salud! –

0
SELECT A.NAME, bb.DATA1, bb.DATA2 
From A Inner Join B on A.NAME = B.NAME 
WHERE B.DATA1 = (SELECT MIN(DATA1) FROM B WHERE NAME = A.NAME) 

Esto le dará el resultado deseado, proporcionando valores B.DATA1 son única dentro del conjunto en relación con la tabla A.

Si no son únicos, la única forma que conozco está utilizando CROSS APPLY en MSSQL 2005 y versiones posteriores.

0

La etiqueta de esta pregunta indica que sería una solución para DB2, pero esto es muy similar a la del servidor MS-SQL, si a fin de tratar estas soluciones:

Uso CRUZ, será posible visualizar lo sólo existe en ambas tablas

select A.*, B.DATA1, B.DATA2 
from A 
cross apply (select top 1 * from B where B.name = A.name) B 

Pero es posible cambiar al exterior para mostrar lo que existe en a sin la obligación de existir en B

select A.*, B.DATA1, B.DATA2 
from A 
OUTER apply (select top 1 * from B where B.name = A.name) B 

en el structu re de la instrucción apply, también sería posible incluir una instrucción ORDER, ya que no hay indicación del orden de las salidas en la tabla B

0

Puede usar el número de fila para obtener una fila para cada nombre, intente algo como debajo de

Select name,data1,data2 from 
(Select A.NAME,B.DATA1,B.DATA2,row_number() over(partitioj by a.name order by a.name) rn 
From A 
Inner Join B on A.NAME = B.NAME) where rn=1 
Cuestiones relacionadas