Newsgroup: it.comp.lang.visual-basic
Titolo: Io proprio non ci riesco [sql]

Nonostante abbia passato le ultime tre notti insonni a scrivere query sql, 
ancora non riesco a fare una importante operazione su un db.... Spero che 
qualche anima pia possa aiutarmi
Ecco il mio db
Nome tabella: TOTALONE
Numero, Servizio, Mese
0001,Servizio1,Gennaio05
0001,Servizio1,Febbraio05
0001,Servizio2,Gennaio05
0002,Servizio1,Marzo05
0003,Servizio1,Aprile05
0003,Servizio1,Maggio05
Da questa tabella ho bisogno di tirarmi fuori un dato:
1) Quanti utenti (numero) si sono registrati ad ogni servizio per x mesi 
CONSECUTIVI.
Per spiegarmi meglio vi dico che il risultato dovrebbe essere, con i dati 
sopra esposti:
Un solo mese:
Servizio1 -> 1 utente (0002)
Servizio2 -> 1 utente (0002)
Due mesi:
Servizio1 -> 2 utenti (0001 e 003)
Servizio2 -> nessun utente
e così via fino a 12 mesi consecutivi....
Cioè significa che per "consecutivi" intendo consecutivi di calendario.
Non sapendo davvero come fare a chiedere questa "consecutività" tramite una 
query mi sono detto: ok, faccio tante query quante sono le consecutività 
(ossia una query per Gennaio-Febbraio, una per Febbraio-Marzo e così via, 
poi una per Gennaio-Febbraio-Marzo, una per Febbraio-Marzo-Aprile e così 
via....fino ad avere 12 mesi di fila)
Ho provato quindi a fare un count distinct sul campo Numero (si perchè lo 
stesso numero può avere il medesimo servizio anche più volte nello stesso 
mese, ma a me serve contarlo una sola volta), mettendo come clausola, ad 
esempio, where Mese='Gennaio05' and Mese='Febbraio05' ma mi vengono fuori 0 
record....In realtà in questo caso penso sia un errore della clausola where 
perchè anche se faccio un semplice Select * from Totalone where 
Mese='Gennaio05' and Mese='Febbraio05'  mi vengono fuori 0 record. Dove 
sbaglio?
Inoltre, avete qualche soluzione/query migliore da consigliarmi
Spero in un vostro gentilissimo aiuto
Ciao a tutti
R 


Dimenticavo una cosa....
Nel caso in cui la tabella sia così composta
Numero, Servizio, Mese
0001,Servizio1,Gennaio05
0001,Servizio1,Febbraio05
0001,Servizio2,Gennaio05
0002,Servizio1,Marzo05
0003,Servizio1,Aprile05
0003,Servizio1,Maggio05
0001,Servizio1,Marzo05
0001,Servizio1,Aprile05
0001,Servizio1,Maggio05
quando vado a fare il conteggio per il servizio1 mi deve dare come risultato
1 utente nei 2 mesi(0003 Aprile e Maggio) e 1 utente nei 3 mesi (0001 Marzo
Aprile e Maggio) cioè deve prendere il MASSIMO numero di mesi consecutivi... 


Dimenticavo una cosa....
Nel caso in cui la tabella sia così composta
Numero, Servizio, Mese
0001,Servizio1,Gennaio05
0001,Servizio1,Febbraio05
0001,Servizio2,Gennaio05
0002,Servizio1,Marzo05
0003,Servizio1,Aprile05
0003,Servizio1,Maggio05


 sbaglio?
Ovvio che ti dia 0 record, perchè il campo mese, per ciascun record,
puù avere solo un valore e non può essere contemporaneamente uguale a
"Gennaio05" e "Febbraio05". Non trovi ? :-D

> 0003,Servizio1,Maggio05
Tanto per cominciare cercherei, giocando con le funzioni di stringa, di 
trasformare il campo mese in un numero progressivo intero, per esempio se il 
tuo sistema è entrato in funzione il 1/1/2003 vorrei
Gennaio03->1
Febbraio03->2
 ...
