2010-04-28 5 views
4

J'ai deux tables: Normes et offres de service. Une norme peut avoir plusieurs offres de service. Chaque standard peut avoir un nombre différent d'offres de service associées.Sélectionner les colonnes dynamiques de retour

Ce que je dois être en mesure de faire est d'écrire une vue qui retournera des données communes et ensuite énumérer les offres de service sur une ligne. Par exemple:

Standard Id | Description | SO #1 | SO #2 | SO #3 | ... | SO #21 | SO Count 
1   | One   | A  | B  | C  | ... | G  | 21 
2   | Two   | A  |  |  | ... |  | 1 
3   | Three  | B  | D  | E  | ... |  | 3 

Je n'ai aucune idée comment écrire ceci. Le nombre de colonnes SO est fixé à un nombre spécifique (21 dans ce cas), donc nous ne pouvons pas dépasser le passé.

Des idées sur la façon d'aborder cela?

Un lieu que j'ai commencé est ci-dessous. Il vient de renvoyer plusieurs lignes pour chaque offre de service, lorsqu'elles doivent être sur une ligne.

SELECT * 
    FROM SERVICE_OFFERINGS 
WHERE STANDARD_KEY IN (SELECT STANDARD_KEY 
          FROM STANDARDS) 

SQL supplémentaires

est le SQL je donc ici ai qui retourne tout ce que je veux, mais retournerai 11 lignes en raison de qu'il y ait 11 offres de services. J'ai essayé le tableau croisé dynamique et ne peux pas sembler comprendre cela avec ceci. Quelqu'un peut-il aider avec un exemple de code?

SELECT DISTINCT stpc.standard_key, 
       stpc.test_id, 
       NULL AS pricebook_id, 
       stpc.stabdard_name AS description, 
       stpc.date_start AS begin_date, 
       stpc.date_end AS end_date, 
       sopd.service_offering_id 
    FROM STANDARDS stpc, 
     SERVICE_OFFERINGS sopd 
WHERE 1=1 
    AND sopd.standard_key = stpc.standard_key 
ORDER BY stpc.standard_key, sopd.service_offering_id 

MISE À JOUR

La base de données ne suppose pas des tableaux croisés dynamiques (et ne pouvait pas comprendre la suggestion XML), je devais faire un peu de SQL difficile à faire fonctionner. Voici ce que je:

select stpc.oracle_product_code AS test_id, 
     CASE WHEN stpc.store_key = 200 THEN 'CE_USAUSD09' 
      WHEN stpc.store_key = 210 THEN 'CE_CANCAD09' END AS pricebook_id, 
     stpc.standard_name AS its_test_desc, 
     CONVERT(VARCHAR(10), stpc.date_start, 101) AS begin_date, 
     CONVERT(VARCHAR(10), stpc.date_end, 101) AS end_date, 
     MAX(CASE WHEN rn = 1 THEN b.service_offering_id END) AS SERVICE_OFFERING_1, 
     MAX(CASE WHEN rn = 2 THEN b.service_offering_id END) AS SERVICE_OFFERING_2, 
     MAX(CASE WHEN rn = 3 THEN b.service_offering_id END) AS SERVICE_OFFERING_3, 
     MAX(CASE WHEN rn = 4 THEN b.service_offering_id END) AS SERVICE_OFFERING_4, 
     MAX(CASE WHEN rn = 5 THEN b.service_offering_id END) AS SERVICE_OFFERING_5, 
     MAX(CASE WHEN rn = 6 THEN b.service_offering_id END) AS SERVICE_OFFERING_6, 
     MAX(CASE WHEN rn = 7 THEN b.service_offering_id END) AS SERVICE_OFFERING_7, 
     MAX(CASE WHEN rn = 8 THEN b.service_offering_id END) AS SERVICE_OFFERING_8, 
     MAX(CASE WHEN rn = 9 THEN b.service_offering_id END) AS SERVICE_OFFERING_9, 
     MAX(CASE WHEN rn = 10 THEN b.service_offering_id END) AS SERVICE_OFFERING_10, 
     MAX(CASE WHEN rn = 11 THEN b.service_offering_id END) AS SERVICE_OFFERING_11, 
     MAX(CASE WHEN rn = 12 THEN b.service_offering_id END) AS SERVICE_OFFERING_12, 
     MAX(CASE WHEN rn = 13 THEN b.service_offering_id END) AS SERVICE_OFFERING_13, 
     MAX(CASE WHEN rn = 14 THEN b.service_offering_id END) AS SERVICE_OFFERING_14, 
     MAX(CASE WHEN rn = 15 THEN b.service_offering_id END) AS SERVICE_OFFERING_15, 
     MAX(CASE WHEN rn = 16 THEN b.service_offering_id END) AS SERVICE_OFFERING_16, 
     MAX(CASE WHEN rn = 17 THEN b.service_offering_id END) AS SERVICE_OFFERING_17, 
     MAX(CASE WHEN rn = 18 THEN b.service_offering_id END) AS SERVICE_OFFERING_18, 
     MAX(CASE WHEN rn = 19 THEN b.service_offering_id END) AS SERVICE_OFFERING_19, 
     MAX(CASE WHEN rn = 20 THEN b.service_offering_id END) AS SERVICE_OFFERING_20, 
     MAX(CASE WHEN rn = 21 THEN b.service_offering_id END) AS SERVICE_OFFERING_21, 
     MAX(rn) AS service_offering_count 
