MS SQL Server è un ottimo prodotto, ma secondo
me ha una grande mancanza:
manca la possibilità di specificare in una query che si vogliono solo le
righe dalle 11 alla 20.
Qualcuno potrebbe dire che basta fare un Select top
20 * from ... e poi
saltare le prime 10 righe in visualizzazione: sfortunatamente il numero dopo il
TOP non è parametrizzabile,
quindi non si può fare passare ad una stored procedure.
Ovviamente ci sono altri mille modi per fare paginazione - salvare la
datatable nella session, magari anche nella cache se è una query
generica (il comunissimo elenco news), ecc... - ma io dovevo per forza mettere
nella stored tutta la logica di paginazione: stavo facendo il modulo MS SQL per
uno dei progetti opensource al quale collaboro (Jgossip) e il modulo di accesso
ai dati era fatto in maniera tale che, nonostante ci fossero N
drivers per gli N database supportati, questi drivers contenevano
solo le query da passare al DB, e non anche tutta la logica di estrazione.
In pratica dovevo fare in modo di ottenere con MS SQL quello con MySQL si fa
semplicemente aggiundo alla fine della query
LIMIT start, pageSize
Questo è il codice della SP che emula il LIMIT di MySQL:
CREATE PROCEDURE
sp_GET_LOG_ENTRIES_ASC
@intimePar varchar(255),
@endtimePar varchar(255),
@loggerPar
varchar(255),
@log_levelPar varchar(32),
@remote_ipPar
varchar(16),
@session_idPar varchar(255),
@user_namePar
varchar(32),
@start int,
@pageSize int
... click here to open ...
... click here to collapse ...
CREATE PROCEDURE
sp_GET_LOG_ENTRIES_ASC
@intimePar varchar(255),
@endtimePar varchar(255),
@loggerPar
varchar(255),
@log_levelPar varchar(32),
@remote_ipPar
varchar(16),
@session_idPar varchar(255),
@user_namePar
varchar(32),
@start int,
@pageSize int
AS
DECLARE @count int
DECLARE @realStart int
DECLARE @log_date varchar(80)
DECLARE @logger
varchar(255)
DECLARE @log_level varchar(32)
DECLARE @message
varchar(2000)
DECLARE @remote_ip varchar(16)
DECLARE @user_name
varchar(32)
DECLARE @session_id varchar(255)
SET @count=0
SET @realStart=@start+1
CREATE TABLE
#tmp
(
log_date
varchar(80),
logger
varchar(255),
log_level
varchar(32),
message
varchar(2000),
remote_ip
varchar(16),
session_id
varchar(255),
user_name
varchar(32)
)
DECLARE log_cursor SCROLL CURSOR FOR
SELECT log_date, logger, log_level,
message, remote_ip, session_id, user_name
FROM jrf_audit_log
WHERE whereStr
ORDER
BY log_date
OPEN log_cursor
FETCH ABSOLUTE @realStart FROM log_cursor
INTO
@log_date,@logger,@log_level,@message,@remote_ip,@session_id,@user_name
IF
@@FETCH_STATUS = 0
insert into #tmp values
(@log_date,@logger,@log_level,@message,@remote_ip,@session_id,@user_name)
WHILE
@@FETCH_STATUS = 0 and @count<@pageSize
BEGIN
SET
@count=@count+1
IF
@count<@pageSize
BEGIN
FETCH NEXT FROM
log_cursor
INTO
@log_date,@logger,@log_level,@message,@remote_ip,@session_id,@user_name
IF
@@FETCH_STATUS = 0
insert into #tmp values
(@log_date,@logger,@log_level,@message,@remote_ip,@session_id,@user_name)
END
END
CLOSE log_cursor
DEALLOCATE log_cursor
select * from #tmp
In pratica creo una tabella temporanea con i campi che mi
servono come risultato, poi dichiaro un cursore e lo apro sulla query vera da
fare al DB e, durante il fetch popolo la tabella temporanea solo se le
righe sono nell'intervallo richiesto, e alla fine faccio il select sulla tabella
temporanea (che contiene solo le righe richieste)
Spero che qualcun'altro possa trarre giovamento da questa
mia pazzia in SP.
powered by IMHO