2010-11-19 21 views
6

esta será la primera pregunta que he publicado aquí, así que disculpe cualquier error imprevisto en la etiqueta de la placa.Datos no agregados "pivotantes" en SQL Server

En mi proyecto actual, tomé una gran tabla no normalizada y la dividí en cuatro tablas separadas y normalizadas. Mi objetivo final al que me estoy dirigiendo es crear una vista que imite la tabla no normalizada de compatibilidad con versiones anteriores.

Para proporcionar una instantánea simplificada de mi escenario, el quid de lo que estoy tratando de hacer mentiras en dos tablas:

ASSOC_ROLE   ASSOCIATE 
----------   ---------- 
assoc_id (fk)  assoc_id (pk) 
role_id (fk)  last_name 
org_nbr (fk) 

Así que si emito la siguiente consulta ...

SELECT Assoc_Role.org_nbr, Assoc_Role.assoc_id, Associate.last_name, Assoc_Role.role_id 
FROM Assoc_Role INNER JOIN 
    Associate ON Assoc_Role.assoc_id = Associate.assoc_id 
WHERE Assoc_Role.org_nbr = '1AA' 

... me sale el siguiente conjunto de resultados

org_nbr  assoc_id  last_name  role_id 
-------  --------  ---------  ------- 
1AA   1447   Cooper  1 
1AA   1448   Collins  3 
1AA   1448   Collins  4 
1AA   1448   Collins  5 
1AA   1449   Lynch   6 

en última instancia, la vista me gustaría construir sería algo como esto :

org_nbr role1_ID role1_name role2_ID role2_name role3_ID role3_name role4_ID role4_name role5_ID role5_name role6_ID role6_name 
------- -------- ---------- -------- ---------- -------- ---------- -------- ---------- -------- ---------- -------- ---------- 
1AA  1447  Cooper  NULL  NULL   1448  Collins  1448  Collins  1448  Collins  1449  Lynch 

Mi idea inicial era tratar de utilizar el comando de pivote, pero mi opinión es que PIVOT requiere algún tipo de agregación, y que no se ajusta a mi escenario. También he jugado con el comando CASE en la cláusula SELECT, pero no aplana mi conjunto de resultados a un solo registro.

Espero que alguien pueda arrojar algo de luz sobre cómo puedo lograr esto. Avíseme si alguien necesita más información. ¡Gracias!

Scot

Respuesta

2

Para obtener los datos básicos en roles numerada, podríamos comenzar con

SELECT 
    org_nbr 
    , r1.assoc_id role1_ID 
    , r1.last_name role1_name 
    , r2.assoc_id role2_ID 
    , r2.last_name role2_name 
    , r3.assoc_id role3_ID 
    , r3.last_name role3_name 
    , r4.assoc_id role4_ID 
    , r4.last_name role4_name 
    , r5.assoc_id role5_ID 
    , r5.last_name role5_name 
    , r6.assoc_id role6_ID 
    , r6.last_name role6_name 
FROM 
    ASSOC_ROLE ar 
    LEFT JOIN ASSOCIATE r1 ON ar.role_id = 1 AND ar.assoc_id = r1.assoc_id 
    LEFT JOIN ASSOCIATE r2 ON ar.role_id = 2 AND ar.assoc_id = r2.assoc_id 
    LEFT JOIN ASSOCIATE r3 ON ar.role_id = 3 AND ar.assoc_id = r3.assoc_id 
    LEFT JOIN ASSOCIATE r4 ON ar.role_id = 4 AND ar.assoc_id = r4.assoc_id 
    LEFT JOIN ASSOCIATE r5 ON ar.role_id = 5 AND ar.assoc_id = r5.assoc_id 
    LEFT JOIN ASSOCIATE r6 ON ar.role_id = 6 AND ar.assoc_id = r6.assoc_id 

PERO esto nos dará, para cada org_nbr, una fila separada para cada role_id que tiene datos ! Que no es lo que queremos, así que necesitamos GROUP BY org_nbr. ¡Pero entonces necesitamos GROUP BY o agregado en cada columna en la lista SELECT! El truco es crear una función agregada que aplaque SQL Server y para darnos los resultados que queremos. En este caso, MIN hará el trabajo:

