[SQLSrv] Da data a data - x

mercoledì 22 marzo 2006 - 10.07

Hamelin [FL] Profilo | Junior Member

In primo luogo vorrei ringraziare sentitamente chi mi ha risposto nel thread riguardante le variabili

Avrei un'altra domanda, molto più semplice della precedente (spero :P ):

Avendo una tabella con usrId e DataLogin (tipo 31/01/2005), dovrei fare alcune select tra la DataLogin e i 365 giorni precedenti a quella data. Cioè qualcosa tipo:

SELECT ...
FROM ...
WHERE DataLogin BETWEEN DataLogin-365 AND DataLogin

Dite che è possibile? Sapete per caso la sintassi corretta? Qualcosa tipo

WHERE (DataLogin BETWEEN CONVERT(datetime, DataLogin - 365, 120) AND CONVERT(datetime, DataLogin, 120))

Ma questo naturalmente dà errore :)

Di nuovo grazie a tutti quanti

alx_81 Profilo | Guru

In questo caso ti è utile la dateadd..
è una funzione che accetta come parametri la parte di data da aggiungere, il numero di unità, relativi alla parte, da aggiungere e la data da prendere in considerazione.

Avendo la tua tabella io farei:

select * from TuaTabella
where DataLogin between DATEADD(d,-365,DataLogin) and DataLogin
-- ovviamente aggiungi le condizioni necessarie per ottenere solo i record che ti interessano, se necessario.

In poche parole ho aggiunto -365 d (days) ad ogni DataLogin della tabella..

ok?

spero di esserti stato di aiuto!
fammi sapere!
ciao!
Alx81 =)

alx_81 Profilo | Guru

Se ti serve uno scalare con il numero di giorni intercorsi va bene la datediff.. altrimenti se ti serve una data o un elenco di date.. è meglio la dateadd..
Alx81 =)

lbenaglia Profilo | Guru

>In primo luogo vorrei ringraziare sentitamente chi mi ha risposto
>nel thread riguardante le variabili

Ciao Hamelin [FL] ,

se ritieni di aver ricevuto informazioni utili, puoi votare la risposta migliore

>Avendo una tabella con usrId e DataLogin (tipo 31/01/2005), dovrei
>fare alcune select tra la DataLogin e i 365 giorni precedenti
>a quella data. Cioè qualcosa tipo:
>
>SELECT ...
>FROM ...
>WHERE DataLogin BETWEEN DataLogin-365 AND DataLogin
>
>Dite che è possibile? Sapete per caso la sintassi corretta?

SQL Server offre due data types per la memorizzazione delle date: datetime e smalldatetime.

datetime
--------
Range di validità: 1 gennaio 1753 - 31 dicembre 9999 con una precisione pari a 0.00333 secondi.
Bytes occupati: 8 (2 coppie di interi di 4 bytes)
- i primi 4 per la memorizzazione dei giorni prima o dopo l'1 gennaio 1900
- gli altri 4 per la memorizzazione dei millisecondi dopo la mezzanotte

smalldatetime
-------------
Range di validità: 1 gennaio 1900 - 6 giugno 2079 con una precisione al minuto.
Bytes occupati: 4 (2 coppie di interi di 2 bytes)
- i primi 2 per la memorizzazione dei giorni dopo l'1 gennaio 1900
- gli altri 2 per la memorizzazione dei minuti dopo la mezzanotte

In entrambi i casi la base date è 01/01/1900. Le date antecedenti la base
date saranno rappresentati da numeri negativi mentre quelle successive come
numeri positivi.

Come vedi le date sono memorizzate in coppie di numeri interi: il primo numero memorizza la data mentre il secondo l'ora.

> WHERE DataLogin BETWEEN DataLogin-365 AND DataLogin

Se il data type della colonna DataLogin è datetime o smalldatetime, l'operazione DataLogin-365 non fa altro che sottrarre 365 giorni dalle date memorizzate nella colonna DataLogin.
Ad ogni modo non capisco quella condizione di WHERE.... Che significa?
Verifichi che DataLogin sia compresa tra DataLogin di 1 anno fa e DataLogin stessa... in pratica questa condizione sarà sempre True quindi restituirai tutte le righe.

Secondo me dopo la BETWEEN dovrai specificare dei parametri di input o delle costanti nel formato 'YYYYMMDD'.

>Di nuovo grazie a tutti quanti
Prego.

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

Hamelin [FL] Profilo | Junior Member

Dunque: la funzione DateAdd fa proprio quello che chiedevo, quindi già di questo vi ringrazio

Ora provo a spiegare un po' meglio cosa mi serviva in modo che vediamo se sto dicendo cose sensate oppure no:

In pratica dovrei definire un utente in base al numero di login che ha fatto negli ultimi 12 mesi rispetto a ogni mese considerato. Se ha eseguito 1 login è un utente "Normal", se ne ha eseguite 2 è "Super". Questo controllo però non lo devo fare su una finestra "statica" di 12 mesi, ma sui 12 mesi precedenti a ogni mese di login. Quindi se la tabella delle login ha questi dati:

[UsrId] [DataLogin]
1 | 01/01/2005
1 | 02/01/2005

E, nel 2006, faccio la mia stima, l'utente 1 dev'essere definito 'Super' a gennaio 2006 (perchè negli ultimi 12 mesi, e cioè da gennaio 2005 a gennaio 2006, ha eseguito 2 login) e 'Normal' a febbraio 2006 (perchè negli ultimi 12 mesi, e cioè da febbraio 2005 a febbraio 2006, ha eseguito 1 login, visto che la prima non viene più considerata)

Probabilmente sbagliando, il modo che ho trovato di risolvere il problema è stato il seguente:

SELECT usrId,
CASE
WHEN COUNT(usrId) = 2 THEN 'Super'
ELSE 'Normal' END
AS TipoUtente
FROM TabellaLogin
WHERE DataLogin BETWEEN DATEADD(d, - 365, DataLogin) AND DataLogin

Io cioè speravo che, riga per riga, mi definisse l'utente in base alla data login di quella riga, e ai 12 mesi precedenti.
Sbaglio? Se sì, dite che esiste un modo per risolvere il mio problema?

Grazie per l'attenzione

alx_81 Profilo | Guru

Direi che va bene..hai fatto una cosa giusta..
magari metterei >1 invece di = 2... visto che un utente sarà super anche se si è loggato più di 2 volte no? =)))
io credo di averti dato l'aiuto corretto per quello che ti serviva..
DateAdd è ok..
a meno che chi ne sa più di me (e sono a miliardi) non trovi soluzioni più furbe..
allora copierò! =)
Ciao!
Alx81 =)

Hamelin [FL] Profilo | Junior Member

Anch'io pensavo fosse giusta, ma non sembra funzionare come dovrebbe ^^" (sembra che la finestra non cambi riga per riga, ma sia fissa per tutta la stima)

Ora mi ci scorno un po' per tentare di capire meglio... magari sfugge uno di quegli errori logici minimi che rendono tutto completamente sbagliato :P

