2009-09-25 7 views
2

Nous travaillons sur une application C#, nous avons utilisé Linq to SQL ou ADO standard (lorsque les performances requises) pour travailler avec SQL Server.SQL Server - PIVOT

Nous avons une table layed dehors comme si:

N ° de client, Année/Mois, Nom du produit, Quantité

Chaque client a des colonnes supplémentaires par produit.

Nous avons besoin d'afficher ces informations dans une grille de données comme ceci:

client, Année/Mois, Produit A Quantité, produit B Quantité, produit C Quantité, etc.

Quelle requête pourrait donner nous ces résultats? Et comment pourrait-il être dynamique, peu importe quels produits sont ajoutés et supprimés? Nous allons utiliser un ListView dans WPF pour afficher les données.

Nous stockerons simplement les informations différemment, mais ils peuvent ajouter/supprimer des produits tout le temps.

Est-ce que PIVOT fonctionnera?

(PS - les noms de produits sont vraiment dans une autre table pour la normalisation, je l'ai changé un peu de simplicité pour vous les gars)

Répondre

1

Vous pouvez utiliser le pivot avec SQL dynamique. Le code T-SQL suivant est tiré de this article on sqlteam.com. J'ai essayé de modifier l'échantillon pour vos besoins. Méfiez-vous également des dangers utilisant SQL dynamique, il pourrait conduire à l'injection SQL si un nom de produit contient apostrophe.

Créer un proc stocké en premier;

CREATE PROCEDURE crosstab 
@select varchar(8000), 
@sumfunc varchar(100), 
@pivot varchar(100), 
@table varchar(100) 
AS 

DECLARE @sql varchar(8000), @delim varchar(1) 
SET NOCOUNT ON 
SET ANSI_WARNINGS OFF 

EXEC ('SELECT ' + @pivot + ' AS pivot INTO ##pivot FROM ' + @table + ' WHERE 1=2') 
EXEC ('INSERT INTO ##pivot SELECT DISTINCT ' + @pivot + ' FROM ' + @table + ' WHERE ' 
+ @pivot + ' Is Not Null') 

SELECT @sql='', @sumfunc=stuff(@sumfunc, len(@sumfunc), 1, ' END)') 

SELECT @delim=CASE Sign(CharIndex('char', data_type)+CharIndex('date', data_type)) 
WHEN 0 THEN '' ELSE '''' END 
FROM tempdb.information_schema.columns 
WHERE table_name='##pivot' AND column_name='pivot' 

SELECT @[email protected] + '''' + convert(varchar(100), pivot) + ''' = ' + 
stuff(@sumfunc,charindex('(', @sumfunc)+1, 0, ' CASE ' + @pivot + ' WHEN ' 
+ @delim + convert(varchar(100), pivot) + @delim + ' THEN ') + ', ' FROM ##pivot 

DROP TABLE ##pivot 

SELECT @sql=left(@sql, len(@sql)-1) 
SELECT @select=stuff(@select, charindex(' FROM ', @select)+1, 0, ', ' + @sql + ' ') 

EXEC (@select) 
SET ANSI_WARNINGS ON 

Alors essayez les éléments suivants (je ne l'ai pas tester, vous devrez peut-être ajouter qté pour sélectionner la déclaration)

EXECUTE crosstab 'select ProductID,CustomerID, YearMonth from sales group by ProductId', 'sum(qty)','ProductId','sales' 
+0

Quel genre de vitesse que je regarde ici? Les requêtes appelant cette procédure stockée seront-elles assez lentes pour une table contenant 22 millions d'enregistrements? – jonathanpeppers

+0

Le SP génère un code T-SQL dynamique comme 'select customername, cas où productid = 1 puis quantité autre 0 END AS Product1, case .... du groupe de commande par nom_personnel'. Mon expérience avec les serveurs de production est limitée, donc je n'ai aucune idée de 22 millions d'enregistrements. Mais je vous suggère de créer l'index sur la colonne productname puis de tester la vitesse avec les enregistrements créés par les outils de génération de stress/enregistrement de sql server. –

+0

Votre réponse doit être correcte, à moins qu'il y ait un moyen alternatif de procéder. Mes problèmes vont être la vitesse et la flexibilité, donc nous allons devoir essayer. – jonathanpeppers

2

La commande pivot sql peut être utilisé, mais il faut les colonnes d'être codées en dur . Vous pouvez soit les coder en dur, utiliser SQL dynamique pour générer les colonnes, ou seulement obtenir les données brutes de SQL sans un pivot et faire le massage des données dans C#.

0

Si vous voulez essayer une méthode qui ne comporte pas SQL dynamique, you could go through C#.

Ce gars a couru un test comparant les deux: http://weblogs.sqlteam.com/jeffs/jeffs/archive/2005/05/12/5127.aspx

+0

C'est essentiellement ce que j'ai fini par faire à la fin, j'avais besoin de notre solution pour être assez dynamique et l'utilisation de C# semblait assez rapide pour nos objectifs.Nous n'avons fait aucun test de perf entre PIVOT et C#, PIVOT semblait lourd et difficile à maintenir car nous aurions dû utiliser manuellement les noms de colonnes ou le SQL dynamique. C# semblait beaucoup plus facile à gérer. – jonathanpeppers