Newsgroup: it.comp.lang.visual-basic
Titolo: [OT] Stringa SQL un po' complicata (magari, invece, è una caXXata!)

Scusate l'OT e il fatto che non ho cercato a lungo nei vecchi post, però ho
un problema per il quale spero qualcuno mi suggerisca una soluzione a tempo
di record! Avete presente l'acqua alla gola? Ecco, arriva un po' più in su!
Ho una tabella in cui registro il costo di acquisto di alcuni materiali e .
Ogni registrazione viene mantenuta, quindi non sovrascrivo i record relativi
ad acquisti precedenti dello stesso articolo.
Codice    Data            Costo
00001    20010101    150,00
00002    20010101    180,00
00001    20010525    145,00
00003    20010630    135,00
Vorrei ottenere una tabella che mostri solo il record più recente.
Codice    Data            Costo
00001    20010525    145,00
00002    20010101    180,00
00003    20010630    135,00
Sto impazzendo a furia di provare stringhe SQL perché non riesco a ottenere
solo il record più recente!
Per favore, datemi una mano! Scusate l'irruzione e, di nuovo, per l'OT e
grazie mille sin d'ora!
Alex
--
Private replays to 
not.to....@geocities.com
Remove "
not.to
."!!

 Vorrei ottenere una tabella che mostri solo il record più recente.
forse
SELECT TOP 1 * FROM NomeTabella ORDER BY Data DESC
?
--
Faber

 ?
Ma questo restituisce solo UN record... Io, invece, ho bisogno di tutti i
record più recenti per ogni singolo codice.
Grazie comunque.


--------------------------
MAO
web...@libero.it
ICQ: 50543286 webmind
-------------------------

 )
a me seleziona un record in più con i campi tutti vuoti (o impostati a zero)


dovrebbe funzionare:
SELECT *
FROM Tabella1
where Tabella1.codice & Tabella1.data in
(SELECT Tabella1.codice & Max(Tabella1.data) 
FROM Tabella1
GROUP BY Tabella1.codice);
ciao
maurizio

Prova questa... l'ho testata con Access XP
_____________________________
select tabella1.codice, tabella1.data, tabella1.costo from
tabella1
inner join
(
  select codice, max(data) as data1 from tabella1
  where codice in (SELECT distinct codice FROM Tabella1)
  group by codice
) as q1
on (tabella1.codice=q1.codice and tabella1.data=q1.data1);

Come non detto...

 ha scritto nel messaggio
news:3c68416d...@news.tin.it...

C'è un errore, però non riesco a correggerlo. Questo è: "E' stata scritta
una sottoquery che può restituire più campi senza utilizzare la parola
riservata EXISTS nella proposizione FROM della query principale. Modificare
l'istruzione SELECT nella sottoquery per richiedere soltanto un campo."

 ha scritto nel messaggio
news:3c683f36...@powernews.libero.it...

Sta lavorando su un db di 46.000 record... A spanne dovrebbe andare, però
una cosa analoga l'avevo già provata ed era di una lentezza esasperante!
Intanto grazie!


qual'è l'ambiente?
prima di scrivere ho provato su access 97 (e ho adattato quello che di
solito uso su DB2/AS400) e funzionava ...
ciao
maurizio

 maurizio
Access 2000.
Non mi reggo piů in piedi, vado a letto!
Ciao!
Alex

 00003    20010630    135,00
Eccola:
SELECT tabella.codice, tabella.descrizione, tabella.data,tabella.costo
FROM tabella
WHERE tabella.data in
(select max(tabella.data)  from tabella group by codice)

 (select max(tabella.data)  from tabella group by codice)
Ovviamente occorre un ID al posto della data, visto che la data non è
univoca (se hai comprato lo stesso articolo due volte nello stesso giorno,
la query postata ti torna due record).
Siccome i database seri (non so Access, ma infatti non lo mettevo fra quelli
seri :-)))) non sono posizionali, ossia non gestiscono i record nell'ordine
in cui sono inseriti, se non hai previsto un progressivo o una altra chiave
più precisa, non c'è modo.
Se utilizzi, oltre alla data, anche l'ora con i secondi, hai una buona
probabilità che la query di cui sopra funzioni. Ma attenzione, non ne hai la
certezza, visto che comunque due utenti potrebbero inserire due acquisti
dello stesso materiale in istanti molto vicini, al di sotto della precisione
del tuo campo data.
Se hai una chiave univoca, sei quasi a posto. 'Quasi' nel senso che ti torna
un record solo, ma se non hai anche un progressivo da utilizzare nel max(),
può arrivare indifferentemente uno dei due
Ciao
Alberto

 00003    20010630    135,00