(comunque sì, in base alla mia richiesta iniziale la funzione che mi hai dato era proprio quella giusta, grazie mille :) )

lbenaglia Profilo | Guru

>Anch'io pensavo fosse giusta, ma non sembra funzionare come dovrebbe
>^^" (sembra che la finestra non cambi riga per riga, ma sia fissa
>per tutta la stima)

Ciao Hamelin [FL],

come ti ho già spiegato nel precedente post quella condizione di ricerca è priva di senso e anche la logica che stai cercando di implementare mi è poco chiara.
Nel tuo precedente esempio dicevi:

> E, nel 2006, faccio la mia stima, l'utente 1 dev'essere definito 'Super' a gennaio 2006
> (perchè negli ultimi 12 mesi, e cioè da gennaio 2005 a gennaio 2006, ha eseguito 2 login)
> e 'Normal' a febbraio 2006 (perchè negli ultimi 12 mesi, e cioè da febbraio 2005 a febbraio 2006,
> ha eseguito 1 login, visto che la prima non viene più considerata)

Ma dove specifichi nella query che stai prendendo in considerazione gennaio 2006, febbraio 2006...?

>(comunque sì, in base alla mia richiesta iniziale la funzione
>che mi hai dato era proprio quella giusta, grazie mille :) )

Dato che devi semplicemente sottrarre da una data un certo numero di giorni, in questo caso la funzione DATEADD() può essere tranquillamente sostituita dall'operatore algebrico "-" generando meno overhead del dovuto.

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

Hamelin [FL] Profilo | Junior Member

> Ma dove specifichi nella query che stai prendendo in considerazione gennaio 2006, febbraio 2006...?

Provo a spiegare la logica che sto tenendo, sperando mi possiate dare una mano a rendere sensata la query, in base alle richieste:

- Parto dalla tabella con i campi UsrId e DataLogin

- Su questa faccio la view scritta sopra che mi definisce il tipo di utente in base a quante login ha fatto nei 12 mesi precedenti il valore del mese presente in DataLogin, aggiungendo un group by YEAR in modo che me li suddivida per anno (e già mi rendo conto che questo è un errore, è per questo motivo che la finestra mi resta statica: in realtà mi restituisce niente più che i tipi utenti raggruppati per anno, ma non tiene conto della mia clausola WHERE. Forse dovrei raggrupparli sulla finestra, anzichè mettere la finestra sul where, ma non saprei come)
Per fare questo speravo che mettendo "WHERE DataLogin BETWEEN DataLogin-365 AND DataLogin" mi considerasse appunto, riga per riga, i 12 mesi precedenti la data presente nel campo.
Da questa view ottengo una tabella del tipo [UsrId] [TipoUtente]

- Una seconda view mi serve appunto per tener conto del mese. Definisco questa view come
SELECT usrId, MONTH([Data Login]) AS Mese, YEAR([Data Login]) AS Anno
FROM Tabella
GROUP BY usrId, MONTH([Data Login]), YEAR([Data Login])

- A questo punto la query finale, tramite un join tra le due basato sull'usrId, gruppando per tipo utente, mese e anno mi restituisce la tabella [TipoUtente] [ConteggioLogin] [Mese] [Anno]


Dite che è risolvibile la richiesta del datore di lavoro? E' proprio sbagliato il mio ragionamento? Il problema credo sia sulla finestra scorrevole... Dovrei in qualche modo modificare la prima view in modo che non sia fissa su un intervallo temporale, ma che scorra sui 12 mesi precedenti il login

lbenaglia Profilo | Guru

>Per fare questo speravo che mettendo "WHERE DataLogin BETWEEN
>DataLogin-365 AND DataLogin" mi considerasse appunto, riga per
>riga, i 12 mesi precedenti la data presente nel campo.

Ciao Hamelin [FL],

vedo che insisti su quella WHERE... ragioniamo insieme.
Supponiamo di avere DataLogin = '20060322'.
La WHERE sarebbe:

WHERE '20060322' BETWEEN '20050322' AND '20060322' che ovviamente è vera, ma lo sarebbe con qualsiasi data!!

Se vuoi ricevere un aiuto più mirato, posta un piccolo esempio con la struttura della tabella base (CREATE TABLE), alcune righe di prova (INSERT INTO) ed il result set che vorresti ottenere.

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

Hamelin [FL] Profilo | Junior Member

No no, come ti ho detto mi sono persuaso che quella clausola non ha senso e non è assolutamente risolutiva del mio problema :)

Purtroppo, però, non riesco a trovare una soluzione. Spero almeno di aver fatto capire cosa mi servirebbe:

Da una tabella degli usrId e DateLogin

UsrId | DataLogin
1 | 01/01/2005
1 | 01/02/2005
2 | 01/02/2005
3 | 02/02/2005
1 | 01/03/2005


Alla fine devo arrivare a una tabella che mi dica, per ogni mese, quanti sono gli utenti di ogni tipo
Mese | Tipo | NumeroUtentiPerTipo
1 | Sconosciuto | 2
1 | Normale | 1
2 | Sconosciuto | 1
2 | Normale | 1

Dove "Sconosciuto" e "Normale" del mese 1 lo definisco in base a quante login ha fatto nei 12 mesi precedenti al mese 1
Sconosciuto e Normale del mese 2 lo definisco in base a quante login ha fatto nei 12 mesi precedenti al mese 2
E così via

Ho dato sufficienti informazioni? Sono stato comprensibile? E soprattutto: sarà risolvibile in qualche modo?

Grazie davvero, sono un po' in panne...

lbenaglia Profilo | Guru

>Ho dato sufficienti informazioni? Sono stato comprensibile? E
>soprattutto: sarà risolvibile in qualche modo?

A questo punto getto la sugna, mi dispiace ma non capisco la logica che vuoi applicare.
Vediamo se qualcun altro sarà in grado di darti una mano.

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

Hamelin [FL] Profilo | Junior Member

Nel caso non mi sia spiegato bene posso provare ad essere più chiaro