FROM (
select standard_key, 
     service_offering_id, 
     row_number() over (partition by standard_key order by standard_key) rn 
from SERVICE_OFFERINGS 
) B, 
SERVICE_OFFERINGS sopd, 
STANDARDS stpc 
where b.service_offering_id = sopd.service_offering_id 
AND b.standard_key = stpc.standard_key 
AND sopd.standard_key = stpc.standard_key 
AND stpc.store_key IN (200,210) 
AND stpc.create_date > '03/29/2010' 
group by stpc.oracle_product_code,stpc.store_key,stpc.standard_name,stpc.date_start,stpc.date_end 

Répondre

2

Vous pouvez utiliser la fonctionnalité de PIVOT pour cela.

Découvrez http://archive.msdn.microsoft.com/SQLExamples/Wiki/View.aspx?title=PIVOTData

Au lieu de PIVOT, vous devez utiliser une combinaison de FOR XML et SplitToColumns.

Utilisez FOR XML et faites pivoter vos offrandes à une seule colonne Concatenating Row Values in Transact-SQL

Ensuite, utilisez une fonction de style CTE pour décomposer une seule cellule dans les colonnes comme indiqué ici http://www.sqlservercentral.com/articles/CTE/67974/

Cela vous donnera une table pivoté sur à la mode dont vous avez besoin.

Ensuite, faites de l'arithmétique pour obtenir le nombre de colonnes non nulles et vous avez le nombre dont vous avez besoin à la fin.

1

Oui, les requêtes pivot sont ce que vous devez utiliser.

La colonne 21 est-elle toujours la même ou est-ce que vous ne pouvez pas afficher plus de 21 colonnes (par exemple, des centaines)? Si les couleurs réelles peuvent varier d'une requête à l'autre, vous devrez chercher à écrire des requêtes dynamiques (construire la requête sous forme de chaîne - en incorporant les colonnes à faire pivoter - puis exécuter la chaîne).

1

Philippe a raison. Si vous aurez toujours 21 colonnes, c'est une simple requête Pivot. Je colle ici un exemple de code que vous pourriez utiliser. Mais si le nombre de colonnes varie entre 1 et 21, vous devrez écrire une requête dynamique.

SELECT standard_key, stabdard_name, [A] as SO1, [B] as SO2, [C] as SO3, [D] as SO4, [E] as SO5....-- and so on with the other columns 
FROM 
(SELECT ST.standard_key, ST.stabdard_name, SO.service_offering_id 
FROM SERVICE_OFFERINGS SO 
    INNER JOIN STANDARDS ST 
     ON SO.standard_key= ST.standard_key)p 
PIVOT 
(
MAX (service_offering_id) 
FOR service_offering_id IN 
([A], [B], [C], [D], [E]....-- and so on with the other values) 
) AS pvt 
ORDER BY standard_key 

Si les colums peuvent varier yo peut essayer quelque chose comme ceci:

declare @sql nvarchar(max) 
declare @sql2 nvarchar(max) 

SET @sql2='' 
set @sql = ' 
select 
    standard_key, stabdard_name,' 

select @sql = @sql + '['+ service_offering_id + '] AS [SO' + convert(varchar, Row_number() OVER (ORDER BY service_offering_id))+ '],' 
from (select distinct [service_offering_id] from [SERVICE_OFFERINGS]) as moduleids 

select @sql2 = @sql2 + '['+ service_offering_id + '],' 
from (select distinct [service_offering_id] from [SERVICE_OFFERINGS]) as moduleids 

set @sql2 = substring(@sql2,1,len(@sql2)-1) 

set @sql = substring(@sql,1,len(@sql)-1) + ' 
FROM 
(SELECT ST.standard_key, ST.stabdard_name, SO.service_offering_id 
FROM SERVICE_OFFERINGS SO 
    INNER JOIN STANDARDS ST 
     ON SO.standard_key= ST.standard_key)p 
PIVOT 
(
MAX (service_offering_id) 
FOR service_offering_id IN 
(' + @sql2 + 
')) AS pvt 
ORDER BY standard_key' 

print @sql 

exec sp_executesql @sql 
+0

Merci beaucoup pour l'exemple. J'ai essayé d'exécuter cela et apparemment j'ai besoin de mettre à jour le niveau de compatibilité de la base de données. Une fois cela fait, je vais certainement vérifier cela. Merci! – Ascalonian

Questions connexes