Pregunta

Tengo una tabla con los siguientes datos:

Fiscal Year | Fiscal Quarter | Fiscal Week | Data
2009        | 2              | 22          | 9.5
2009        | 2              | 24          | 8.8
2009        | 2              | 26          | 8.8
2009        | 3              | 28          | 8.8
2009        | 3              | 31          | 9.1
2009        | 3              | 33          | 8.8

Me gustaría escribir una consulta que produciría el siguiente:

Fiscal Year | Fiscal Quarter | Fiscal Week | Data | Trend
2009        | 2              | 22          | 9.5  | NULL
2009        | 2              | 24          | 8.8  | -0.7
2009        | 2              | 26          | 8.8  | 0
2009        | 3              | 28          | 8.8  | 0
2009        | 3              | 31          | 9.1  | 0.3
2009        | 3              | 33          | 8.8  | -0.3 

Sé que esto puede lograrse fácilmente haciendo una simple unión de las tablas a sí mismo con la semana fiscal anterior, sin embargo, esto no siempre será un t1.[Fiscal Week] = t2.[Fiscal Week] - 2 sencilla porque a veces la diferencia es de 3 semanas.

Puedo tirar del registro máximo fácilmente con algo como esto:

SELECT
    MAX(t1.[Fiscal Week]) "LastWeek"
FROM t1
WHERE t1.[Fiscal Year] = 2009
    AND t1.[Fiscal Week] < 31

Pero estoy en una pérdida cuando se trata de la abstracción para hacer el trabajo unirse.

¿Cómo puedo hacer una auto unirse en "el más grande semanas fiscal que es más pequeño que el registro actual"?

¿Fue útil?

Solución

La manera más fácil de hacer esto con SQL 2005 + es utilizar la funciones de ventanas - simplemente partición / ordenar sus datos y asignar una secuencia apropiada para cada registro (en este caso está particionando por fiscalYear y pedidos por fiscalWeek sobre esa ventana) - sería algo como esto:

with data as
(
    select  row_number() over (partition by a.fiscalYear order by a.fiscalWeek) as rn,
            a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data
    from    #TableName a
)
select  a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data, 
        a.Data - b.Data as Trend
from    data a
left join data b
on      a.fiscalYear = b.fiscalYear
and     a.rn = b.rn + 1
order by a.fiscalYear, a.rn

Esta consulta en particular no permitiría la extensión a través de fronteras fiscalYear - si desea extender a cruzar estas fronteras año sólo tendría que quieren dejar caer la "partición" cláusula y "fiscalYear" condición de combinación y en lugar de ordenar el establecido por una combinación del fiscalYear y fiscalWeek, algo como esto:

with data as
(
    select  row_number() over (order by a.fiscalYear + a.fiscalWeek) as rn,
            a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data
    from    #TableName a
)
select  a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data, 
        a.Data - b.Data as Trend
from    data a
left join data b
on      a.rn = b.rn + 1
order by a.rn

Otros consejos

Cómo funciona? La consulta en línea es un poco de un bocado y es probable que haya una mejor manera de hacerlo ...

select
  [fiscal year]
, [fiscal quarter]
, [fiscal week]
, [data] 
, (
    select top 1 (i.data - t1.data) from t1 as i
    where i.[fiscal year] >= t1.[fiscal year]
    and i.[fiscal quarter] >= t1.[fiscal quarter]
    and i.[fiscal week] >= t1.[fiscal week]
    and (
          i.[fiscal year] <> t1.[fiscal year]
       or i.[fiscal quarter] <> t1.[fiscal quarter]
       or i.[fiscal week] <> t1.[fiscal week]
    )
    order by [fiscal year] asc, [fiscal quarter] asc, [fiscal week] asc
) as trend
from t1

Si está utilizando SQL Server 2005, puede utilizar la cláusula CROSS APPLY.

Aquí podría tener una función con valores de tabla, que devolverá la fila para la semana fiscal, antes de la una en la fila actual.

CREATE FUNCTION dbo.fn_GetFiscalWeekBeforeThis(@Year AS int, 
  @CurrentWeek as int)
  RETURNS TABLE
AS
RETURN
  SELECT TOP 1 *
  FROM t1
  WHERE [Fiscal Year] = @Year 
  AND [Fiscal Week] < @CurrentWeek
  ORDER BY [Fiscal Week] DESC
GO

Y a continuación,

SELECT A.*,
A.Data - B.Data
FROM
t1 A
CROSS APPLY 
   dbo.fn_GetFiscalWeekBeforeThis(A.[Fiscal Year],  
   A.[Fiscal Week]) AS B

EDIT: Tenga en cuenta que he adaptado el SQL examinado un artículo y sin un IDE
. Además, no sé -. Cómo se va a trabajar para la primera fila

Así que, por favor, ser amable:)

Edit2: Quiero saber, si no funciona en absoluto
. Esto me ayudará a conocer -. No responder a las cosas, sin comprobar los resultados

Edit3:. I Se ha eliminado la necesidad de parámetro cuartos de la función

DECLARE @Fiscal TABLE
  ( 
   FiscalYear int
  ,FiscalQuarter int
  ,FiscalWeek int
  ,[Data] decimal(4,1) 
  )

INSERT INTO @Fiscal
          ( FiscalYear, FiscalQuarter, FiscalWeek, [Data] )
SELECT 2009, 2, 22, 9.5 UNION
SELECT 2009, 2, 24, 8.8 UNION
SELECT 2009, 2, 26, 8.8 UNION
SELECT 2009, 3, 28, 8.8 UNION
SELECT 2009, 3, 31, 9.1 UNION
SELECT 2009, 3, 33, 8.8 UNION
SELECT 2010, 1, 1, 9.0 UNION
SELECT 2010, 1, 2, 9.2

;
WITH  abcd
        AS ( SELECT FiscalYear
                   ,FiscalQuarter
                   ,FiscalWeek
                   ,[Data]
                   ,row_number() OVER ( ORDER BY FiscalYear, FiscalWeek ) AS rn
             FROM   @Fiscal
           )
  SELECT  a.FiscalYear
         ,a.FiscalQuarter
         ,a.FiscalWeek
         ,a.[Data]
         ,a.[Data] - b.[Data] AS [Trend]
  FROM    abcd AS a
          LEFT JOIN abcd AS b ON b.rn = ( a.rn - 1 )
  ORDER BY a.FiscalYear
         ,a.FiscalWeek
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top