(si tratta di sapere, ogni mese, quante login ha fatto ogni "tipo di utente". E per stabilire il tipo di utente guardo quante login ha fatto un utente nell'arco di tempo pari a 12 mesi prima del mese che sto considerando)

Se invece è proprio la richiesta ad essere contorta/irrisolvibile nulla, massimo rassegnerò le mie dimissioni :P (perchè ovviamente se non si può fare non ci crederanno mai, e passerò io per incompetente - cosa peraltro vera in questo genere di cose)

Grazie comunque per l'aiuto, e speriamo che qualcuno sappia trovare una via percorribile

Hamelin [FL] Profilo | Junior Member

La sintassi è scorrettissima, ma si dovrebbe risolvere con qualcosa tipo:

WHERE CASE
WHEN month([Data Login]) = 1 THEN [Data Login] BETWEEN '2004-01-01' AND '2005-01-01'
WHEN month([Data Login]) = 2 THEN [Data Login] BETWEEN '2004-02-01' AND '2005-02-01'
ELSE [Data Login] BETWEEN '2004-03-01' AND '2005-03-01'
END

Anche lasciando perdere il resto dell'architettura, c'è il modo di programmare in SQL qualcosa che faccia una cosa del genere?

Hamelin [FL] Profilo | Junior Member

Mi è stata fornita questa soluzione:

WHERE (month (data_login) = 1 and data_login between 01/01/2005 and 01/01/2006)
or (month (data_login) = 2 and data_login between 01/02/2005 and 01/02/2006)
or (...)


Che è un po' macchinosa da fare per tutti i mesi dell'anno (servono 12 rami OR), però mi sembra corretta

Forse c'è un modo meno macchinoso, ma in pratica fa il check sul mese della data login: se è uguale a 1, allora clausola where usata è il between 01/2005 e 01/2006
Se il mese è uguale a 2 viene presa come data between 02/2005 e 02/2006
Eccetera

Sinceramente non riesco bene a capire se ci possa essere un errore #__# Ma mi sto aggrappando alla speranza che sia giusta :P

alx_81 Profilo | Guru

Anche se la migliori come leggibilità o implementazione, credo che serva per forza un dominio dei mesi dell'anno.. sennò sei costretto a riferirti alle sole mensilità che hai nella tabella delle login..
Se a te interessano tutti i mesi, ti serve il dominio, viceversa puoi utilizzare l'elenco delle date di login.
Ciao!
Alx81 =)

Hamelin [FL] Profilo | Junior Member

Ho paura di non aver capito ^^"

alx_81 Profilo | Guru

Per avere l'elenco di tutti i mesi dell'anno, hai bisogno di creartelo..
semplice.. =)

Alx81 =)

Hamelin [FL] Profilo | Junior Member

Ahhh capisco :)

Sì in effetti visto che la clausola WHERE non supporta cicli, mi dovrò creare la lista a mano di tutti i mesi (l'ho fatto, ma non sono sicuro sul funzionamento)

Comunque, sul mio problema generale, ne ho postato la spiegazione, ad esempio, qui (oltre che su tutti i forum attendibili di SQL che sto trovando):

http://www.oracleportal.it/oipforum/thread.jspa?forumID=17&threadID=5815&tstart=0

Speriamo che qualcuno sappia rispondere, inizio a disperarmi :)
Ovviamente se trovo la soluzione ve la posto per completezza :P

alx_81 Profilo | Guru

In poche parole..
Tu devi sapere ogni mese quante login ha fatto l'utente (andando a ritroso per un anno).

io ricaverei la distinct di ogni datalogin per utente in questo modo:

SELECT distinct UserId,DataLogin
FROM Tabella

-------------------------
1 2005-01-01
1 2005-02-01
1 2005-03-01
2 2005-02-01
3 2005-02-01

poi farei un cursore, macchinoso eh.. s'intenda!! =), però sembra andare bene..

DECLARE @UserId int
DECLARE @DataLogin datetime

DECLARE DATE_LOGIN CURSOR FOR
SELECT distinct UserId,DataLogin
FROM Logins
OPEN DATE_LOGIN

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin

WHILE @@FETCH_STATUS = 0
BEGIN

SELECT @UserId,count(*),
CASE
WHEN count(*) <= 1 THEN 'Normale'
ELSE 'Super'
END
FROM Tabella
WHERE DataLogin >= DateAdd(dd,-365,DataLogin) AND DataLogin <= @DataLogin
AND UserId = @UserId

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin
END

CLOSE DATE_LOGIN
DEALLOCATE DATE_LOGIN


cambia il nome della tabella.. i campi dovrebbero essere uguali ai tuoi..
fammi sapere!

Se qualcuno mi comunica un modo per fare questo cursore con una query me lo faccia sapere.. perchè così è un pochino macchinoso!




Alx81 =)

alx_81 Profilo | Guru

Hai provato???
sono curioso!! =)
Alx81 =)

Hamelin [FL] Profilo | Junior Member

Poichè sto usando MS SQL Server Reporting Services, che io sappia non posso far interagire tra loro 2 query diverse. Cioè: non posso (che io sappia eh) creare una query che mi restituisca dei campi, e con un'altra query andare a interrogare quei campi.

Per fare questo al momento ho risolto creando delle view, che poi vado a interrogare con la query finale. Quindi quella che mi definisce il tipo di utente sarebbe una view.

E il guaio è che le view non possono avere dichiarazioni di variabili, quindi non posso seguire questa strada ^^"

alx_81 Profilo | Guru

fai una stored procedure..
Alx81 =)

Hamelin [FL] Profilo | Junior Member

Temo di non essere in grado :P

Cmq vado sul concreto e posto l'implementazione, che con tutti questi discorsi di esempi e teorie non ci capisco più niente io, mi immagino voi :P

Questa è l'architettura _funzionante con finestra fissa_

La prima view che definisce il *Tipo di Utente* (chiamata TipoUtente2005):

SELECT usrId,
CASE WHEN COUNT(usrId) > 150 THEN 'Super'
ELSE 'Normal' END
AS TipoUtente, YEAR([Data Login]) AS Anno
FROM dbo.TabellaLogin
WHERE ([Data Login] BETWEEN '2004-12-01' AND '2005-12-01')
GROUP BY usrId, YEAR([Data Login])
HAVING (YEAR([Data Login]) = 2005)

La seconda view che serve a tener conto del mese in cui ha fatto login (chiamata PerMese2005):

SELECT usrId, MONTH([Data Login]) AS Mese, YEAR([Data Login]) AS Anno
FROM dbo.TabellaLogin
WHERE ([Data Login] BETWEEN '2005-01-01' AND '2005-12-31')
GROUP BY usrId, MONTH([Data Login]), YEAR([Data Login])
HAVING (YEAR([Data Login]) = 2005)

La query finale che, dal join tra le due view, ricava quanti utenti per tipo han loggato ogni mese:

SELECT dbo.TipoUtente2005.TipoUtente, COUNT(dbo.PerMese2005.Mese) AS Conteggio, dbo.PerMese2005.Mese, dbo.PerMese2005.Anno
FROM dbo.PerMese2005 INNER JOIN dbo.TipoUtente2005 ON dbo.PerMese2005.usrId = dbo.TipoUtente2005.usrId
GROUP BY dbo.TipoUtente2005.TipoUtente, dbo.PerMese2005.Mese, dbo.PerMese2005.Anno
ORDER BY dbo.PerMese2005.Mese

*****************************************************

Ora, il problema è trasformare la "finestra" temporale _fissa_ della prima view (WHERE [Data Login] BETWEEN '2004-12-01' AND '2005-12-01') in una finestra temporale _variabile_ (non definire il tipo utente sul 2005, ma sui 12 mesi precedenti a ogni mese considerato). Per fare questo mi è stato suggerito di trasformare quel where in qualcosa tipo:

