Press "Enter" to skip to content

Usare la funzione Rank per estrarre una lista di righe con la data più alta

Oggi avevo il problema di dover creare una query che mi restituisse il prezzo più recente contenuto in una tabella listini. Ogni listino può contenere gli stessi articoli ripetuti più volte, ciascuna riga con una data di validità diversa. Ho fatto qualche ricerca in merito ed ho trovato la funzione RANK, usata in un caso simile, pubblico quindi un esempio in modo da ricordarmi come fare quando mi servirà di nuovo e ovviamente dare a chi legge un suggerimento per risolvere simili problemi.

La tabella

CREATE TABLE [dbo].[TbListiniRg](
    [IDListinoRg] [int] NOT NULL,
    [IDListino] [nvarchar](10) NOT NULL,
    [IDArticolo] [nvarchar](32) NULL,
    [Prezzo] [decimal](18, 5) NULL,
    [ValidoDal] [date] NULL,
 CONSTRAINT [PK_TbListiniRg] PRIMARY KEY CLUSTERED 
(
    [IDListinoRg] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  
= ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]

Ogni riga è collegata al listino tramite IDListino, la tabella listini non ci serve quindi è stata omessa.

INSERT INTO [dbo].[TbListiniRg]
           ([IDListino]
           ,[IDArticolo]
           ,[Prezzo]
           ,[ValidoDal])
     VALUES
           ('CLD'
           ,'ABC'
           ,10
           ,CONVERT(date, '20080105', 112))
GO

INSERT INTO [dbo].[TbListiniRg]
           ([IDListino]
           ,[IDArticolo]
           ,[Prezzo]
           ,[ValidoDal])
     VALUES
           ('CLD'
           ,'OCQ'
           ,14
           ,CONVERT(date, '20080105', 112))
GO

INSERT INTO [dbo].[TbListiniRg]
           ([IDListino]
           ,[IDArticolo]
           ,[Prezzo]
           ,[ValidoDal])
     VALUES
           ('CLD'
           ,'FYS'
           ,21
           ,CONVERT(date, '20080105', 112))
GO

INSERT INTO [dbo].[TbListiniRg]
           ([IDListino]
           ,[IDArticolo]
           ,[Prezzo]
           ,[ValidoDal])
     VALUES
           ('CLD'
           ,'MUI'
           ,13
           ,CONVERT(date, '20080105', 112))
GO

INSERT INTO [dbo].[TbListiniRg]
           ([IDListino]
           ,[IDArticolo]
           ,[Prezzo]
           ,[ValidoDal])
     VALUES
           ('CLD'
           ,'SIO'
           ,42
           ,CONVERT(date, '20080105', 112))
GO

INSERT INTO [dbo].[TbListiniRg]
           ([IDListino]
           ,[IDArticolo]
           ,[Prezzo]
           ,[ValidoDal])
     VALUES
           ('CLD'
           ,'GOU'
           ,18
           ,CONVERT(date, '20080105', 112))
GO

INSERT INTO [dbo].[TbListiniRg]
           ([IDListino]
           ,[IDArticolo]
           ,[Prezzo]
           ,[ValidoDal])
     VALUES
           ('CLD'
           ,'HOU'
           ,20
           ,CONVERT(date, '20080105', 112))
GO

Questo script inserisce alcuni articoli, ripetuto variando il codice listino, le date ed i prezzi ci permetterà di dimostrare la nostra funzionalità.

SELECT [IDListinoRg]
      ,[IDListino]
      ,[IDArticolo]
      ,[Prezzo]
      ,[ValidoDal]
      ,RANK() OVER (PARTITION BY IDLISTINO, IDARTICOLO ORDER BY ValidoDal DESC) DATERANK
  FROM [paperinik].[dbo].[TbListiniRg]

La funzione RANK ci permette di indicare uno o più campi di raggruppamento su cui il calcolo del Ranking viene effettuato,  usando la clausola PARTITION BY, ovvero su quali campi spezzare il calcolo del ranking in questo caso codice listino ed articolo. La clausola ORDER BY indica invece qual’è il campo su cui il Ranking viene misurato, mentre la clausola DESC dice che vogliamo andare dalla data più recente indietro.

Questa query ci da questo risultato.

IDListinoRg IDListino IDArticolo Prezzo ValidoDal DATERANK
107 CLD ABC 1.000.000 24/10/2010 1
86 CLD ABC 1.000.000 15/05/2010 2
65 CLD ABC 1.000.000 08/01/2010 3
44 CLD ABC 1.000.000 08/09/2009 4
23 CLD ABC 1.000.000 16/04/2009 5
1 CLD ABC 1.000.000 05/01/2008 6
2 CLD ABC 1.000.000 05/01/2008 6
109 CLD FYS 2.100.000 24/10/2010 1
88 CLD FYS 2.100.000 15/05/2010 2
67 CLD FYS 2.100.000 08/01/2010 3
46 CLD FYS 2.100.000 08/09/2009 4
25 CLD FYS 2.100.000 16/04/2009 5
4 CLD FYS 2.100.000 05/01/2008 6
112 CLD GOU 1.800.000 24/10/2010 1
91 CLD GOU 1.800.000 15/05/2010 2
70 CLD GOU 1.800.000 08/01/2010 3
49 CLD GOU 1.800.000 08/09/2009 4
28 CLD GOU 1.800.000 16/04/2009 5
7 CLD GOU 1.800.000 05/01/2008 6
113 CLD HOU 2.000.000 24/10/2010 1
92 CLD HOU 2.000.000 15/05/2010 2
71 CLD HOU 2.000.000 08/01/2010 3
50 CLD HOU 2.000.000 08/09/2009 4
29 CLD HOU 2.000.000 16/04/2009 5
8 CLD HOU 2.000.000 05/01/2008 6

Pertanto per poter vedere solo il prezzo più recente, ci basta un filtro sul DATERANK = 1, così come per avere la data meno recente ci basta togliere la clausola DESC dalla query.