Gennaio04->13
Febbraio04->14
ecc.
Diciamo che questo campo calcolato lo chiami Mese2 e ti crei una vista 
(TOTALONE2) che contiene Mese2 e già che ci sei ti toglie i duplicati. 
Questa trasformazione è molto semplice, basta estrarre l'anno, sottrargli 
03, moltiplicare per 12, poi aggiungere il valore numerico del mese 
(generato con una iif o con una CASE se sei in SQL server). Insomma con un 
mix di iif, mid e val te la cavi.... Certo che se tu potessi salvare il mese 
come data sarebbe anche meglio...
A questo punto il gioco è quasi fatto:
Select Numero,Servizio,Count(Mese2) As Consecutivi,Count(Mese2) - 
(Max(Mese2)-Min(Mese2)+1) As Test  from TOTALONE2 group by Numero, Servizio 
having Count(Mese2) - (Max(Mese2)-Min(Mese2)+1) =0 and Count(Mese2)>1
Cioè l'idea è che se la differenza fra max e min  è uguale al conteggio 
(meno 1) dei record, essendo questi distinti saranno necessariamente 
consecutivi. "Quasi", perché così non riesci a separare più gruppi di mesi 
consecutivi per lo stesso servizio/utente, ma prendi in considerazione tutti 
i mesi in una botta sola -o sono tutti consecutivi o no.
Applicando apposite condizioni su Mese2 in modo da esaminare solo 
determinati intervalli di record, puoi esaminare meglio il tuo insieme.Se 
per esempio ti crei una tabella con gli interi da 1 a 12 (INTERI12) e una 
con gli interi da 1 a max(Mese2) (INTERI_MAX), e le metti entrambe in cross 
join con TOTALONE2, ottieni 12*max(mesi) copie di ogni record ciascuno con 
una diversa coppia di valori il primo da 1 a 12 e il secondo da 1 a 
MAX(mesi).
Select Numero
,Servizio
,Count(Mese2) As Consecutivi
,Count(Mese2) - (Max(Mese2)-Min(Mese2)+1) As Test
,INTERI_MAX.N, INTERI12.N
from TOTALONE2
 cross join INTERI12
 cross join INTERI_MAX
where
  Mese2>=INTERI_MAX.N
 and Mese2<=INTERI_MAX.N +  INTERI12.N
group by
 Numero
, Servizio
, INTERI_MAX.N
, INTERI12.N
 having
 Count(Mese2) - (Max(Mese2)-Min(Mese2)+1) =0
 and Count(Mese2)>1,
Così ottieni la stessa query di cui sopra, ma ricalcolata a partire da 
ciascun mese e per tutte le durate da 1 a 12.
La memorizzi come vista, la filtri per eliminare i conteggi più bassi (cioè 
la aggreghi un'altra volta prendendo il "Consecutivi" più alto per ciascun 
utente/servizio), e il gioco è fatto!
Non le ho testate, sono andato "a sentimento", quindi perdonami eventuali 
imperfezioni...l'importante è il principio di funzionamento.
Ciao
Elef

 cross join ...
Potresti anche creati delle viste senza inserire altre tabelle...
create view INTERI12 as
select 1 as N
union select 2 as N
union select 3 as N
union select 4 as N
...
union select 12 as N
go
poi la metti in cross join con se stessa un paio di volte (o quanto basta) e 
la filtri per creare l'altra:
create view INTERI_MAX as
select (N1.N-1)*144+(N2.N-1)*12 +N3.N
from INTERI12 as N1 cross join  INTERI12 as N2 cross join  INTERI12 as N3
where (N1.N-1)*144+(N2.N-1)*12 +N3.N < (select max(Mese2) FROM TOTALONE2)
go
Ciao
Elef 

 sbaglio?