WHERE (MONTH([Data Login]) = 1) AND ([Data Login] BETWEEN '2004-01-01' AND '2005-01-01') OR
(MONTH([Data Login]) = 2) AND ([Data Login] BETWEEN '2004-02-01' AND '2005-02-01') OR
(MONTH([Data Login]) = 3) AND ([Data Login] BETWEEN '2004-03-01' AND '2005-03-01') OR
(...)

Cioè è una sorta di ciclo case... Se il mese della data login è uguale a 1, allora attiva il primo ramo e considera la data login tra gen2004 e gen2005, se il mese è uguale a 2, attiva il secondo ramo e considera la data login tra feb2004 e feb2005

Benchè macchinosissimo, anche una soluzione così mi andrebbe bene. Il fatto è che questa non sembra funzionare (oltre a non essere affatto sicuro sul raggruppamento per anno che ho fatto. Poco male comunque: non funziona nè col raggruppamento per anno nelle 2 query, nè senza)

Come faccio a dire che non funziona? Con la finestra variabile, quando si arriva a dicembre la finestra variabile coincide con la finestra fissa usata nella query funzionante, quindi a dicembre i dati dovrebbero coincidere. Invece non è così.

alx_81 Profilo | Guru

sostituisci il nome della tabella (per me si chiama Logins), le etichette (Normale e super, per intenderci) ed esegui questo sql..

------


CREATE PROCEDURE [dbo].[spGetUserLoginLevel]
AS


DECLARE @UserId int
DECLARE @DataLogin datetime

CREATE TABLE #TempTable
(UserId int, Counter int, UserType varchar(50))

DECLARE DATE_LOGIN CURSOR FOR
SELECT distinct UserId,DataLogin
FROM Logins
OPEN DATE_LOGIN

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin

WHILE @@FETCH_STATUS = 0
BEGIN

INSERT INTO #TempTable (UserId, Counter, UserType)
SELECT @UserId,count(*),
CASE
WHEN count(*) <= 1 THEN 'Normale'
ELSE 'Super'
END
FROM Logins
WHERE DataLogin >= DateAdd(dd,-365,DataLogin) AND DataLogin <= @DataLogin
AND UserId = @UserId

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin
END

SELECT * FROM #TempTable

DROP TABLE #TempTable

CLOSE DATE_LOGIN
DEALLOCATE DATE_LOGIN


-------



Con questo sql crei la stored procedure..
Nel Reporting service, invece che eseguire una select fai: exec spGetUserLoginLevel, che ti tornerà la tabella che ti serve.. Se non riesci a saltarci fuori, chiedi pure..
ciao!


Alx81 =)

Hamelin [FL] Profilo | Junior Member

Dunque dunque...

La stored procedure sono riuscito a crearla (già per lo sbattimento di averla fatta ti ringrazio infinitamente, purtroppo non sono capace di scriptarle), ora ho un problemuccio: poichè la tabella è di diverse migliaia di righe, purtroppo non sono ancora riuscito a vederne l'esecuzione finita ^^" Mi sa che è troppo pesante e si blocca

Quindi due piccole richieste (ho fatto un po' di prove ma si blocca sempre):

1) Come posso far sì di considerare, per prova, un piccolo periodo temporale anzichè tutta la tabella? Tipo mettergli da qualche parte un bel "WHERE DataLogin BETWEEN '2005-01-01' AND '2005-06-30'

2) Non sono sicuro di capire bene quando stiamo parlando della variabile DataLogin e del campo DataLogin della tabella originale (questo perchè in realtà il campo si chiama [Data Login], e non sono sicuro di averlo sostituito nei posti giusti)

3) (ancora da confermare): mi dà un errore di "Invalid object name #TempTable" (anche se tolgo il cancelletto)... ma forse questo è solo legato alla creazione di parametri che posso fare a mano... una volta che riuscirò a ottenere risultati senza far impalare il computer ti saprò dire :P

Chissà che non riusciamo finalmente a arrivare a una soluzione, nel frattempo comunque un grosso grazie

Hamelin [FL] Profilo | Junior Member

Sono riuscito a risolvere tutti i problemi che avevo richiesto nel post precedente :)

Lo script funziona e sembra proprio giusto, quindi ti voto e ti ringrazio :P

Piccolo problema: il database è composto da centinaia di migliaia di righe, e per periodi temporali superiori a due settimane il server non ci sta più dietro. E l'azienda vorrebbe fare le stime su un intero anno.

Però direi che questo non è un problema dello script: è proprio la richiesta che implica la scansione del database milioni di volte (per ogni utente e per ogni mese prendere i 12 mesi precedenti, vedere quante volte ha loggato l'utente, contarlo, fare questa conta _per tutti_ gli utenti e contare ogni tipo utente). Speravo che il server aziendale ci stesse dietro, ma purtroppo non è così

Dubito ci sia una soluzione più veloce, quindi non mi resta che cercare di spiegare ai capi quanto sia complicato per il DB


Grazie davvero per l'impegno, spero vi abbia dato qualcosa come l'ha dato a me (nonostante la non riuscita, qualcosa ho sicuramente imparato, tra cui l'uso di Stored Procedure)

alx_81 Profilo | Guru

Riesci a scaricare la tabella su txt e zipparla?
così guardo se riesco ad ottimizzare.. grazie per il voto =)
ciaoooo!
Alx81 =)

Hamelin [FL] Profilo | Junior Member

La tabella sono più di 350.000 righe di "userId" e "DataLogin" ^^"

Volendo ne puoi creare una a caso con date a caso, passarla mi sa ch esarebbe probitivo ^^"

Comunque la richiesta è pesantuccia, non so quanto sia ottimizzabile... inoltre non vorrei stressarti oltremisura e poi magari non si riesce a ottenere un risultato :)

alx_81 Profilo | Guru

E' pesante sì..
essendo inoltre un cursore..
puoi pensare di non fare la CASE, che è pesante.potresti pensare di farla applicativamente nel report.. già questo risparmia..
del resto non ho altre soluzioni =)
ok?
ciao!
Alx81 =)

Hamelin [FL] Profilo | Junior Member

Ho pensato a una soluzione alternativa: eseguo la tua SP mese per mese (aggiungendo quindi un campo per il mese) e vado a salvare tutti i dati in una tabella che quindi sarà del tipo

[UserId] [Count] [TipoUtente] [Mese]

E poi tutte le interrogazioni le potrò fare su questa tabella definitiva :) In questo modo non mi interessa la pesantezza, visto che faccio tante piccole interrogazioni anzichè una sola grande

Che ne pensi?

Unico "problema", ho fatto un po' di prove ma non ne sono venuto a capo: come modifico la tua SP in modo che non accodi dati a una tabella temporanea, ma a una definitiva in modo da salvarceli? (la tabella l'ho già creata, la SP dovrebbe quindi andare a fare un INSERT dei nuovi dati)

Grazie ancora

alx_81 Profilo | Guru

