2016-12-20 2 views
3

Je me demande si quelqu'un pourrait être en mesure de résoudre ma requête. J'ai une table simple qui a des économies de projet par mois. Il y a toujours des économies de 12 mois consécutifs, mais le premier mois peut varier (par exemple: partir de janvier pour 12 mois, commencer à partir de mars pour 12 mois, etc.).Encore une autre LEFT OUTER JOIN échouer dans SQL Server 2012 Express

J'ai besoin d'un rapport qui me rapporte toutes les économies (par mois) pour une année donnée. Cela signifie que pour certaines économies de projet, si le mois de démarrage n'est pas janvier, alors certaines de ces économies de projet tomberont dans une année de rapport différente.

J'ai donc besoin d'une requête qui retournera tous les mois pour l'année du rapport en cours, et qui ne comporte aucun élément pour lequel un projet n'a pas de valeurs d'épargne pour ce mois.

J'ai quelques projets débutant en juillet, et je ne récupère que ces 6 mois avec leur valeur. C'est-à-dire que la gauche rejoint la date WITH n'est pas une connexion externe correcte. Quelqu'un peut-il me dire où je vais mal s'il vous plaît?

Code Voir ci-dessous:

DECLARE @MonthEndSnapshot SMALLDATETIME; 
SELECT @MonthEndSnapshot = getdate() 

DECLARE @StartDate SMALLDATETIME, @EndDate SMALLDATETIME; 
SELECT @StartDate = FORMAT(@MonthEndSnapshot, 'yyyy') + '0101', @EndDate = FORMAT(@MonthEndSnapshot, 'yyyy') + '1231'; 

;WITH d(d) AS 
(
    SELECT 
     DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, @StartDate), 0)) 
    FROM 
     (SELECT TOP 
      (DATEDIFF(MONTH, @StartDate, @EndDate) + 1) 
      n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1 
     FROM 
      sys.all_objects 
     ORDER BY [object_id]) AS n 
) 
select 
    left(datename(month, d.d), 3) as xAxisValueMon, 
    datepart(mm, d.d) as xAxisValue, 
    a.ProjectId as ProjectId, 
    ISNULL(SUM(a.Saving), 0) as yAxisValue 
from 
    d 
LEFT OUTER JOIN 
    (SELECT 
     mes.ProjectId, mes.Saving, mes.SavingMonth 
    FROM 
     dbo.sf_SnapshotMonthEndSaving() mes) AS a ON d.d = a.SavingMonth 
group by 
    a.ProjectId, datename(month, d.d), datepart(mm, d.d) 
order by 
    a.ProjectId, datepart(mm, d.d) 

Le AVEC d (d) des œuvres de Pärt, et retourne 12 dates mois (1er mois de janvier à décembre).

J'ai essayé aussi la structure suivante comme la requête:

;WITH d(d) AS 
(
    SELECT DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, @StartDate), 0)) 
    FROM (SELECT TOP (DATEDIFF(MONTH, @StartDate, @EndDate) + 1) 
    n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1 
    FROM sys.all_objects ORDER BY [object_id]) AS n 
) 
select left(datename(month, d.d), 3) as xAxisValueMon, 
    datepart(mm, d.d) as xAxisValue, 
    mes.ProjectId as ProjectId, 
    ISNULL(SUM(mes.Saving), 0) as yAxisValue 
from d LEFT OUTER JOIN 
    dbo.sf_SnapshotMonthEndSaving() mes 
    ON d.d = mes.SavingMonth 
group by mes.ProjectId, datename(month, d.d), datepart(mm, d.d) 
order by mes.ProjectId, datepart(mm, d.d) 

Mais mêmes résultats. Le tableau MonthEndSaving est la suivante:

CREATE TABLE [dbo].[MonthEndSaving] 
(
    [MonthEndSavingId] [int] IDENTITY(1,1) NOT NULL, 
    [MonthEndSnapshot] [datetime] NOT NULL, 
    [ProjectId] [int] NOT NULL, 
    [SavingMonth] [datetime] NOT NULL, 
    [Saving] [money] NOT NULL, 
    [DateCreated] [datetime] NOT NULL, 

    PRIMARY KEY CLUSTERED (MonthEndSavingId) 
) 
GO 

ALTER TABLE MonthEndSaving 
    ADD CONSTRAINT [ProjectMonthEndSaving] 
    FOREIGN KEY (ProjectId) REFERENCES [dbo].[Project](ProjectId) 
GO 
+0

Quelles sont les valeurs de 'mes.SavingMonth'? –

+0

Le projetID sera uniquement affiché pour les mois où ce projet a une valeur "SavingMonth" qui correspond à un mois dans votre jeu 'd'. Si vous voulez que chaque ID de projet apparaisse, vous devrez les rejoindre sans condition. Votre condition doit être dans une instruction 'CASE' à l'intérieur de votre' SUM' si je comprends bien (par exemple 'ISNULL (SUM (cas où MES.SavingMonth = MONTH (dd) THEN mes.Saving ELSE 0 END), 0) '). – Kidiskidvogingogin