Ringrazio tutti quanti mi hanno dato una mano. Nella speranza che in futuro
possa servire a qualcuno, pubblico la mia soluzione basata su datashaping.
Le soluzioni che mi avete proposto bene o male fanno tutte il lavoro. Il
problema, però, diventano le prestazioni. In poche parole, avendo 46.000
record (che diventano 120.000 visto che ci sono di mezzo dei join su tabelle
di quelle dimensioni), se per ogni record devo fare una SELECT i tempi
diventano dell'ordine delle svariate ore su un pc che abbia una sua copia
del db (sul server sarà poco meno, però aumentano le bestemmie degli
utenti).
Complessivamente (quindi oltre a quello che ho spiegato che dovevo ottenere
nel mio post originale) dovevo associare l'ultimo costo di un articolo a una
tabella contenente l'anagrafica di tutti gli articoli trattati dalla mia
azienda.
La tabella di partenza, [Anagrafica articoli], è strutturata così:
Codice, Descrizione, ...altri campi...
Innanzitutto ho creato una nuova tabella  con l'anagrafica dove il codice è
la chiave primaria.
La tabella reale (la chiamerò [Anagrafica finale]) è, una volta
semplificata, più o meno fatta così e corrisponde a quella che avevo
spiegato nel mio primo post:
Codice, .....vari campi (tra cui Descrizione)......., DataUltimoAcquisto,
UltimoCosto
La tabella contenente l'ultimo costo è, invece, proprio come quella del mio
esempio, che qui chiamerò [Ultimo costo]:
 Codice    Data            Costo
 00001    20010101    150,00
 00002    20010101    180,00
 00001    20010525    145,00
 00003    20010630    135,00