devi fare la create table (con cotrollo di esistenza della tabella, e in quel caso drop) prima del cursore.. in questo modo:

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TUA_TABELLA]') AND type in (N'U'))
DROP TABLE [TUA_TABELLA]

CREATE TABLE [TUA_TABELLA]
(
[Userid] [int] NOT NULL,
[Data] datetime NOT NULL,
[Tipo] [varchar](50) NOT NULL
)

sostituisci TUA_TABELLA col nome della tua tabella fisica e commenta la parte di creazione della temporanea.

poi nel cursore devi fare la insert delle variabili che leggi col FETCH NEXT nella TUA_TABELLA, commentando la insert nella temporanea.

Alla fine hai una tabella fisica piena..

io riempivo una temporanea.. basta che la sostituisci..

tutto qui..

in alternativa puoi creare la tabella col designer di sql server e poi troncarla (truncate table TUA_TABELLA) ed inserire i valori da capo. In tal caso devi eliminare la creazione della temporanea e fare solo la insert sulla TUA_TABELLA.. chiaro??

ciao!
Alx81 =)

Hamelin [FL] Profilo | Junior Member

Io ho creato la tabella TableType, e ho modificato la Stored Procedure nel seguente modo, sperando che questo mi inserisca i valori :P

LTER PROCEDURE dbo.spCreateTableType
AS

DECLARE @UserId int
DECLARE @DataLogin datetime

CREATE TABLE #TempTable
(UserId int, Counter int, UserType varchar(50), Mese int, Anno int)

DECLARE DATE_LOGIN CURSOR FOR
SELECT distinct usrId,[Data Login]
FROM TabellaLogin
WHERE [Data Login] BETWEEN '2005-01-01' AND '2005-01-31'
OPEN DATE_LOGIN

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin

WHILE @@FETCH_STATUS = 0
BEGIN

INSERT INTO [TableType] (UserId, Counter, UserType, Mese, Anno)
SELECT @UserId,count(usrId),
CASE
WHEN count(usrId) > 75 THEN 'Super'
ELSE 'Normal'
END,
1, 2005
FROM dbo.EVO_UsersHistory
WHERE [Data Login] BETWEEN '2004-10-01' AND '2004-12-31'
AND usrId = @UserId
GROUP BY usrId

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin
END

SELECT * FROM #TempTable

DROP TABLE #TempTable

CLOSE DATE_LOGIN
DEALLOCATE DATE_LOGIN


Ma mi sa che ho fatto una baggianata ^^" (io dovrei accodare i dati alla mia tabella, e non crearne una nuova ogni volta)

alx_81 Profilo | Guru

Personalmente utilizzerei la mia sp, per tutte le date, eseguendola prima di eseguire il report..
poi, quando hai la tabella fisica con meno righe, farei solo la query sulla tabella finale, a meno che non siano ancora troppe righe..
se la vuoi fare per mese, basta che lasci la mia logica, senza star lì a fare la tabella fisica, più lenta che la temporanea..
però metterei due parametri, l'anno ed il mese..

basta fare

alter procedure [proc_name]
(
@anno int,
@mese int
)
AS
...

e poi fai la where sullo year e sul month, invece che la between..
Alx81 =)

Hamelin [FL] Profilo | Junior Member

Non posso eseguirla prima di eseguire il report perchè ci mette un sacco di tempo ^^"

Quindi devo per forza attuare la soluzione - brutta, me ne rendo conto - di crearmi a mano una tabella permanente con i dati estratti dalla tua SP

Però, avendo quella scritta qui sopra, non riesco ad adattarla per far sì che appunto faccia la INSERT in una tabella fissa, se eseguo quello che ho scritto mi dà "Invalid Object Name TableType", presumo sia perchè sbaglio la sintassi generale della SP di insert...

alx_81 Profilo | Guru

se noti, la mia sp inserisce già, ma in una tabella temporanea..
sostituisci la tabella temporanea con la tua.. anche nella create in alto.. e nella drop alla fine..
io intendevo di eseguirla di notte.. ed il giorno dopo fare la query sulla tabella fissa.. in modo da eseguire i processi divisi e distinti..
Alx81 =)

Hamelin [FL] Profilo | Junior Member

Ma se faccio la drop alla fine non mi elimina la tabella che ho appena creato?

E avendo la tabella già creata quindi immagino basti eliminare la parte

CREATE TABLE #TempTable
(UserId int, Counter int, UserType varchar(50), Mese int, Anno int)

Però trasformando la SP come mi hai indicato, mi dà questo errore:

Running dbo."spCreateTableType".
Invalid object name 'TableType'.
No rows affected.
(0 row(s) returned)
@RETURN_VALUE =
Finished running dbo."spCreateTableType".


La SP l'ho appunto trasformata nella seguente:

ALTER PROCEDURE dbo.spCreateTableType
AS

DECLARE @UserId int
DECLARE @DataLogin datetime

DECLARE DATE_LOGIN CURSOR FOR
SELECT distinct usrId,[Data Login]
FROM TabellaLogin
WHERE [Data Login] BETWEEN '2005-01-01' AND '2005-01-31'
OPEN DATE_LOGIN

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin

WHILE @@FETCH_STATUS = 0
BEGIN

INSERT INTO [TableType] (UserId, Counter, UserType, Mese, Anno)
SELECT @UserId,count(usrId),
CASE
WHEN count(usrId) > 75 THEN 'Super'
ELSE 'Normal'
END,
1, 2005
FROM TabellaLogin
WHERE [Data Login] BETWEEN '2004-10-01' AND '2004-12-31'
AND usrId = @UserId
GROUP BY usrId

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin
END

SELECT * FROM [TableType]

CLOSE DATE_LOGIN
DEALLOCATE DATE_LOGIN

(scusami, mi sento davvero fesso ma non ci arrivo, mi devo trovare un manuale di come si scripano le SP...)

alx_81 Profilo | Guru

dovrebbe essere così..


ALTER PROCEDURE dbo.spCreateTableType
(
@from datetime,
@to datetime,
@from2 datetime,
@to2 datetime
)

AS

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[TableType]') AND type in (N'U'))
DROP TABLE [TableType]
CREATE [TableType]
(
UserId int,
Counter int,
UserType varchar(50),
Mese int,
Anno int
)

DECLARE @UserId int
DECLARE @DataLogin datetime

DECLARE DATE_LOGIN CURSOR FOR
SELECT distinct usrId,[Data Login]
FROM TabellaLogin
WHERE [Data Login] BETWEEN @from AND @to
OPEN DATE_LOGIN

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin

WHILE @@FETCH_STATUS = 0
BEGIN

INSERT INTO [TableType] (UserId, Counter, UserType, Mese, Anno)
SELECT @UserId,count(usrId),
CASE
WHEN count(usrId) > 75 THEN 'Super'
ELSE 'Normal'
END,
Month(@from), Year(@from)
FROM TabellaLogin
WHERE [Data Login] BETWEEN @from2 AND @to2
AND usrId = @UserId
GROUP BY usrId

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin
END

