Question

J'ai un Statut Mensuel vue de base de données j'ai besoin de créer un rapport basé sur.Les données de la vue ressemble à quelque chose comme ceci:

Category | Revenue  |  Yearh  |  Month
Bikes      10 000      2008        1
Bikes      12 000      2008        2
Bikes      12 000      2008        3
Bikes      15 000      2008        1
Bikes      11 000      2007        2
Bikes      11 500      2007        3
Bikes      15 400      2007        4


...Et ainsi de suite

Le point de vue a une catégorie de produits, des recettes, un an et un mois.Je veux créer un rapport de comparaison de 2007 et de 2008, montrant la valeur 0 pour le mois, avec aucune vente.Ainsi, le rapport devrait ressembler à quelque chose comme ceci:

Category  |  Month  |  Rev. This Year  |  Rev. Last Year
Bikes          1          10 000               0
Bikes          2          12 000               11 000
Bikes          3          12 000               11 500
Bikes          4          0                    15 400


La clé de chose à remarquer, c'est le mois 1 seule un chiffre d'affaires en 2008, et est donc 0 pour 2007.Aussi, 4 mois seulement n'a pas de chiffre d'affaires en 2008, d'où le 0, alors qu'il a chiffre d'affaires en 2007 et encore.

Aussi, le rapport est en réalité financière de l'année donc j'aimerais avoir des colonnes vides avec des 0 dans les deux cas il n'y a pas de ventes à dire 5 mois, soit en 2007 ou en 2008.

La requête que j'ai obtenu ressemble à quelque chose comme ceci:

SELECT 
    SP1.Program,
    SP1.Year,
    SP1.Month,
    SP1.TotalRevenue,
    IsNull(SP2.TotalRevenue, 0) AS LastYearTotalRevenue

FROM PVMonthlyStatusReport AS SP1 
     LEFT OUTER JOIN PVMonthlyStatusReport AS SP2 ON 
                SP1.Program = SP2.Program AND 
                SP2.Year = SP1.Year - 1 AND 
                SP1.Month = SP2.Month
WHERE 
    SP1.Program = 'Bikes' AND
    SP1.Category = @Category AND 
    (SP1.Year >= @FinancialYear AND SP1.Year <= @FinancialYear + 1) AND
    ((SP1.Year = @FinancialYear AND SP1.Month > 6) OR 
     (SP1.Year = @FinancialYear + 1 AND SP1.Month <= 6))

ORDER BY SP1.Year, SP1.Month

Le problème avec cette requête, c'est qu'il ne serait pas de retour de la quatrième rangée dans mon exemple, les données ci-dessus, puisque nous n'avons pas de chiffre d'affaires en 2008, mais nous avons fait en 2007.

C'est probablement une commune de la requête/problème, mais mon SQL est rouillé, après avoir fait front-end développement depuis si longtemps.Toute aide est grandement appréciée!

Oh, btw, je suis à l'aide de SQL 2005 pour cette question, donc si il y a tout utile de nouvelles fonctionnalités qui pourraient m'aider à me le faire savoir.

Était-ce utile?

La solution

L'Instruction case est mon meilleur sql ami.Vous avez également besoin d'une table pour générer votre 0 rev dans les deux mois.

Les hypothèses sont fondées sur la disponibilité des tables suivantes:

ventes:Category | Recettes | Yearh | Mois

et

tm:Année | Mois (rempli avec tous les les dates de déclaration nécessaires)

Exemple 1 sans les lignes vides:

select
    Category
    ,month
    ,SUM(CASE WHEN YEAR = 2008 THEN Revenue ELSE 0 END) this_year
    ,SUM(CASE WHEN YEAR = 2007 THEN Revenue ELSE 0 END) last_year

from
    sales

where
    year in (2008,2007)

group by
    Category
    ,month

RETOURNE:

Category  |  Month  |  Rev. This Year  |  Rev. Last Year
Bikes          1          10 000               0
Bikes          2          12 000               11 000
Bikes          3          12 000               11 500
Bikes          4          0                    15 400

