2010-02-03 15 views
0

Afin d'éliminer le biais introduit par les différences de nombre de jours dans les mois et les années (dans le cas des années bissextiles), à partir des comparaisons mensuelles totales de quantités arbitraires et en supposant, par exemple, une table nommée My_Table avec une colonne datetime nommée order_date, et un entier un nommé revenue, j'utilise la requête suivante pour obtenir impartiales totaux des revenus mensuels:Supprimer le biais des totaux mensuels

-- sum revenue per month, divided by the number of days of that month 
-- and then multiplied by the average days of the that year's months 

SELECT datepart(mm,order_date) as my_month, sum(
round(convert(decimal, revenue)/
    CASE WHEN MONTH(order_date) = 2 THEN 
CASE WHEN (YEAR(order_date) % 4 = 0 AND YEAR(order_date) % 100 != 0) OR 
      (YEAR(order_date) % 400 = 0) THEN 29 ELSE 28 END 
    WHEN (MONTH(order_date)%8 + floor(MONTH(order_date)/8)) % 2 = 0 THEN 30 ELSE 31 END 
    * CASE WHEN (YEAR(order_date) % 4 = 0 AND YEAR(order_date) % 100 != 0) OR 
       (YEAR(order_date) % 400 = 0) THEN 366 ELSE 365 END/12 , 3) 
) as monthly_unb_revenue 
FROM My_Table 
group by datepart(mm,order_date) 

Je voudrais vos opinions ou d'autres pratiques

+0

Juste curieux, est-ce pour un système de base de données particulier? Des fonctions disponibles uniquement peuvent aider. –

+0

oui, en fait, c'est une requête sybase - j'ai oublié de préciser que :) –

Répondre

1

roulant vos propres calculs de calendrier peuvent être difficiles. Il est probablement plus fiable d'utiliser des fonctions intégrées.

Par exemple, vous pouvez trouver le premier jour de chaque mois comme:

DATEADD(mm, DATEDIFF(m,0,DateColumn),0) 

Faire un datediff entre les deux obtiendriez-vous le nombre de jours pour ce mois. Vous pouvez faire la même chose depuis des années:

select 
    datediff(d, 
     DATEADD(mm, DATEDIFF(mm,0,getdate()),0), 
     DATEADD(mm, DATEDIFF(mm,0,getdate())+1,0)) 
     as NumOfDaysThisMonth, 
    datediff(d, 
     DATEADD(yy, DATEDIFF(yy,0,getdate()),0), 
     DATEADD(yy, DATEDIFF(yy,0,getdate())+1,0)) 
     as NumOfDaysThisYear 

Cet exemple fonctionne sur SQL Server, je l'espère, il y a un équivalent sur Sybase :)

+0

Merci. Il semble que dans Sybase, la syntaxe soit légèrement différente, par ex. DATEDIFF nécessite une datepart et 2 arguments de date. Dans l'expression DATEDIFF (mm, 0, getdate()), 0 n'est pas accepté. De toute façon j'ai eu ton point de vue! –

+0

Dans le serveur SQL, la date '0' correspond à' '1900-01-01 00: 00: 00.000''. Vous pouvez entrer la date sous forme de chaîne dans Sybase. Bonne chance! – Andomar

0

Je suppose que vous utilisez SQL Server depuis cela semble être le seul système Je connais de avec datepart().

En oracle et MySQL vous avez une fonction LAST_DAY(). J'ai trouvé un équivalent de fonction définie par l'utilisateur pour SQL Server here:

CREATE FUNCTION [dbo].[ufn_GetLastDayOfMonth] (@pInputDate DATETIME) 
RETURNS DATETIME 
BEGIN 

    DECLARE @vOutputDate  DATETIME 

    SET @vOutputDate = CAST(YEAR(@pInputDate) AS VARCHAR(4)) + '/' + 
         CAST(MONTH(@pInputDate) AS VARCHAR(2)) + '/01' 
    SET @vOutputDate = DATEADD(DD, -1, DATEADD(M, 1, @vOutputDate)) 

    RETURN @vOutputDate 

END 
GO 

Vous pouvez ajouter cette fonction, puis l'utiliser pour simplifier votre requête.

+0

Dans SQL Server, vous pouvez trouver le dernier jour d'un mois avec 'DATEADD (s, -1, DATEADD (mm, DATEDIFF (m, 0, @ InputDate) +1,0))'. Mais il semble que l'OP utilise Sybase :) – Andomar