SELECT * FROM [TableType]

CLOSE DATE_LOGIN
DEALLOCATE DATE_LOGIN
Alx81 =)

Hamelin [FL] Profilo | Junior Member

Mi sa che la mia niubbaggine e babbeaggine mi impediscano di farmi capire, e mi chiedo come fai ad avere ancora la pazienza di starmi dietro :P

Ma se faccio IF EXISTS ... DROP TABLE non mi elimina la tabella?

Cioè: io dovrei tenere la tabella fissa, e accodare ogni volta i campi

Cioè eseguo la SP per gennaio, e la tabella si riempie con i dati di gennaio
La rieseguo per febbraio, e i dati di febbraio si accodano a quelli già inseriti a gennaoi
La rieseguo per marzo, e i dati di marzo si accodano a gennaio e febbraio


Con quell'IF invece non si distrugge la tabella ad ogni esecuzione?
E se tolgo il blocco if (drop, create) mi dà il famoso errore "Invalid Object Name TableType" :(

alx_81 Profilo | Guru

allora creala e basta con uno script o dalla console..

e tira via il drop create sulla sp..
l'errore te lo da perchè la tabella non esiste..

e comunque, crea un id (come primary key identity) e un bell'indice sulla data.. così diventa più veloce (tiene di più sul disco ma le prestazioni aumentano notevolmente).

ok?

Alx81 =)

Hamelin [FL] Profilo | Junior Member

Ri-edit

Sì confermo avevo detto una baggianata :P Ora mi dà risultati più congruenti

Premetto che va tutto bene e sembra proprio che sto riuscendo a fare quello che mi era stato chiesto.

Mi hanno dato una piccola modifica da fare: il count per la definizione utente non la dovrei fare sul numero di login, ma sul numero di login distinte per giorno (cioè se in un giorno faccio 1 o 100 login vale sempre per 1)

Ho modificato la SP in questo modo... avevo postato perchè dava risultati stranissimi, invece ho trovato l'errore e penso di averlo corretto in questo modo:

INSERT INTO [TableType] (UserId, Counter, UserType)
SELECT @UserId,count(distinct [Data Login]),
CASE
WHEN count(distinct [Data Login]) > 75 THEN 'Super'
WHEN count(distinct [Data Login]) > 50 AND count(distinct [Data Login]) <= 75 THEN 'Normal'
WHEN count(distinct [Data Login]) > 25 AND count(distinct [Data Login]) <= 50 THEN 'Occasionale'
WHEN count(distinct [Data Login]) > 1 AND count(distinct [Data Login]) <= 25 THEN 'Sleeper'
ELSE 'Sconosciuto'
END
FROM Tabella
WHERE [Data Login] BETWEEN '2005-09-01' AND '2005-11-30'
AND usrId = @UserId
GROUP BY usrId

Avevo il dubbio sul SELECT @UserId,count(distinct [Data Login]), ma sembra giusto quindi niente... se non è concettualmente sbagliato (non intendendomene di SP non so quando vanno usate le variabili e quando i campi della tabella) dovrei essere a posto :)

alx_81 Profilo | Guru

ci sta =)

cmq, io torno fra una settimana dall'irlanda.. quindi scusa se non rispondo per un po' =)
Alx81 =)

Hamelin [FL] Profilo | Junior Member

EDIT DEFINITIVO: scusate, ritiro il post, in realtà è giusto così com'è, non è un errore


Oggi ho fatto la definizione degli utenti anche diviso per giorno, oltre che per mese. Quindi ho 2 SP:

*****
MESE:
*****

DECLARE DATE_LOGIN CURSOR FOR
SELECT usrId,[Data Login]
FROM dbo.EVO_UsersHistory
WHERE [Data Login] BETWEEN @DataInizio AND @DataFine
OPEN DATE_LOGIN

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin

WHILE @@FETCH_STATUS = 0
BEGIN

INSERT INTO [TableType] (UserId, Counter, UserType, Mese, Anno)
SELECT @UserId,count(distinct [Data Login]),
CASE
WHEN count(distinct [Data Login]) > 48 THEN '5.Super'
WHEN count(distinct [Data Login]) > 12 AND count(distinct [Data Login]) <= 48 THEN '4.Normal'
ELSE '3.Occasionale'
END,
@Mese, @Anno
FROM dbo.EVO_UsersHistory
WHERE [Data Login] BETWEEN @DataInizioStima AND @DataFineStima
AND usrId = @UserId
GROUP BY usrId

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin
END


*******
GIORNO:
*******

DECLARE DATE_LOGIN CURSOR FOR
SELECT usrId,[Data Login]
FROM dbo.EVO_UsersHistory
WHERE [Data Login] BETWEEN @DataInizio AND @DataFine
OPEN DATE_LOGIN

[...]

INSERT INTO [TableTypeDay] (UserId, Counter, UserType, Giorno, Mese, Anno)
SELECT @UserId,count(distinct [Data Login]),
CASE
WHEN count(distinct [Data Login]) > 48 THEN '5.Super'
WHEN count(distinct [Data Login]) > 12 AND count(distinct [Data Login]) <= 48 THEN '4.Normal'
ELSE '3.Occasionale'
END,
@Giorno, @Mese, @Anno
FROM dbo.EVO_UsersHistory
WHERE [Data Login] BETWEEN @DataInizioStima AND @DataFineStima
AND usrId = @UserId
GROUP BY usrId

****

Ma c'è qualcosa che non va. Il numero di accessi mensili dovrebbe essere uguale alla somma del numero di accessi giornalieri di quel mese, no?
Invece il numero di accessi giornalieri è molto, molto maggiore (in un mese 500 accessi, e ogni giorno di quel mese circa 100 accessi)
Guardandoli separatamente i dati sembrano comunque giusti (pochi accessi a agosto, pochi accessi nei weekend eccetera), eppure c'è questa cosa della conta che non torna.

C'è forse qualcosa di sbagliato che non riesco a vedere?

Per quanto riguarda le variabili, puntualizzo che:
Ricordo che l'utente va definito nel seguente modo: Nel mese 1, l'utente è Super se nei 3 mesi precedenti a 1 (quindi 10, 11 e 12), ha fatto tot login.
Quindi:
@DataInizio e @DataFine (quellendel cursor) sono rispettivamente 01/01/06 e 31/01/06
@DataInizioStrima e @DataFineStima (quelle della select) sono rispettivamente 01/10/05 e 31/12/05

Nel giornaliero invere, nel giorno 1 mese 1, l'utente è super se nei 3 mesi precedenti il giorno 1 e mese 1 ha fatto tot login
Quindi:
@DataInizio e @DataFine sono il giorno 1, quindi 01/01/06 e 01/01/06
@DataInizioStima e @DataFineStima sono ancora 01/10/05 e 31/12/05 (con la differenza che nella stima precedente si spostano di mese in mese, qui di giorni in giorno)