Tenete presente che non necessariamente esiste un ultimo acquisto (ci sono
articoli che si trovavano nel magazzino prima che fosse introdotto il nuovo
server e, soprattutto, il nuovo gestionale), e in tal caso si presentano due
possibilità (per entrambe di default DataUltimoAcquisto=0 e UltimoCosto=0):
l'articolo è codificato ma non è mai stato acquistato, oppure l'articolo è
codificato, è stato comprato prima che entrasse in funzione il nuovo server
e quindi, se esiste, si ha solo una valorizzazione iniziale della giacenza
di magazzino (vuol dire che per articoli con giacenza nulla nel momento in
cui è stato messo in funzione il nuovo server non posso ricavare
l'informazione).
Mi creo quindi una tabella ausiliaria, [Costo iniziale], in cui, per tutti
gli articoli con giacenza iniziale <> 0 ho il nuovo campo
Codice, CostoIniziale
Il criterio è: dove non esiste un ultimo costo, utilizzo, se disponibile, il
valore iniziale.
Armatomi di VB6, ecco quindi la mia soluzione (spero, modificandola per
pubblicarla, di non commettere errori).
Nel Form_Load apro una connessione al db, nel mio caso cnAS400
Private Sub cmdCommand1_Click()
    Dim rsSource As New ADODB.RecordSet
    Dim rsTarget As New ADODB.RecordSet
    Dim subRs As Recordset
    Dim subRsCostoIniz As Recordset
    Dim x As Integer
    If cnAS400.State = 1 Then
        cnAS400.Close
    End If
    cnAS400.Open
    If cn.State = 1 Then
        cn.Close
    End If
    cn.Open
    SqlSource = ""
    SqlSource = "SHAPE {SELECT * FROM [Anagrafica articoli] ORDER BY Codice}
APPEND ({SELECT * FROM [Ultimo costo] ORDER BY Codice} RELATE Codice TO
Codice) AS UCosto, ({SELECT * FROM [Costo iniziale] ORDER BY Codice} RELATE
Codice TO Codice) AS CostoIniz"
    Set rsSource.ActiveConnection = cnAS400
    rsSource.Open SqlSource, cnAS400
    SqlTarget = ""
    SqlTarget = "SELECT * FROM [Anagrafica articoli finale];"
    Set rsTarget.ActiveConnection = cn
    rsTarget.Open SqlTarget, cn, adOpenKeyset, adLockOptimistic
    With rsSource
        Do While Not .EOF
            rsTarget.AddNew
            rsTarget.Fields("Codice").Value = .Fields("Codice").Value
            rsTarget.Fields("Descrizione").Value =
.Fields("Descrizione").Value
            ...
            eccetera
            ...
            Set subRs = rsSource.Fields("UCosto").Value
            Set subRsCostoIniz = rsSource.Fields("CostoIniz").Value
            'Se non c'è l'ultimo costo
            If subRs.EOF Then
                If subRsCostoIniz.EOF Then
                    'e nemmeno il costo iniziale => scrivi un valore di
default
                    rsTarget.Fields("DataUltimoAcquisto").Value = 0
                    rsTarget.Fields("UltimoCosto").Value = 0
                Else
                    'se c'è un costo iniziale => scrivilo
                    rsTarget.Fields("DataUltimoCarico").Value = 0
                    rsTarget.Fields("UltimoCosto").Value =
subRsCostoIniz.Fields(1).Value
                End If
            End If
            'Il ciclo Do viene eseguito come se fosse nell'Else dell'If
precedente,
            'cioè solo se subRs.EOF è Falso
            Do Until subRs.EOF
                If IsNull(rsTarget.Fields("UltimoCosto").Value) And
subRs.Fields(2).Value = 0 Then
                    'Metto il valore iniziale se il campo è nullo o zero
                    rsTarget.Fields("DataUltimoAcquisto").Value = 0
                    If subRsCostoIniz.EOF Then
                        rsTarget.Fields("UltimoCosto").Value = 0
                    Else
                        rsTarget.Fields("UltimoCosto").Value =
subRsCostoIniz.Fields(1).Value
                    End If
                Else
                    If IsNull(rsTarget.Fields("DataUltimoAcquisto").Value)
Or subRs.Fields(1) > rsTarget.Fields("DataUltimoAcquisto").Value Then
                        rsTarget.Fields("DataUltimoAcquisto").Value =
subRs.Fields(1).Value
                        rsTarget.Fields("UltimoCosto").Value =
subRs.Fields(2).Value
                    End If
                End If
                subRs.MoveNext
            Loop
            Set subRs = Nothing
            Set subRsCostoIniz = Nothing
            rsTarget.Update
            .MoveNext
        Loop
    End With
    rsSource.Close
    Set rsSource = Nothing
    rsTarget.Close
    Set rsTarget = Nothing
    cnAS400.Close
    cn.Close
    MsgBox "Importazione completata!", vbOKOnly, Title
End Sub
Se siete arrivati fino qua... che ne dite?
Il mio sorgente lo devo a uno spunto di Lukino2000 che, qualche tempo fa su
questo ng, mi ha fatto capire il datashaping: uno strumento eccezionale.
Tempo di elaborazione: 3 minuti, secondo più, secondo meno.
Grazie a tutti e ciao!
Alex

>>if isnull [cut] or subRs.Fields(1) >
rsTarget.Fields("DataUltimoAcquisto").Value [cut]
Quindi si torna a quanto ho scritto nel post precedente:
Se usi solo la data come indice progressivo, e hai due acquisti nello stesso
giorno, il sistema ne prende uno a caso (in realtà prende il primo che
trova, visto che hai messo >, ma siccome nella query non hai un order by, di
fatto i record arrivano in ordine non necessariamente sequenziale).
Se sono stati acquistati con due prezzi diversi (cosa frequente con le
economie di scala), la risposta offerta dal tuo sistema è non
deterministica.
Occorre tassativamente avere un progressivo del record degli acquisti, e
devi basare il tuo test (riportato sopra), sul progressivo e non sulla data.
Se però non ti interessa che due acquisti nello stesso giorno ti cambino le
statistiche (ad esempio perchè è un evento remoto, o perchè comunque i due
prezzi unitari dovrebbero essere molto simili), allora la tua soluzione è
perfetta.
Ciao
Alberto

 perfetta.
...oltre a questo, c'è da dire che per semplificare le cose (generalizzando,
cioè, al massimo la domanda originale), ho un po' barato. Mi spiego: si
tratta di acquisti che caricano quattro magazzini. Ogni "carico", in realtà,
cancella il precedente relativo allo stesso magazzino, quindi, per ogni
articolo posso avere al massimo 4 record, uno per magazzino, appunto.
Dicendo di non sovrascrivere i record intendevo solamente specificare che
potevo avere, appunto, più record relativi a uno stesso codice, senza
limitare la domanda al caso specifico, e di questi mi serviva solo il più
recente. Non sapendo come tirar fuori la stringa SQL, non pensavo che fosse
necessario questo distinguo e la tua osservazione è, allora,  naturalmente
giustissima. Nel caso specifico, invece, è ovvio che potrei caricare
contemporaneamente due magazzini, ma ciò avverrebbe caricando anche lo
stesso costo (perché l'acquisto è fatturato complessivamente: la
distribuzione nei magazzini avviene secondo stime di vendita e in base alle
giacenze riscontrate).
Mi ha fatto piacere, comunque, scambiare due chiacchiere.
Ti saluto e ringrazio per l'aiuto!
Alex