Forse dovresti utilizzare "OR" invece di "AND" (come potrebbe un record 
avere MESE uguale sia a Genn che a Febb?????), se utilizzi le date in modo 
corretto (come ti hanno gia' suggerito) forse la clausola "BETWEEN" fa al 
caso tuo.
A mio modestissimo parere in SQL puoi farlo solo utilizzando i puntatori, 
probabilmente e' piu' semplice in VB: apri il recordset con questa query
SELECT COUNT(*) AS Cont, cliente, servizio, data
FROM Totalone
GROUP BY cliente, servizio, data
HAVING COUNT(*) > 2 --cosi' verranno scartati tutti i clienti che hanno un 
solo "servizio"
ORDER BY cliente, servizio, data
Durante il ciclo sui record controlli ogni volta rispetto al record 
precedente se:
a) e' cambiato il cliente
b) e' cambiato il servizio
c) la data e' contigua (quello che sembrta ti serva)
In bocca al lupo
-- 
.o0-- I.d.N. alias JYD --0o.
Please Cut "-some trees-" for reply 

 Mese=Cast(Left(Rtrim([mese]),Strlen(Rtrim([mese]))-2) As Numeric(18,0)),
Ehm...
ovviamente pensavo a Convert, ma qualcosa mi ha fatto scrivere Cast...
Ciao
Alberto
-- 
"Se viriamo, viriamo viriamo viriamo;
Se andiamo dritti, viriamo"
(Cit. "il tattico")

 CONSECUTIVI.
Partiamo dicendo che il campo mese, fatto così, è una porcheria immane.
Occorre quindi, innanzitutto, scorporare mese e anno in due campi 
numerici distinti, e quindi ottenere un numero che indichi, ad esempio, 
i mesi passati da una data di riferimento (e spero vivamente che tu non 
abbia niente prima del 2000...).
Una prima sottoquery, quindi potrebbe essere:
Select A.Numero, A.Servizio,
Mese_Totale=A.Anno * 12.0 + A.Mese
From (
Select Numero, Servizio,
Mese=Cast(Left(Rtrim([mese]),Strlen(Rtrim([mese]))-2) As 
Numeric(18,0)),
Anno=Cast(Right(Rtrim([mese]),2) as Numeric(18,0)
From Tabella ) As A
E questa sottoquery diventa la tabella di origine di tutto.
A seguire, hai due possibilità.
La prima, sicuramente la più semplice, è quella di aprire un cursore 
sulla tabella così ottenuta, ordinata per Numero, Servizio, 
Mese_Totale, e scorrerlo con dei Fetch. Non è performante al massimo, 
ma diventa molto lineare e pulito, e fino a un paio di milioni di 
record rimani su performanc eaccettabili.
La seconda, più complessa ma più affascinante, è quella di individuare 
le discontinutià. Cioè, anzichè cercare di conteggiare i mesi contigui, 
individui i mesi dove un cliente passa da iscritto a non iscritto o 
viceversa. Poi, cerchi la massima differenza fra due occorrenze 
consecutive.
Chiamando TAB_B il codice di cui sopra, avresti una cosa del tipo:
SELECT C.*,
SENSO='FINE_ISCRIZIONE'
FROM TAB_B AS C
LEFT OUTER JOIN
TAB_B AS D
ON C.NUMERO=D.NUMERO
AND C.SERVIZIO=D.SERVIZIO
AND C.MESE_TOTALE=D.MESE_TOTALE-1
WHERE D.SERVIZIO IS NULL
UNION
SELECT C.*,
SENSO='INIZ_ISCRIZIONE'
FROM TAB_B AS C
LEFT OUTER JOIN
TAB_B AS D
ON C.NUMERO=D.NUMERO
AND C.SERVIZIO=D.SERVIZIO
AND C.MESE_TOTALE=D.MESE_TOTALE+1
WHERE D.SERVIZIO IS NULL
Dal risultato di questa query, puoi iniziare a ragionare con le 
differenze (prestando attenzione a filtrare bene di fare le differenze 
solo sui contigui).
Non è impossibile, solo che ci vuole pazienza.
Se sfrutti le tabelle #, e ti fai stampare i risultati nei vari 
passaggi, ti si illumina un mondo.


 
scusa eh, ma con questo acronimo 
 sembra che tu abbia gia' il destino segnato in maniera indelebile!