Pregunta

Tengo 2 tablas una tabla de la Cuenta y una tabla de Usuarios.Cada cuenta puede tener varios usuarios.Tengo un escenario donde quiero hacer una sola consulta/unirse en contra de estas dos tablas, pero quiero que todos los datos de la Cuenta (la Cuenta.*) y sólo el primero conjunto de datos de usuario (en concreto su nombre).

En lugar de hacer un "min" o "max" en mi grupo agregado, quería hacer una "primera".Pero, al parecer, no hay una "Primera" función de agregado en TSQL.

Cualquier sugerencia sobre cómo ir sobre cómo obtener esta consulta?Obviamente, es fácil conseguir el producto cartesiano de Cuenta de los Usuarios de x:

 SELECT User.Name, Account.* FROM Account, User
 WHERE Account.ID = User.Account_ID

Pero, ¿cómo podría yo tengo unos consiguiendo solamente el primer usuario del producto basado en el orden de su Usuario.ID ?

¿Fue útil?

Solución

En lugar de agrupar, de hacerlo así ...

select
    *

from account a

join (
    select 
        account_id, 
        row_number() over (order by account_id, id) - 
            rank() over (order by account_id) as row_num from user
     ) first on first.account_id = a.id and first.row_num = 0

Otros consejos

Yo sé que mi respuesta es un poco tarde, pero que podría ayudar a los demás. Hay una manera de conseguir un primero () y Last () en SQL Server, y aquí está:

Stuff(Min(Convert(Varchar, DATE_FIELD, 126) + Convert(Varchar, DESIRED_FIELD)), 1, 23, '')

Utilice Min () para el primero () y Max () para Last (). El DATE_FIELD debería ser la fecha que determina si es el primero o el último registro. El DESIRED_FIELD es el campo que desea el primer o el último valor. Lo que hace es:

  1. Añadir la fecha en formato ISO en el inicio de la cadena (23 caracteres)
  2. Añada la DESIRED_FIELD a la cadena
  3. Obtener el valor MIN / MAX para ese campo (ya que se inicia con la fecha, obtendrá el primer o último registro)
  4. Cosas que concatened cadena para eliminar los primeros 23 caracteres (la parte de fecha)

Aquí tienes!

EDIT: Tengo problemas con la primera fórmula: cuando el DATE_FIELD tiene como 0,000 milisegundos, SQL Server devuelve la fecha como cadena de caracteres sin milisegundos en todo, eliminando así los primeros 4 caracteres de la DESIRED_FIELD. Simplemente cambia el formato de "20" (sin milisegundos) y funciona genial. El único inconveniente es que si usted tiene dos campos que se crearon en los mismos segundos, el tipo posiblemente puede ser un poco incómodo ... cas en las que se puede volver a "126" para el formato.

Stuff(Max(Convert(Varchar, DATE_FIELD, 20) + Convert(Varchar, DESIRED_FIELD)), 1, 19, '')

EDIT 2: Mi intención original era para devolver la última (o primera) fila NO NULO. Me pregunté cómo devolver la última o primera fila, wether sea nulo o no. Basta con añadir una ISNULL a la DESIRED_FIELD. Al concatenar dos cadenas con un operador +, cuando uno de ellos es nulo, el resultado es NULL. A fin de utilizar lo siguiente:

Stuff(Max(Convert(Varchar, DATE_FIELD, 20) + IsNull(Convert(Varchar, DESIRED_FIELD), '')), 1, 19, '')
Select *
From Accounts a
Left Join (
    Select u.*, 
    row_number() over (Partition By u.AccountKey Order By u.UserKey) as Ranking
    From Users u
  ) as UsersRanked
  on UsersRanked.AccountKey = a.AccountKey and UsersRanked.Ranking = 1

Esto puede ser simplificado mediante el uso de la partición por la cláusula. En lo anterior, si una cuenta tiene tres usuarios, entonces los números subconsulta ellos 1,2, y 3, y por un AccountKey diferente, se restablecerá la numnbering. Esto significa que para cada AccountKey único, siempre habrá un 1, y, potencialmente, 2,3,4, etc.

De este modo se filtra en el Ranking = 1 para agarrar el primer lugar de cada grupo.

