Insérer des dates manquantes à partir d'une requête

9

Comment puis-je insérer des dates manquantes dans une requête que j'ai créée. Le résultat ci-dessous:

Date          Frequency
2014-05-18    5
2014-05-20    7
2014-05-25    7
2014-05-27    6

Je veux que le résultat ait des dates manquantes avec une valeur 0 comme indiqué ci-dessous:

Date          Frequency
2014-05-18    5
2014-05-19    0
2014-05-20    7
2014-05-21    0
2014-05-22    0
2014-05-23    0
2014-05-24    0
2014-05-25    7
2014-05-26    0
2014-05-27    6

Veuillez noter que je n'ai accès qu'en lecture seule au serveur.

Arvin
la source
utilisez-vous une requête pour récupérer le résultat? ou avez-vous défini une plage de dates. pouvez-vous ajouter votre requête ou table
vijayp
1
Utilisez un tableau de calendrier, sélectionnez-le et rejoignez vos fréquences par date social.technet.microsoft.com/wiki/contents/articles/…
Mark Sinkinson
J'utilise une requête pour récupérer le résultat de la table principale.
Arvin
Si vous disposez d' un accès en lecture seule , vous n'êtes pas censé insérer ou mettre à jour la base de données. Demandez plutôt à votre équipe DBA de vous aider.
Kin Shah
1
@Kin Je pense que la question signifie qu'ils veulent insérer des lignes dans le jeu de résultats, plutôt que d'insérer des lignes dans une table de base de données réelle.
Mark Sinkinson

Réponses:

12

Voici un exemple utilisant une table de calendrier (que vous devriez vraiment avoir). Cet exemple ne remplit que 2014, mais vous pouvez le remplir avec autant d'années que vous le souhaitez ...

CREATE TABLE dbo.Calendar(d DATE PRIMARY KEY);

INSERT dbo.Calendar(d) SELECT TOP (365)
 DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY number)-1, '20140101')
 FROM [master].dbo.spt_values
 WHERE [type] = N'P' ORDER BY number;

Maintenant, la requête est simple:

DECLARE @s DATE = '20140518', @e DATE = '20140527';

SELECT c.d, Frequency = COALESCE(s.Frequency,0)
  FROM dbo.Calendar AS c
  LEFT OUTER JOIN dbo.splunge AS s
  ON c.d = s.[date]
  WHERE c.d >= @s
    AND c.d < DATEADD(DAY, 1, @e);

Exemple SQLfiddle

Si vous ne pouvez pas créer une table de calendrier (et que vous n'avez pas non plus de table de nombres à portée de main), vous pouvez simplement la mettre en ligne:

DECLARE @s DATE = '20140518', @e DATE = '20140527';

SELECT c.d, Frequency = COALESCE(s.Frequency,0)
  FROM 
(
   SELECT TOP (DATEDIFF(DAY, @s, @e)+1)
 DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY number)-1, @s)
 FROM [master].dbo.spt_values
 WHERE [type] = N'P' ORDER BY number
) AS c(d)
  LEFT OUTER JOIN dbo.splunge2 AS s
  ON c.d = s.[date]
  WHERE c.d >= @s
    AND c.d < DATEADD(DAY, 1, @e);

Exemple SQLfiddle

Pour en savoir plus sur les groupes électrogènes (de dates, nombres, etc.), consultez cette série:

Aaron Bertrand
la source
0
DECLARE @t TABLE(Dt Date,Frequency int)
INSERT INTO @t VALUES
('2014-05-18',5),('2014-05-20',7),('2014-05-25',7),('2014-05-27',6)



DECLARE @startDate DATE, @endDate DATE
SELECT @startDate = '2014-05-18', @endDate = '2014-05-27' --yyyy-mm-dd
;WITH Calender AS (
    SELECT @startDate AS CalanderDate
    UNION ALL
    SELECT DATEADD(day,1,CalanderDate) FROM Calender
    WHERE DATEADD(day,1,CalanderDate) <= @endDate
)
INSERT INTO @t SELECT
    Dt = CalanderDate,Frequency = 0

FROM Calender c
LEFT JOIN @t t 
ON t.Dt = c.CalanderDate
WHERE t.dt IS NULL
option (maxrecursion 0)

SELECT * FROM @t ORDER BY dt

VIOLON

2014-05-18  5
2014-05-19  0
2014-05-20  7
2014-05-21  0
2014-05-22  0
2014-05-23  0
2014-05-24  0
2014-05-25  7
2014-05-26  0
2014-05-27  6
Mihai
la source
L'approche CTE récursive devient exponentiellement plus chère à mesure que la plage de dates s'élargit. Il existe des moyens plus efficaces de dériver des ensembles à cet effet.
Aaron Bertrand
@AaronBertrand La gamme est assez petite ici, mais tout lien vers des alternatives? Pour ma curiosité.
Mihai
1
Oui, ici , il se trouve que c'est une petite plage. Le problème est que les gens apprennent cette approche et l'appliquent ensuite à des échelles beaucoup plus grandes où cela devient un problème. Pourquoi utiliser une approche lente juste parce que c'est "ok" dans ce cas? Voir ma réponse.
Aaron Bertrand