+0

En se concentrant sur un seul ProjectId (qui commence à épargner à partir de juillet), vous prévoyez 12 enregistrements: un pour Jan, un pour Feb, un pour March, etc ... et vous attendez que ces 6 premiers enregistrements aient un montant nul et le 7ème et plus loin pour avoir les montants pertinents de la fonction de table. Droite? Et le problème est que vous n'avez que 6 enregistrements: un pour juillet, un pour août, un pour septembre, etc., chacun avec leurs montants respectifs. Est-ce que je comprends bien? – deroby

Répondre

0

Ce code doit faire ce que vous avez besoin:

DECLARE @MonthEndSnapshot SMALLDATETIME; 
SELECT @MonthEndSnapshot = getdate() 



DECLARE @StartDate SMALLDATETIME, @EndDate SMALLDATETIME; 
SELECT @StartDate = FORMAT(@MonthEndSnapshot, 'yyyy') + '0101', @EndDate = FORMAT(@MonthEndSnapshot, 'yyyy') + '1231'; 

;WITH d(d) AS 
(
    SELECT DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, @StartDate), 0)) 
    FROM (SELECT TOP (DATEDIFF(MONTH, @StartDate, @EndDate) + 1) 
    n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1 
    FROM sys.all_objects ORDER BY [object_id]) AS n 
) 
select left(datename(month, d.d), 3) as xAxisValueMon, 
    datepart(mm, d.d) as xAxisValue, 
    prj.ProjectId as ProjectId, 
    ISNULL(SUM(a.Saving), 0) as yAxisValue 
from d 
CROSS JOIN 
    (
     SELECT DISTINCT mes.ProjectId 
     FROM dbo.sf_SnapshotMonthEndSaving() mes 
    ) as prj 
LEFT OUTER JOIN 
    (
     SELECT mes.ProjectId, mes.Saving, mes.SavingMonth 
     FROM dbo.sf_SnapshotMonthEndSaving() mes 
    ) as a 
    ON d.d = a.SavingMonth 
    AND prj.ProjectID = a.ProjectID 
group by prj.ProjectId, datename(month, d.d), datepart(mm, d.d) 
order by prj.ProjectId, datepart(mm, d.d) 
1

Dang, Rire Vergil semble être plus rapide dactylo =) Quoi qu'il en soit, l'idée est à peu près la même. Votre 'erreur' était que vous vous joignez chaque mois à TOUS les projets au dbo.sf_SnapshotMonthEndSaving(). Si l'un s'adapte, il est retourné pour celui-là seulement, si deux correspondent, il montrera ces deux etc ... mais il ne se répétera pas pour CHAQUE projet. Ceci devrait.

DECLARE @StartDate datetime = '1 jan 2016', 
     @EndDate datetime = '1 dec 2016' 

;WITH d(FirstDayOfMonth) AS 
(
    SELECT DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, @StartDate), 0)) 
    FROM (SELECT TOP (DATEDIFF(MONTH, @StartDate, @EndDate) + 1) 
    n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1 
    FROM sys.all_objects ORDER BY [object_id]) AS n 
), 
RelevantProjects AS 
(
    SELECT DISTINCT ProjectId 
    FROM dbo.sf_SnapshotMonthEndSaving() mes 
    WHERE mes.SavingMonth BETWEEN @StartDate AND @EndDate -- you could also join to d but I think this is faster 
), 
ProjectsAndDates AS 
(
    SELECT ProjectID, 
      FirstDayOfMonth 
     FROM d 
    CROSS JOIN RelevantProjects 
) 
select left(datename(month, d.FirstDayOfMonth), 3) as xAxisValueMon, 
     datepart(mm, d.FirstDayOfMonth) as xAxisValue, 
     d.ProjectId as ProjectId, 
     ISNULL(SUM(mes.Saving), 0) as yAxisValue 
    from ProjectsAndDates d 
    LEFT OUTER JOIN [MonthEndSaving] mes -- dbo.sf_SnapshotMonthEndSaving() mes 
       ON mes.SavingMonth = d.FirstDayOfMonth 
       AND mes.Project_id = d.ProjectID 
    group by d.ProjectId, datename(month, d.FirstDayOfMonth), datepart(mm, d.FirstDayOfMonth) 
    order by d.ProjectId, datepart(mm, d.FirstDayOfMonth) 
+0

Génial !! Merci pour ce @deroby et @LaughingVergil! En réalité, je dois encore le joindre à une table de projet pour obtenir ProjectTypeId au lieu de simplement ProjectId. Mais vous m'avez aidé à résoudre le problème avec le JOIN. Voyons comment je peux le remplir d'ici! p –