Select arzigogolata..

venerdì 03 novembre 2006 - 16.49

bule Profilo | Junior Member

ciao a tutti averi da porvi la seguente domanda...relativamente alla formulzione di una query con sql 2005

dunque il data base ha due tabelle:
DettagliImpiegato: con le colonne che ci interessano: Nome e IDimpiegato
Info: con le colonne che ci interessano IDRiga,IDimpiegato,Dati

IDriga è chiave primaria di Info
IDImpiegato è chiave primaria di dettagliImpiegato in realzione con idImpiegato di Info

scopo della query era inizialmnte quello di ricavare la riga Dato relativamnte al più alto IDriga per ogni impiegato ( spero si sia capito...:-[) e quindi ho fatto così:

select d.Nome,i1.Dati
from info i1
join dettagliImpiegato d
on d.IdImpiegato = i1.Idimpiegato
where IdRiga=(select max(IdRiga) from info i2 where i1.idimpiegato=i2.idimpiegato)
order by d.Nome


con una nested query...

se ora volessi ottenere le stesse informazioni ma solo per gli impiegati che si chiamano per esempio Giiovanni e Marco come fare?

spero che si capisca il problema...

lbenaglia Profilo | Guru

>se ora volessi ottenere le stesse informazioni ma solo per gli
>impiegati che si chiamano per esempio Giiovanni e Marco come
>fare?

Ciao Bule,

io adotterei una soluzione simile a questa:

USE tempdb; GO CREATE TABLE dbo.DettagliImpiegato ( IDimpiegato int NOT NULL PRIMARY KEY, Nome varchar(10) NOT NULL ); CREATE TABLE dbo.Info ( IDRiga int NOT NULL PRIMARY KEY, IDimpiegato int NOT NULL, Dati varchar(20) NOT NULL, CONSTRAINT FK_Info_DettagliImpiegato FOREIGN KEY(IDimpiegato) REFERENCES dbo.DettagliImpiegato(IDimpiegato) ); GO INSERT dbo.DettagliImpiegato VALUES(1, 'Lorenzo'); INSERT dbo.DettagliImpiegato VALUES(2, 'Andrea'); INSERT dbo.DettagliImpiegato VALUES(3, 'Marcello'); INSERT dbo.DettagliImpiegato VALUES(4, 'Giovanni'); INSERT dbo.DettagliImpiegato VALUES(5, 'Marco'); INSERT dbo.Info VALUES(1, 1, 'Dato Lorenzo 1'); INSERT dbo.Info VALUES(2, 1, 'Dato Lorenzo 2'); INSERT dbo.Info VALUES(3, 4, 'Dato Giovanni 1'); INSERT dbo.Info VALUES(4, 4, 'Dato Giovanni 2'); INSERT dbo.Info VALUES(5, 4, 'Dato Giovanni 3'); INSERT dbo.Info VALUES(6, 3, 'Dato Marcello 1'); INSERT dbo.Info VALUES(7, 5, 'Dato Marco 1'); INSERT dbo.Info VALUES(8, 5, 'Dato Marco 2'); GO WITH CTE_MaxRiga AS ( SELECT IDimpiegato, MAX(IDRiga) AS IDRiga FROM dbo.Info GROUP BY IDimpiegato ) SELECT DI.Nome, I.Dati FROM dbo.DettagliImpiegato AS DI JOIN dbo.Info AS I ON DI.IDimpiegato = I.IDimpiegato JOIN CTE_MaxRiga AS CTE ON I.IDimpiegato = CTE.IDimpiegato AND I.IDRiga = CTE.IDRiga WHERE DI.Nome IN('Marco', 'Giovanni'); GO /* Output: Nome Dati ---------- -------------------- Giovanni Dato Giovanni 3 Marco Dato Marco 2 (2 row(s) affected) */ DROP TABLE dbo.Info, dbo.DettagliImpiegato;

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

bule Profilo | Junior Member

grazie mille ...soprattutto mi spiace per il temo che hai perso per scrivere tutte quele righe li...

adesso provo e poi ti dico...

lbenaglia Profilo | Guru

>grazie mille ...soprattutto mi spiace per il temo che hai perso
>per scrivere tutte quele righe li...

Ecco, la prossima volta se le scrivi tu mi fai un favore!
Mi raccomando, scrivile bene!!!!!!!!!

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

bule Profilo | Junior Member

ordunque ho provato...
non capivo bene cosa fosse il comando

with CTE_maxRiga as
(
...
)

e quindi ho usato una

SELECT IDimpiegato, MAX(IDRiga) AS IDRiga

into #temp

FROM dbo.Info
GROUP BY IDimpiegato

funziona e fà quello che deve fare però l'esecuzione è più lenta che non quando richiamo tutti gli impiegati...
giustamnente anche perchè dopo che sqlserver ha estratto cmq tutte le righe deve anche selezionare quelle richieste...

a stò punto devo capire se mi conviene comunque ritornare tutte le righe e filtrarle una volta ricevute
o perdere più tempo nella query...

l'ottimo sarebbe tentare di popolare la tabella CTE_maxRiga (#temp da me) solo con le righe relative ai nomi richiesti ...

ho provato così dunque:

prima della query che avevo usato per restituire tutte le righe relative al max idRiga per ogni impiegato..

select nome,idImpiegato
into #temp
from dettagliImpiegato
where nome in ('Giovanni','Marco')

poi la nested query va a leggere in #temp e non in tutto dettagliImpiegato

select d.Nome,i1.Dati
from info i1
join #temp d
on d.IdImpiegato = i1.Idimpiegato
where IdRiga=(select max(IdRiga) from info i2 where i1.idimpiegato=i2.idimpiegato)
order by d.Nome

drop table #temp

così è rapido ....
UNICO dubbio ho letto che usare le tabelle temporanee è una pratica non buona...non c'è un altro sistema per fare quello che ho fato ?

beh dai ho scritto un papiro io stavolta...ciao e grazie ancora

lbenaglia Profilo | Guru

>UNICO dubbio ho letto che usare le tabelle temporanee è una
>pratica non buona...non c'è un altro sistema per fare quello
>che ho fato ?

Il sistema che ti ho proposto non utilizza tabelle temporanee!
Per quale motivo non lo vuoi adottare?
Se non sai cosa sono le CTE, consulta i Books Online:

"WITH common_table_expression (Transact-SQL)"
http://msdn2.microsoft.com/it-it/library/ms175972.aspx

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

bule Profilo | Junior Member

adesso sicuramente guardo cosa sono le CTE...

ma il tuo sistema impiega più tempo a eseguire rispetto alla mia seconda query che ho scritto, quella usando le tabelle temporanee...

lbenaglia Profilo | Guru

>ma il tuo sistema impiega più tempo a eseguire rispetto alla
>mia seconda query che ho scritto, quella usando le tabelle temporanee...

L'hai provato?
Hai indicizzato opportunamente le tabelle?
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

bule Profilo | Junior Member

si si ho provato...

c'è un indice non clustered univoco su idRiga per entrambe le query provate adesso uso una CTE e ti dico...

comunque il probema secondo me è quello che ho scritto nel tuo modo prima trovo tutte le righe con max valore per impiegato e poi visualizzo solo quelle che mi interessano, cioè quelle filtarte dalla where Nome in (...)

con quella che ho provato io seleziono solo la max riga degli impiegati che voglio e quindi taglio la ricerca all'inizio ...

penso sia così..ma potrei anche sbagliarmi

però adesso provo a usare la CTE e vedo che succede..

lbenaglia Profilo | Guru

>c'è un indice non clustered univoco su idRiga per entrambe le
>query provate adesso uso una CTE e ti dico...

Prova a definire i seguenti indici:

Tabella dbo.Info
Definisci un indice clustered su IDimpiegato ed un indice non clustered sulle colonne IDimpiegato, IDRiga

Tabella dbo.DettagliImpiegato
Definisci un indice clustered su IDimpiegato

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

bule Profilo | Junior Member

non posso mettere un indice clustered su idRiga perchè lìho già sprecato su un altra colonna...la tabella del database che uso è più grande di quella che ho postato e l'indice clusterede mi serviva su un altra colonna..

comunque ho ritestato entrambe le query e adesso si equivalgono , si vede che la tua era più penalizzata dall'uso di una tabella

temporanea si equivalgono sia come tempo di esecuzione si come letture logiche sulla tabella info che è quella più grossa...(letture viste con --SET STATISTICS IO ON)..

questo però mi sembra un pò strano dato che come ti ho detto pensavo che il mio metodo tagliasse all'inizo un pò di accessi alla tabella info ..saranno i misteri di sql server..per lo meno misteri per me che lo stò usando da circa un mesetto

grazie mille...

lbenaglia Profilo | Guru

>non posso mettere un indice clustered su idRiga perchè lìho già
>sprecato su un altra colonna...
Beh, toglilo!

>la tabella del database che uso
>è più grande di quella che ho postato e l'indice clusterede mi
>serviva su un altra colonna..
Sicuro? Come fai a dirlo?

>comunque ho ritestato entrambe le query e adesso si equivalgono
>, si vede che la tua era più penalizzata dall'uso di una tabella
>
>temporanea
??!?! LA MIA NON USA ALCUNA TABELLA TEMPORANEA!!!

>questo però mi sembra un pò strano dato che come ti ho detto
>pensavo che il mio metodo tagliasse all'inizo un pò di accessi
>alla tabella info ..saranno i misteri di sql server..per lo meno
>misteri per me che lo stò usando da circa un mesetto
L'unico modo per capire come l'optimizer decide di risolvere una query è quello di analizzare il piano di esecuzione. Sui Books Online troverai tutte le informazioni necessarie per interpretarlo.

>grazie mille...
Prego.

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

bule Profilo | Junior Member

>comunque ho ritestato entrambe le query e adesso si equivalgono
>, si vede che la tua era più penalizzata dall'uso di una tabella
>
>temporanea
??!?! LA MIA NON USA ALCUNA TABELLA TEMPORANEA!!!

...l'avevo modificata io perch+ non capivo cosa eran le CTE...

l'indice clustered mi serve sull'altra colonna perchè faccio molte query che hanno quella come argomento del where....però magari provo a fare un pò di cambi di indici e vedo che succede

gracias mille

lbenaglia Profilo | Guru

>l'indice clustered mi serve sull'altra colonna perchè faccio
>molte query che hanno quella come argomento del where....

Allora ti serve ben poco
Se non utilizzi la clausola BETWEEN, un indice non clustered sarà altrettanto efficiente.
Leggi attentamente questo vecchio post:
http://groups.google.it/group/microsoft.public.it.sql/msg/a8693e050bb3bc09

>magari provo a fare un pò di cambi di indici e vedo che succede
Prova, prova

>gracias mille
Prego.

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

bule Profilo | Junior Member

in realtà uso prprio la clausola beetween in cun campo dateTime sul quale appunto ho l'indice clustered...

where t.Tempo between '19/09/2006' and '19/09/2006 23:59:59.000'

molte query son proprio fatte così... i giorni cambiano in quanto sono come paramtri di una store procedure...

lbenaglia Profilo | Guru

>in realtà uso prprio la clausola beetween in cun campo dateTime
>sul quale appunto ho l'indice clustered...
>
>where t.Tempo between '19/09/2006' and '19/09/2006 23:59:59.000'

Allora lascialo.
Ricordati di specificare le date in formato ISO 'YYYYMMDD' NON in formato italiano ed inoltre occhio ai millisecondi dell'estremo superiore (997 non 000 altrimenti rischi di perdere 1 secondo di dati).

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

bule Profilo | Junior Member

è vero...scusa ho fatto copia incolla di un pezzo di una clausola vecchia...per quanto rigurda l'estero superiore

ma scusa non va bene usare la data italiana? non ho mai avuto problemi fin qui ...ma adesso mi metti un dubbio..

scusa se ti disturbo ancora...

lbenaglia Profilo | Guru

>ma scusa non va bene usare la data italiana?
No. Se ti funziona probabilmente la login che stai utilizzando per connetterti all'istanza ha impostato Italiano come lingua di default, se provi a mettere una qualsiasi altra lingua otterrai un bell'errore.
Per svincolarti completamente dal formato data/ora, utilizza SEMPRE il formato ANSI ISO 'YYYYMMDD'.

Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org
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