Ho forse sbagliato qui e doveva esssere il contrario? Notate altri possibili errori?


***********
EDIT dopo un controllo:

Dunque, qualcosa che torna c'è, ed è quello che io pensavo fosse il numero di accessi mensili (mentre non torna il numero di utenti)

Forse semplicemente non ho ben capito cosa ritorna questa SP: mi ritorna una tabella del tipo

UserId ConteggioTreMesiPrecedenti TipoUtente Mese Anno

E ogni utente compare tante volte quante sono le volte che ha fatto login in quel mese
Io facevo una SELECT COUNT(DISTINCT UserId) per fare la tabella degli utenti mensili... ma a quel punto se un utente ha loggato in un mese 10 volte me lo contava una volta sola, giusto?
Invece dovrei fare anche nella query una count distinct sulla data... insomma, inizio a capire qualcosa, scusate, vedo di chiarirmi le idee

alx_81 Profilo | Guru

vorrei aiutarti =), visto che ti ho procurato parte del problema, ma temo di essermi perso =)
Alx81 =)

Hamelin [FL] Profilo | Junior Member

Ho notato solo ora, andando a ripescare questo thread, che mi avevi risposto... avevo fatto casini con gli EDIT, ma in realtà alla fine volevo dire che funzionava tutto ed ero a posto :)

Scusami se abuso di nuovo della tua disponibilità, ma mi è uscito un altro problema (ormai siamo agli sgoccioli però, fatte queste cose ho finito :P )

In pratica alla stored procedure perfettamente funzionante cui eravamo giunti:

****************************

ALTER PROCEDURE dbo.spCreateTableType
AS

DECLARE @UserId int
DECLARE @DataLogin datetime

DECLARE @DataInizio datetime
DECLARE @DataFine datetime
DECLARE @NuovoIscritto datetime
DECLARE @Mese int
DECLARE @Anno int
DECLARE @DataInizioStima datetime
DECLARE @DataFineStima datetime

SET @DataInizio = '2006-04-01'
SET @DataFine = '2006-04-30'
SET @NuovoIscritto = '01/03/2006'
SET @Mese = 4
SET @Anno = 2006
SET @DataInizioStima = '2006-01-01'
SET @DataFineStima = '2006-03-31'

DELETE FROM dbo.TableType
WHERE (Mese = @Mese) AND (Anno = @Anno)

DECLARE DATE_LOGIN CURSOR FOR
SELECT usrId,[Data Login]
FROM dbo.EVO_UsersHistory
WHERE [Data Login] BETWEEN @DataInizio AND @DataFine
OPEN DATE_LOGIN

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin

WHILE @@FETCH_STATUS = 0
BEGIN

INSERT INTO [TableType] (UserId, Counter, UserType, Mese, Anno, AreaCommerciale, AnnoNascita, GruppoTBP, GruppoD2B, GruppoSeniorAccount, GruppoTeleAccount)
SELECT @UserId,count(distinct dbo.EVO_UsersHistory.[Data Login]),
CASE
WHEN count(distinct dbo.EVO_UsersHistory.[Data Login]) > 0 AND dbo.EVO_Users.[Data iscrizione] > @NuovoIscritto THEN '1.Nuovo iscritto'
WHEN count(distinct dbo.EVO_UsersHistory.[Data Login]) > 48 THEN '5.Super'
WHEN count(distinct dbo.EVO_UsersHistory.[Data Login]) > 12 AND count(distinct dbo.EVO_UsersHistory.[Data Login]) <= 48 THEN '4.Normal'
WHEN count(distinct dbo.EVO_UsersHistory.[Data Login]) > 1 AND count(distinct dbo.EVO_UsersHistory.[Data Login]) <= 12 THEN '3.Occasionale'
WHEN count(distinct dbo.EVO_UsersHistory.[Data Login]) = 1 THEN '2.Sleeper'
END,
@Mese, @Anno, dbo.EVO_Users.[Area Commerciale], YEAR(dbo.EVO_Users.[Data di Nascita]), dbo.EVO_Users.[Gruppo TBP], dbo.EVO_Users.[Gruppo D2B], dbo.EVO_Users.[Gruppo Senior Account], dbo.EVO_Users.[Gruppo Tele Account]
FROM dbo.EVO_UsersHistory INNER JOIN dbo.EVO_Users ON dbo.EVO_UsersHistory.usrId = dbo.EVO_Users.usrId
WHERE [Data Login] BETWEEN @DataInizioStima AND @DataFineStima
AND dbo.EVO_UsersHistory.usrId = @UserId AND (dbo.EVO_Users.[Abilitato al punteggio] = 'Abilitato') AND (dbo.EVO_Users.[Abilitato a ESms] = 'Abilitato') AND (dbo.EVO_Users.[Data cessazione] IS NULL OR dbo.EVO_Users.[Data cessazione] > @DataFine)
GROUP BY dbo.EVO_UsersHistory.usrId, dbo.EVO_Users.[Data iscrizione], dbo.EVO_Users.[Area Commerciale], dbo.EVO_Users.[Data di Nascita], dbo.EVO_Users.[Gruppo TBP], dbo.EVO_Users.[Gruppo D2B], dbo.EVO_Users.[Gruppo Senior Account], dbo.EVO_Users.[Gruppo Tele Account]

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin
END

SELECT * FROM [TableType]

CLOSE DATE_LOGIN
DEALLOCATE DATE_LOGIN

**************************

Dovrei modificare la parte della CASE WHEN in modo da inserire una cosa del genere:

**************************

Select Q.UserID, Q.Conteggio,

(CASE WHEN Conteggio > 48 THEN '5.Super'
ELSE
CASE WHEN (Conteggio > 12 AND Conteggio <= 48)
AND (CDL15 > 2) AND (CDL3015 > 2) AND (CDL4530 >2)
THEN '4.Normal'
ELSE '3.Occasionale'
END
END) AS Tipo

FROM
(
SELECT UserId,count(distinct DataLogin) AS Conteggio,
(
select count(distinct DataLogin) FROM TabellaLogin
where UserID=T.UserID
and DataLogin BETWEEN DATEADD(day, -15, @DataInizio) AND @DataInizio
) as CDL15,

(
select count(distinct DataLogin) FROM TabellaLogin
where UserID=T.UserID
and DataLogin BETWEEN DATEADD(day, -30, @DataInizio) AND DATEADD(day, -15, @DataInizio)
) as CDL3015,

(
select count(distinct DataLogin) FROM TabellaLogin
where UserID=T.UserID
and DataLogin BETWEEN DATEADD(day, -45, @DataInizio) AND DATEADD(day, -30, @DataInizio)
) as CDL4530

FROM TabellaLogin T
WHERE T.DataLogin BETWEEN '01/01/2006' AND '01/04/2006'
group by UserID
) as q

**********************************

