2009-02-24 22 views
77

Sé que puedo seleccionar una columna de una subconsulta con esta sintaxis:¿Cómo puedo seleccionar varias columnas de una subconsulta (en SQL Server) que debe tener un registro (seleccionar top 1) para cada registro en la consulta principal?

SELECT A.SalesOrderID, A.OrderDate, 
     (
     SELECT TOP 1 B.Foo 
     FROM B 
     WHERE A.SalesOrderID = B.SalesOrderID 
     ) AS FooFromB 
FROM A 
WHERE A.Date BETWEEN '2000-1-4' AND '2010-1-4' 

Pero lo que es la sintaxis correcta de utilizar varias columnas de una subconsulta (en mi caso un selecto superior 1 subconsulta)? Muchas gracias.

Respuesta

2
SELECT 
    T1.PrimaryKey, 
    T1.SomeColumn, 
    MySubQuery.Col1, 
    MySubQuery.Col2, 
    MySubQuery.Col3 
From 
    Table1 T1 
    LEFT JOIN (SELECT TOP 1 Col1, Col2, Col3, Fkey FROM Table 2 ORDER BY Col1 DESC) AS MySubQuery ON T1.PrimaryKey = MySubQuery.Fkey 
+47

No sólo esta respuesta no se explica en absoluto, tampoco hay una relación entre las tablas. ¿Cómo puede esto tener tantos upvotes? –

+3

Por favor explique lo que está haciendo allí, gracias. – BastetFurry

7

Vas a tener que hacer una combinación:

SELECT A.SalesOrderID, B.Foo 
FROM A 
JOIN B bo ON bo.id = (
    SELECT TOP 1 id 
    FROM B bi 
    WHERE bi.SalesOrderID = a.SalesOrderID 
    ORDER BY bi.whatever 
    ) 
WHERE A.Date BETWEEN '2000-1-4' AND '2010-1-4' 

, suponiendo que b.id es una PRIMARY KEY en B

En MS SQL 2005 y más alto se puede usar la siguiente sintaxis:

SELECT SalesOrderID, Foo 
FROM (
    SELECT A.SalesOrderId, B.Foo, 
     ROW_NUMBER() OVER (PARTITION BY B.SalesOrderId ORDER BY B.whatever) AS rn 
    FROM A 
    JOIN B ON B.SalesOrderID = A.SalesOrderID 
    WHERE A.Date BETWEEN '2000-1-4' AND '2010-1-4' 
) i 
WHERE rn 

Esto seleccionará exactamente una reco rd desde B para cada SalesOrderId.

99

Aquí es generalmente cómo seleccionar varias columnas de una subconsulta:

SELECT 
    A.SalesOrderID, 
    A.OrderDate, 
    SQ.Max_Foo, 
    SQ.Max_Foo2 
FROM 
    A 
LEFT OUTER JOIN 
    (
    SELECT 
      B.SalesOrderID, 
      MAX(B.Foo) AS Max_Foo, 
      MAX(B.Foo2) AS Max_Foo2 
    FROM 
      B 
    GROUP BY 
      B.SalesOrderID 
    ) AS SQ ON SQ.SalesOrderID = A.SalesOrderID 

Si lo que estás en última instancia, tratando de hacer es obtener los valores de la fila con el valor más alto para Foo (en lugar del máximo de foo y el máximo de Foo2 - que no es lo mismo), entonces lo siguiente será por lo general funcionan mejor que una subconsulta:

SELECT 
    A.SalesOrderID, 
    A.OrderDate, 
    B1.Foo, 
    B1.Foo2 
FROM 
    A 
LEFT OUTER JOIN B AS B1 ON 
    B1.SalesOrderID = A.SalesOrderID 
LEFT OUTER JOIN B AS B2 ON 
    B2.SalesOrderID = A.SalesOrderID AND 
    B2.Foo > B1.Foo 
WHERE 
    B2.SalesOrderID IS NULL 

básicamente Usted está diciendo, me dan la fila de B, donde no puedo encontrar cualquier otra fila de B con el mismo SalesOrderID y un Foo mayor.

0

Creo que eso es lo que quiere.

SELECT 
     A.SalesOrderID, 
     A.OrderDate, 
     FooFromB.* 

FROM A, 
    (SELECT TOP 1 B.Foo 
     FROM B 
     WHERE A.SalesOrderID = B.SalesOrderID 
    ) AS FooFromB 

WHERE A.Date BETWEEN '2000-1-4' AND '2010-1-4' 
+1

A.SalesOrderID no puede vincularse – Patrick

6
SELECT a.salesorderid, a.orderdate, s.orderdate, s.salesorderid 
FROM A a 
OUTER APPLY (SELECT top(1) * 
      FROM B b WHERE a.salesorderid = b.salesorderid) as s 
WHERE A.Date BETWEEN '2000-1-4' AND '2010-1-4' 
+0

Esta respuesta funciona muy bien cuando la coincidencia de B debe diferir para cada registro A, que no funciona con una combinación de subconsulta típica. – Keith

+0

Gracias, aplicar externo es mejor que unir, porque uno puede hacer referencia también a otros parámetros, que es necesario para llamadas a funciones más complejas, etc. –

Cuestiones relacionadas