SELECT 
    org_nbr 
    , MIN(r1.assoc_id) role1_ID 
    , MIN(r1.last_name) role1_name 
    , MIN(r2.assoc_id) role2_ID 
    , MIN(r2.last_name) role2_name 
    , MIN(r3.assoc_id) role3_ID 
    , MIN(r3.last_name) role3_name 
    , MIN(r4.assoc_id) role4_ID 
    , MIN(r4.last_name) role4_name 
    , MIN(r5.assoc_id) role5_ID 
    , MIN(r5.last_name) role5_name 
    , MIN(r6.assoc_id) role6_ID 
    , MIN(r6.last_name) role6_name 
FROM 
    ASSOC_ROLE ar 
    LEFT JOIN ASSOCIATE r1 ON ar.role_id = 1 AND ar.assoc_id = r1.assoc_id 
    LEFT JOIN ASSOCIATE r2 ON ar.role_id = 2 AND ar.assoc_id = r2.assoc_id 
    LEFT JOIN ASSOCIATE r3 ON ar.role_id = 3 AND ar.assoc_id = r3.assoc_id 
    LEFT JOIN ASSOCIATE r4 ON ar.role_id = 4 AND ar.assoc_id = r4.assoc_id 
    LEFT JOIN ASSOCIATE r5 ON ar.role_id = 5 AND ar.assoc_id = r5.assoc_id 
    LEFT JOIN ASSOCIATE r6 ON ar.role_id = 6 AND ar.assoc_id = r6.assoc_id 
GROUP BY 
    org_nbr 

Salida:

org_nbr role1_ID role1_name role2_ID role2_name role3_ID role3_name role4_ID role4_name role5_ID role5_name role6_ID role6_name 
---------- ----------- ---------- ----------- ---------- ----------- ---------- ----------- ---------- ----------- ---------- ----------- ---------- 
1AA  1447  Cooper  NULL  NULL  1448  Collins 1448  Collins 1448  Collins 1449  Lynch 
Warning: Null value is eliminated by an aggregate or other SET operation. 

Por supuesto, esto no alcanzará si el máximo aumento role_id ...

+0

Interesante ... Soy bastante nuevo en la formación de consultas SQL en este nivel avanzado, por lo que nunca habría pensado en unirme consecutivamente a una tabla, pero puedo ver claramente cómo funciona. Mi próximo desafío será incorporar esto en una consulta más amplia, pero esto me da un gran comienzo. ¡Muchas gracias! Una pregunta sin embargo, con respecto a: "Por supuesto, esto no alcanzará si el máximo role_id aumenta ..." ¿Quiere decir simplemente que si tuviera que agregar más role_ID's, tendría que contabilizarlos en el consulta, o ¿estás sugiriendo más que eso? – ScottieByNature

+0

@ScottieByNature si aumenta el 'role_ID' máximo, tiene dos opciones. Si el cambio está en la línea de "solía haber como máximo 6 pero ahora hay como mucho 9", necesitaría agregar a la consulta lo que espero sea la manera más clara. Sin embargo, si es "ahora habrá un número arbitrario de posibles roles", entonces se debe buscar un enfoque diferente, en cuyo caso las consideraciones de @Chris Lively entran en juego, y se debe pensar en hacerlo fuera de SQL, o usando dinámicas SQL, o algo completamente distinto, puedes venir y preguntar aquí :) – AakashM

+0

Entendido ... ¡muy apreciado! – ScottieByNature

2

Si es posible, lo haría Recomiendo encarecidamente hacer este tipo de pivote en el código regular (C#, vb, lo que sea).

PIVOTAR en SQL Server tiene muchos inconvenientes. En primer lugar, cualquier elemento de más de 7 u 8 elementos aumentará enormemente la cantidad de tiempo que tardan sus consultas. En segundo lugar, requiere que realice un sql dinámico O que conozca todos los ID potenciales antes de tiempo. En tercer lugar, será difícil de mantener.

Los mismos problemas existen en la respuesta de AakashM.

Hemos intentado muchas formas diferentes de hacer que esto funcione en una configuración de SQL puro. Para conjuntos de datos pequeños con pivotes muy limitados funcionará bien. Sin embargo, la cantidad de Identificaciones de roles que ya tiene va más allá.

En su lugar, simplemente tome los datos y en su idioma favorito cree la tabla que necesita. En ese momento, coloque los datos en una tabla sql diferente o envíelos a donde quiera que vaya.

+0

Una sugerencia justa ... sin embargo, el sistema para el que intento crear esta vista compatible con versiones anteriores está basado en Visual FoxPro. Supongo que simplemente asumí que me sería más fácil crear una vista de esta complejidad en SQL Server frente a FoxPro. Tendré absolutamente presente esta consideración cuando continúe trabajando en esto. ¡Gracias! – ScottieByNature

Cuestiones relacionadas