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.