Exemple 2 avec des lignes vides:Je vais utiliser une sous-requête (mais d'autres ne peuvent pas) et sera de retour une ligne vide pour chaque produit et de l'année, le mois de combo.

select
    fill.Category
    ,fill.month
    ,SUM(CASE WHEN YEAR = 2008 THEN Revenue ELSE 0 END) this_year
    ,SUM(CASE WHEN YEAR = 2007 THEN Revenue ELSE 0 END) last_year

from
    sales
    Right join (select distinct  --try out left, right and cross joins to test results.
                   product
                   ,year
                   ,month
               from
                  sales --this ideally would be from a products table
                  cross join tm
               where
                    year in (2008,2007)) fill


where
    fill.year in (2008,2007)

group by
    fill.Category
    ,fill.month

RETOURNE:

Category  |  Month  |  Rev. This Year  |  Rev. Last Year
Bikes          1          10 000               0
Bikes          2          12 000               11 000
Bikes          3          12 000               11 500
Bikes          4          0                    15 400
Bikes          5          0                    0
Bikes          6          0                    0
Bikes          7          0                    0
Bikes          8          0                    0

Notez que la plupart des outils de reporting fera ce tableau croisé ou de la matrice de la fonctionnalité, et maintenant que j'y pense SQL Server 2005 a pivot de la syntaxe qui va le faire ainsi.

Voici quelques ressources supplémentaires.CAS http://www.4guysfromrolla.com/webtech/102704-1.shtml SQL SERVER 2005 PIVOT http://msdn.microsoft.com/en-us/library/ms177410.aspx

Autres conseils

@Christian -- démarque de l'éditeur -- POUAH;en particulier lors de la prévisualisation et la version finale de votre post en désaccord...@Christian -- jointure externe complète -- la jointure externe complète est contredit par le fait qu'il y a des références à SP1 dans la clause where la clause where est appliqué après le REJOINDRE.Pour faire une jointure externe complète avec le filtrage sur l'une des tables, vous devez mettre votre clause where dans une sous-requête, de sorte que le filtrage se passe avant la jointure, ou essayer de construire l'ensemble de vos critères sur la JOINTURE SUR la clause, qui est incroyablement laid.Eh bien, il n'y a effectivement pas de jolie façon de faire de celui-ci.

@Jonas:Considérant ceci:

Aussi, le rapport est en fait pour l'année financière afin de J'aimerais avoir des colonnes vides avec des 0 dans les deux cas il n'y a pas de ventes à dire 5 mois, soit en 2007 ou en 2008.

et le fait que ce travail ne peut être fait avec une jolie requête, je voudrais certainement essayer d'obtenir les résultats que vous voulez vraiment.Aucun point en ayant une vilaine requête et pas même obtenir les données exactes que vous voulez vraiment.;)

Donc, je vous suggère de le faire en 5 étapes:
1.créer une table temporaire dans le format que vous voulez que vos résultats correspondent à
2.remplir avec douze lignes, avec 1 à 12 dans la colonne du mois de
3.mise à jour de la "Cette Année" dans la colonne à l'aide de votre SP1 logique
4.mise à jour de la "Dernière Année" de la colonne à l'aide de votre SP2 logique
5.sélectionnez à partir de la table temporaire

Bien sûr, je suppose que je suis en train de travailler à partir de l'hypothèse que vous pouvez créer une procédure stockée pour accomplir cette tâche.Vous pourriez être techniquement en mesure d'exécuter le lot entier en ligne, mais ce genre de laideur est très rarement vu.Si vous ne pouvez pas faire un SP, je vous suggère de revenir à la jointure externe complète via la sous-requête, mais il ne sera pas vous obtenir une ligne lorsqu'un mois avait pas de ventes, soit l'année.

À propos de la démarque - Oui, c'est frustrant.L'éditeur a aperçu mon tableau HTML, mais après la publication, il avait disparu - avait Donc de supprimer tout le code HTML mise en forme du post...

@kcrumley je pense que nous sommes parvenus à des conclusions similaires.Cette requête facilement s'laid.J'ai effectivement résolu ce problème avant de lire votre réponse, à l'aide d'un semblable (mais encore différentes de l'approche).J'ai accès à créer des procédures stockées et des fonctions sur la base de données de rapports.J'ai créé une fonction à valeur de Table d'accepter un produit de la catégorie et un exercice en tant que paramètre.Basé sur que la fonction va remplir un tableau contenant les 12 rangs.Les lignes seront remplis avec les données de la vue si les ventes de la disposition, si ce n'est la ligne aura valeurs à 0.

Je puis joindre les deux tables retournées par les fonctions.Car je sais que toutes les tables ont douze vagabonde, il est plus facile d'attribuer, et je peux me joindre sur la Catégorie de Produit et par Mois:

SELECT 
    SP1.Program,
    SP1.Year,
    SP1.Month,
    SP1.TotalRevenue AS ThisYearRevenue,
    SP2.TotalRevenue AS LastYearRevenue
FROM GetFinancialYear(@Category, 'First Look',  2008) AS SP1 
     RIGHT JOIN GetFinancialYear(@Category, 'First Look',  2007) AS SP2 ON 
         SP1.Program = SP2.Program AND 
         SP1.Month = SP2.Month

Je pense que votre approche est probablement un peu plus propre que le GetFinancialYear fonction est tout à fait désordre!Mais au moins cela fonctionne - ce qui me rend heureux pour l'instant ;)

L'astuce est de faire une JOINTURE avec la ISNULL pour obtenir les colonnes jointes à partir d'un tableau.J'ai l'habitude de terminer dans une vue ou une table dérivée, sinon vous devez utiliser la fonction ISNULL dans la clause where ainsi.

SELECT 
    Program,
    Month,
    ThisYearTotalRevenue,
    PriorYearTotalRevenue
FROM (
    SELECT 
        ISNULL(ThisYear.Program, PriorYear.Program) as Program,
        ISNULL(ThisYear.Month, PriorYear.Month),
        ISNULL(ThisYear.TotalRevenue, 0) as ThisYearTotalRevenue,
        ISNULL(PriorYear.TotalRevenue, 0) as PriorYearTotalRevenue
    FROM (
        SELECT Program, Month, SUM(TotalRevenue) as TotalRevenue 
        FROM PVMonthlyStatusReport 
        WHERE Year = @FinancialYear 
        GROUP BY Program, Month
    ) as ThisYear 
    FULL OUTER JOIN (
        SELECT Program, Month, SUM(TotalRevenue) as TotalRevenue 
        FROM PVMonthlyStatusReport 
        WHERE Year = (@FinancialYear - 1) 
        GROUP BY Program, Month
    ) as PriorYear ON
        ThisYear.Program = PriorYear.Program
        AND ThisYear.Month = PriorYear.Month
) as Revenue
WHERE 
    Program = 'Bikes'
ORDER BY 
    Month

Qui devrait vous obtenir vos exigences minimales - lignes avec un chiffre d'affaires soit en 2007 ou en 2008, ou les deux.Pour obtenir les lignes sans les ventes dans l'année, vous avez juste besoin de JOINTURE INTERNE à une 1-12 tableau de nombres (vous ne l'un de ceux, n'est-ce pas?).

J'ai peut-être tort, mais ne devriez-vous pas être à l'aide d'une jointure externe complète au lieu d'une jointure gauche?De cette façon, vous obtiendrez le "vide", les colonnes des deux tables.

http://en.wikipedia.org/wiki/Join_(SQL)#Full_outer_join

À l'aide du pivot et du Sql Dynamique, nous pouvons parvenir à ce résultat

SET NOCOUNT ON
IF OBJECT_ID('TEMPDB..#TEMP') IS NOT NULL
DROP TABLE #TEMP

;With cte(Category , Revenue  ,  Yearh  ,  [Month])
AS
(
SELECT 'Bikes', 10000, 2008,1 UNION ALL
SELECT 'Bikes', 12000, 2008,2 UNION ALL
SELECT 'Bikes', 12000, 2008,3 UNION ALL
SELECT 'Bikes', 15000, 2008,1 UNION ALL
SELECT 'Bikes', 11000, 2007,2 UNION ALL
SELECT 'Bikes', 11500, 2007,3 UNION ALL
SELECT 'Bikes', 15400, 2007,4
)
SELECT * INTO #Temp FROM cte

Declare @Column nvarchar(max),
        @Column2 nvarchar(max),
        @Sql nvarchar(max)


SELECT @Column=STUFF((SELECT DISTINCT ','+ 'ISNULL('+QUOTENAME(CAST(Yearh AS VArchar(10)))+','+'''0'''+')'+ 'AS '+ QUOTENAME(CAST(Yearh AS VArchar(10)))
FROM #Temp order by 1 desc FOR XML PATH ('')),1,1,'')

SELECT @Column2=STUFF((SELECT DISTINCT ','+ QUOTENAME(CAST(Yearh AS VArchar(10)))
FROM #Temp FOR XML PATH ('')),1,1,'')

SET @Sql= N'SELECT Category,[Month],'+ @Column +'FRom #Temp
            PIVOT
            (MIN(Revenue) FOR yearh IN ('+@Column2+')
            ) AS Pvt

            '
EXEC(@Sql)
Print @Sql

Résultat

Category    Month   2008    2007
----------------------------------
Bikes       1       10000   0
Bikes       2       12000   11000
Bikes       3       12000   11500
Bikes       4       0       15400
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top