Esto le dará una fila por cada cuenta, y si hay al menos un usuario de esa cuenta, a continuación, se le dará al usuario la tecla más baja (porque uso una izquierda unirse, siempre se obtendrá una lista de cuenta incluso si no existe ningún usuario). Reemplazar Order By u.UserKey con otro campo si se prefiere que el primer usuario puede elegir por orden alfabético o algún otro criterio.

La respuesta cosas de Dominic Goulet es resbaladiza. Pero, si su DATE_FIELD es SMALLDATETIME (en lugar de DATETIME), entonces la longitud ISO 8601 será de 19 en lugar de 23 (porque SMALLDATETIME no tiene milisegundos) - por lo que ajustar el parámetro MATERIA consecuencia o el valor de retorno de la función La materia será incorrecto ( perderse los primeros cuatro caracteres).

Primero y el Último no existen en SQL Server 2005 o 2008, pero en SQL Server 2012 no es una función FIRST_VALUE, LAST_VALUE. Traté de poner en práctica el agregado primero y el último para SQL Server 2005 y llegó a la obstáculo que SQL Server garantizar el cálculo del agregado en un orden definido. (Véase el atributo SqlUserDefinedAggregateAttribute.IsInvariantToOrder la propiedad, que no está implementado.) Esto puede deberse a que el analizador de consultas intenta ejecutar el cálculo del agregado en varios subprocesos y combinar los resultados, lo que acelera la ejecución, pero no garantiza un orden en el que se agregan elementos.

Puede utilizar EXTERIOR aplicar, consulte .

SELECT User1.Name, Account.* FROM Account
OUTER APPLY 
    (SELECT  TOP 1 Name 
    FROM [User]
    WHERE Account.ID = [User].Account_ID
    ORDER BY Name ASC) User1

He Benchmarked todos los métodos, el método simpelest y más rápida de lograrlo es mediante el uso de aplicar externa / cruz

SELECT u.Name, Account.* FROM Account
OUTER APPLY (SELECT TOP 1 * FROM User WHERE Account.ID = Account_ID ) as u

CROSS APPLY funciona igual combinación interna y obtiene las filas en las que ambas tablas están relacionadas, mientras que OUTER APPLY obras como combinación externa izquierda y recupera todas las filas de la tabla izquierda (cuenta aquí)

SELECT (SELECT TOP 1 Name 
        FROM User 
        WHERE Account_ID = a.AccountID 
        ORDER BY UserID) [Name],
       a.*
FROM Account a

Hay varias maneras de hacer esto, he aquí un uno rápido y sucio.

Select (SELECT TOP 1 U.Name FROM Users U WHERE U.Account_ID = A.ID) AS "Name,
    A.*
FROM Account A

Definición de "Primera". Lo que piensan como primera es una coincidencia que normalmente tiene que ver con el orden del índice agrupado, pero no debe ser invocado (se puede idear ejemplos que rompen él).

razón al no utilizar MAX () o MIN (). Aunque tentadora, considere la situación en la que el primer nombre y apellido están en campos separados. Es posible obtener los nombres de los diferentes registros.

Desde que suena como todo su realmente importa es que usted consigue exactamente un registro arbitrario para cada grupo, lo que puede hacer es simplemente MIN o MAX un campo de ID para ese registro, y luego unirse a la tabla en la consulta en ese ID .

(Ligeramente Off-Topic, pero) a menudo ejecutar consultas agregadas a la lista resúmenes de excepción, y luego quiero saber por qué un cliente está en los resultados, a fin de utilizar MIN y MAX para dar 2 muestras semi-aleatorios que puedo mira en detalle, por ejemplo,

SELECT Customer.Id, COUNT(*) AS ProblemCount
      , MIN(Invoice.Id) AS MinInv, MAX(Invoice.Id) AS MaxInv
FROM Customer
INNER JOIN Invoice on Invoice.CustomerId = Customer.Id
WHERE Invoice.SomethingHasGoneWrong=1
GROUP BY Customer.Id

Crear y unirse con una subselección 'FirstUser' que devuelve el primer usuario para cada cuenta

SELECT User.Name, Account.* 
FROM Account, User, 
 (select min(user.id) id,account_id from User group by user.account_id) as firstUser
WHERE Account.ID = User.Account_ID 
 and User.id = firstUser.id and Account.ID = firstUser.account_id
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top