Io avevo provato a modificarla in questo modo, ma non funziona :(

**********************************

ALTER PROCEDURE dbo.spCreateTableType
AS

DECLARE @UserId int
DECLARE @DataLogin datetime

DECLARE @DataInizio datetime
DECLARE @DataFine datetime
DECLARE @NuovoIscritto datetime
DECLARE @Mese int
DECLARE @Anno int
DECLARE @DataInizioStima datetime
DECLARE @DataFineStima datetime

SET @DataInizio = '2006-04-01'
SET @DataFine = '2006-04-30'
SET @NuovoIscritto = '01/03/2006'
SET @Mese = 4
SET @Anno = 2006
SET @DataInizioStima = '2006-01-01'
SET @DataFineStima = '2006-03-31'

DELETE FROM dbo.TableType
WHERE (Mese = @Mese) AND (Anno = @Anno)

DECLARE DATE_LOGIN CURSOR FOR
SELECT usrId,[Data Login]
FROM dbo.EVO_UsersHistory
WHERE [Data Login] BETWEEN @DataInizio AND @DataFine
OPEN DATE_LOGIN

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin

WHILE @@FETCH_STATUS = 0
BEGIN

INSERT INTO [TableType] (UserId, Counter, UserType, Mese, Anno, AreaCommerciale, AnnoNascita, GruppoTBP, GruppoD2B, GruppoSeniorAccount, GruppoTeleAccount)
SELECT Q.UserId,Q.Conteggio,
CASE
WHEN Q.Conteggio > 0 AND Q.DataIscrizione > @NuovoIscritto THEN '1.Nuovo iscritto'
WHEN Q.Conteggio > 48 THEN '5.Super'
WHEN (Q.Conteggio > 12 AND Q.Conteggio <= 48) AND (CDL15 > 2) AND (CDL3015 > 2) AND (CDL4530 > 2) THEN '4.Normal'
WHEN Q.Conteggio > 1 AND Q.Conteggio <= 12 THEN '3.Occasionale'
WHEN Q.Conteggio = 1 THEN '2.Sleeper'
ELSE '3.Occasionale'
END,
@Mese, @Anno, Q.AC, Q.AnnoNascita, Q.TBP, Q.D2B, Q.Senior, Q.Tele

FROM
(
SELECT @UserId AS UserId,count(distinct dbo.EVO_UsersHistory.[Data Login]) AS Conteggio, dbo.EVO_Users.[Data iscrizione] AS DataIscrizione, dbo.EVO_Users.[Area Commerciale] AS AC, YEAR(dbo.EVO_Users.[Data di Nascita]) AS AnnoNascita, dbo.EVO_Users.[Gruppo TBP] AS TBP, dbo.EVO_Users.[Gruppo D2B] AS D2B, dbo.EVO_Users.[Gruppo Senior Account] AS Senior, dbo.EVO_Users.[Gruppo Tele Account] AS Tele,
(
select count(distinct dbo.EVO_UsersHistory.[Data Login]) FROM dbo.EVO_UsersHistory
where UserID=dbo.EVO_UsersHistory.UserID
and dbo.EVO_UsersHistory.[Data Login] BETWEEN DATEADD(day, -15, @DataInizio) AND @DataInizio
) as CDL15,

(
select count(distinct dbo.EVO_UsersHistory.[Data Login]) FROM dbo.EVO_UsersHistory
where UserID=dbo.EVO_UsersHistory.UserID
and dbo.EVO_UsersHistory.[Data Login] BETWEEN DATEADD(day, -30, @DataInizio) AND DATEADD(day, -15, @DataInizio)
) as CDL3015,

(
select count(distinct dbo.EVO_UsersHistory.[Data Login]) FROM dbo.EVO_UsersHistory.[Data Login]
where UserID=dbo.EVO_UsersHistory.UserID
and dbo.EVO_UsersHistory.[Data Login] BETWEEN DATEADD(day, -45, @DataInizio) AND DATEADD(day, -30, @DataInizio)
) as CDL4530

FROM dbo.EVO_UsersHistory INNER JOIN dbo.EVO_Users ON dbo.EVO_UsersHistory.usrId = dbo.EVO_Users.usrId
WHERE [Data Login] BETWEEN @DataInizioStima AND @DataFineStima
AND dbo.EVO_UsersHistory.usrId = @UserId AND (dbo.EVO_Users.[Abilitato al punteggio] = 'Abilitato') AND (dbo.EVO_Users.[Abilitato a ESms] = 'Abilitato') AND (dbo.EVO_Users.[Data cessazione] IS NULL OR dbo.EVO_Users.[Data cessazione] > @DataFine)
GROUP BY dbo.EVO_UsersHistory.usrId, dbo.EVO_Users.[Data iscrizione], dbo.EVO_Users.[Area Commerciale], dbo.EVO_Users.[Data di Nascita], dbo.EVO_Users.[Gruppo TBP], dbo.EVO_Users.[Gruppo D2B], dbo.EVO_Users.[Gruppo Senior Account], dbo.EVO_Users.[Gruppo Tele Account]

) AS Q

FETCH NEXT FROM DATE_LOGIN
INTO @UserId, @DataLogin
END

SELECT * FROM [TableType]

CLOSE DATE_LOGIN
DEALLOCATE DATE_LOGIN

*******************************

Mi rendo conto dell'estremo caos che ho generato, e capisco che potresti non capirci niente di tutto quello che ho postato ^^"

Se invece ci capissi qualcosa, avresti idea di come modificare il tutto per far funzionare quella logica? (in pratica dovrei definire l'utente "Normal" non solo in base al numero di login fatte, ma dovrebbe aver anche fatto 2 login negli ultimi 15 giorni, 2 login da 30 a 15 giorni fa, e 2 login da 45 a 30 giorni fa)

Grazie di nuovo per tutti gli aiuti che mi hai dato... quand'è che ti posso offrire qualcosa?

alx_81 Profilo | Guru

Non mi devi offrire nulla =) no problema..
il problema vero è che non seguendo più il tuo caso ho completamente scordato tutto.. e non riesco a saltarci fuori.. è diventata enorme..
l'unica cosa che mi viene da pensare è di utilizzare delle count in subquery, filtrate per utente..
di più non ti so dire..
scusami..


Alx81 =)

http://blogs.dotnethell.it/suxstellino

Hamelin [FL] Profilo | Junior Member

Sì è decisamente lunghissima, fatico a raccapezzarmici pure io

Comunque questo era solo un "di più", la Stored Procedure va benissimo anche così com'è, e ti ringrazio di nuovo perchè senza di te non ce l'avrei fatta :P

Mi hai fatto guadagnare un posto di lavoro :D

Grazie ancora, e saluti a tutti

alx_81 Profilo | Guru

un posto di lavoro??? =)
Alx81 =)

http://blogs.dotnethell.it/suxstellino

Hamelin [FL] Profilo | Junior Member

Sì sono tirocinante e se riuscivo a fare bene questa cosa mi assumevano :P

alx_81 Profilo | Guru

beh.. grande allora! =)
Alx81 =)

http://blogs.dotnethell.it/suxstellino
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5