Newsgroup: it.comp.software.database
Titolo: Ancora ultimo prezzo

Salve a tutti,
ho la seguente tabella con dati di prova su Mysql 4.0.16:
mysql> select * from t;
+------+--------+------------+
| id   | prezzo | data       |
+------+--------+------------+
|    1 |   2.45 | 2004-02-03 |
|    2 |   1.43 | 2004-03-04 |
|    1 |   0.45 | 2004-11-04 |
|    2 |   0.45 | 2004-10-04 |
|    2 |     15 | 2004-12-04 |
|    3 |    1.5 | 2004-11-04 |
|    3 |   11.5 | 2004-12-04 |
|    3 |    1.4 | 2004-12-05 |
+------+--------+------------+
8 rows in set (0.18 sec)
Devo ottenere un elenco con idArticolo e l'ultimo prezzo in ordine 
cronologico.
Ho usato la seguente query che mi riporta il risultato corretto:
mysql> select 
a.id
, a.prezzo from t a left join t b on (
a.id
=
b.id
 and 
a.data<b.data) where b.data is null;
+------+--------+
| id   | prezzo |
+------+--------+
|    1 |   0.45 |
|    2 |     15 |
|    3 |    1.4 |
+------+--------+
3 rows in set (0.11 sec)
Ora il problema è quando la eseguo sulla tabella con i dati reali che 
contiene 28000 righe. Ho lasciato la query andare per oltre mezz'ora e 
temo che non finisca.
In che modo posso migliorare le prestazioni in modo tale da ottenere un 
risultato?
Grazie

Purtroppo MySQL non possiede funzioni tipo LAST quindi devi rassegnarti 
a una query di questo tipo:
SELECT P.*
FROM
Prezzi P INNER JOIN
  ( SELECT IDArticolo, MAX(Data) AS Data
    FROM Prezzi
    GROUP BY IDArticolo
  ) AS P2
ON P.IDArticolo=P2.IDArticolo
AND P.Data=P2.Data
Comunque ti consiglio di usare una chiave primaria univoca nella tabella.
Cosě almeno ti eviti due controlli nel join e la query diventa:
SELECT P.*
FROM
Prezzi P INNER JOIN
  ( SELECT ID, MAX(Data) AS Data
    FROM Prezzi
    GROUP BY IDArticolo
  ) AS P2
ON 
P.ID
=
P2.ID
-- 
Quando noi ignoranti eravamo di piů, tutto era piů bello (A. Celentano).
  ___   _   ___ _  _______   _______ ___
|   \ /_\ | _ \ |/ / _ ) \ / /_   _| __|
| |) / _ \|   / ' <| _ \\ V /  | | | _|
|___/_/ \_\_|_\_|\_\___/ |_|   |_| |___|

Bugia, e chiedo perdono.
La seconda query non va.
Devi cambiare la seconda query in questo modo:
SELECT P.IDArticolo, P.Costo
FROM Prezzi P INNER JOIN
  ( SELECT MAX(ID) AS ID, MAX(Data) AS Data
    FROM Prezzi
    GROUP BY IDArticolo
  ) AS P2
ON 
P.ID
=
P2.ID
ma in questo caso devi assicurarti che col crescere di ID anche le date 
degli articoli crescano.
-- 
Quando noi ignoranti eravamo di più, tutto era più bello (A. Celentano).


 AND P.Data=P2.Data
OK, ma con Mysql 4.0.16 non posso usare subquery...
sapresti indicarmi un'altra soluzione?
Grazie per la risposta

 Grazie per la risposta
Di nulla :)


 Tutto questo ovviamente in due query.
Chiaro.
Ho creato la tabella temporanea e ho eseguito la query come mi hai 
suggerito.
Attualmente la query č in esecuzione da quasi 10 minuti e ancora non da 
segni di voler terminare !!
Come mai, secondo te, collegando le tabelle in questione in access97 e 
svolgendo la query con la funzione LAST ottengo il risultato 
istantaneamente??
Quale magia compie mai Access che non č possibile compiere con MySQL ??
Grazie ancora del tuo tempo.

 segni di voler terminare !!
?
Possibile?
Mi dici cosa hai detto a MySQL?
Cioč come hai scritto la query che hai lanciato per popolare la tabella 
temporanea?
E lo hai fatto da un linguaggio esterno? VB+ADO?
Raccontami tutto :)


 Raccontami tutto :)
ok sono un fesso io, ho risolto tutto!
la tabella transazione ha come chiave primaria il campo contatore...
ok comunque adesso ti racconto tutto !! :)
allora sono sulla mia linuxbox connesso con il client di mysql sul 
server sul quale devo lavorare. Attualmente il server è scarico quindi 
non c'e' problema di carico elevato.
la tabella con le transazioni contiene 336000 record (le movimentazioni 
di magazzino del 2004). A me interessano solo i prezzi di carico e 
quindi filtro solo i movimenti relativi alla merce che entra. Ecco come:
mysql> select count(*) from transazione;
+----------+
| count(*) |
+----------+
|   336590 |
+----------+
1 row in set (0.13 sec)
mysql> create table maxdata select contatore as num, idArticolo as id, 
max(data) as data from transazione where tipoMovimento=5 or 
tipoMovimento=8 or tipoMovimento=18 group by idArticolo;
Query OK, 19070 rows affected (2.06 sec)
Records: 19070  Duplicates: 0  Warnings: 0
mysql> select count(*) from maxdata;
+----------+
| count(*) |
+----------+
|    19070 |
+----------+
1 row in set (0.12 sec)
mysql>
A questo punto mi ritrovo la tua tabella temporanea (che ho chiamato 
maxdata) che contiene 19070 righe (la cosa è giusta in quanto gli 
articoli in magazzino sono 19534, e dunque evidentemente circa 500 non 
sono mai stati movimentati) con la chiave primaria della tabella 
transazione, l'id dell'articolo e la data dell'ultima movimentazione.
Ora devo solamente fare la join tra la tabella temporanea e quella delle 
transazioni:
mysql> create table ultimoPrezzo select a.idArticolo, a.data, a.prezzo 
from transazione a inner join maxdata b on (contatore=num); Query OK, 
19070 rows affected (2.46 sec)
Records: 19070  Duplicates: 0  Warnings: 0
E quindi in effetti in 5 secondi arrivo al risultato !!!
Grazie ancora dell'aiuto!

 Grazie ancora dell'aiuto!
Di niente :)
Comunque un grosso suggerimento: le tabelle 'temporanee' esistono 
davvero in MySQL.
Basta creare una TEMPORARY TABLE e non una TABLE.
In questo modo non 'sporchi' il disco fisso con file che crei e cancelli 
nel giro di minuti.
Le tabelle temporanee si creano in memoria e le possono vedere solo i 
processi che le creano; quindi se tu hai due console aperte, entrambe 
con un client mysql attivo, le tabelle temporanee le vedrā soltanto il 
client che le ha create. Si distruggono anche da sole quando il client 
si sconnette (quindi il processo termina).
Divertiti :)
-- 
Quando noi ignoranti eravamo di pių, tutto era pių bello (A. Celentano).


 processi che le creano; quindi se tu hai due console aperte, entrambe 
In realtà conoscevo le temporary table solo che negli esempi di questo 
thread non so perchè ho usato le tabelle normali.
Ma a questo punto giusto una domanda... non sapevo che le tabelle 
temporanee risiedessero in memoria. Questo dunque comporta anche un 
aumento delle prestazioni?

 aumento delle prestazioni?
NI
Nel senso che comunque stai usando memoria, quindi diminuisci la 
quantità di ram disponibile al sistema.
Se il database lo usano in pochi e queste tabelle sono piccole o 
comunque non se ne fa uso massiccio è un bene :)
Ovviamente se i client sono 10 e ognuno di loro usa SOLO tabelle 
temporanee allora la ram va a farsi benedire.
Per il resto, le prestazioni comunque salgono.
Primo perchè non stai scomodando il file system, secondo perchè i dati 
sono tutti in memoria quindi ovviamente c'è più rapidità.
L'unico inconveniente delle tabelle temporanee in mysql è che non puoi 
usarle due volte nella stessa query:
mysql> CREATE TEMPORARY TABLE Prova
     -> SELECT 1 AS Uno, 2 AS Due
     -> UNION ALL
     -> SELECT 2, 4
     -> UNION ALL
     -> SELECT 5, 100;
Query OK, 3 rows affected (0.41 sec)
Records: 3  Duplicates: 0  Warnings: 0
mysql> SELECT * FROM Prova;
+-----+-----+
| Uno | Due |
+-----+-----+
|   1 |   2 |
|   2 |   4 |
|   5 | 100 |
+-----+-----+
3 rows in set (0.03 sec)
mysql> SELECT P.*
     -> FROM Prova P INNER JOIN
     -> ( SELECT * FROM Prova) AS T
     -> ON P.Uno=T.Uno;
ERROR 1137 (HY000): Can't reopen table: 'p'
-- 
Quando noi ignoranti eravamo di più, tutto era più bello (A. Celentano).


 temo che non finisca.
In effetti la query che hai fatto genera molti records; se hai un articolo 
con 10 prezzi, ti genera mediamente 50 records (10*10/2); il recordset viene 
creato in memoria e quindi filtrato, ma la prima operazione e' quella che ti 
blocca. Senza contare l'outer join...
Prova a riscriverti la query in qualche moodo, per esempio:
select 
b.id
, b.prezzo from t b,
(select max(a.data) maxdata, 
a.id
 from t a group by 
a.id
) a
where 
a.id
 = 
b.id
 and a.maxdata = b.data
(non mi ricordo se mysql supporta questa sintassi ma mi sembra che le ultime 
versione avessero le subquery)
in alternativa esegui la subquery e per ogni record strai il prezzo, oppure 
aggiungi un campo "ultimoprezzo" (booleano) nella tabella, lo valorizzi e 
quindi estrai i records che hanno il flag settato

 Di niente :)
Approfitto ancora della tua gentilezza...
guarda questa situazione. Come si spiega?
mysql> select contatore, idArticolo, prezzo, data, tipoMovimento from 
transazione where idArticolo=17197 order by data; 
+-----------+------------+--------+------------+---------------+
| contatore | idArticolo | prezzo | data       | tipoMovimento |
+-----------+------------+--------+------------+---------------+
|     67385 |      17197 |  52.95 | 2004-01-01 |             8 |
|     21472 |      17197 |  52.95 | 2004-01-16 |             2 |
|     21473 |      17197 |  52.95 | 2004-01-16 |             2 |
|     21474 |      17197 |  52.95 | 2004-01-16 |             2 |
|     18409 |      17197 |  52.95 | 2004-02-17 |             2 |
|     18410 |      17197 |  52.95 | 2004-02-17 |             2 |
|     84136 |      17197 |  52.95 | 2004-02-24 |             1 |
|     14690 |      17197 |  52.95 | 2004-03-16 |             2 |
|    103289 |      17197 |  52.95 | 2004-03-18 |             2 |
|    123660 |      17197 |  52.95 | 2004-04-22 |             2 |
|    123661 |      17197 |  52.95 | 2004-04-22 |             2 |
|    190761 |      17197 |  55.56 | 2004-06-08 |             1 |
|    201311 |      17197 |  55.56 | 2004-08-06 |             2 |
|    226974 |      17197 |  55.56 | 2004-09-07 |             1 |
|    281265 |      17197 |  55.56 | 2004-10-13 |             2 |
|    293099 |      17197 |  55.56 | 2004-11-03 |             2 |
|    313089 |      17197 |  55.56 | 2004-12-06 |             2 |
|    313090 |      17197 |  55.56 | 2004-12-06 |             2 |
|    335361 |      17197 |  55.56 | 2004-12-13 |             1 |
|    329513 |      17197 |  55.56 | 2004-12-24 |             2 |
|    329514 |      17197 |  55.56 | 2004-12-24 |             2 |
+-----------+------------+--------+------------+---------------+
21 rows in set (1.70 sec)
mysql> create table maxdata select contatore as num, max(idArticolo) as 
id, max(data) as data from transazione where tipoMovimento=5 or 
tipoMovimento=8 or tipoMovimento=18 or tipoMovimento=1 group by idArticolo;
Query OK, 19484 rows affected (2.19 sec)
Records: 19484  Duplicates: 0  Warnings: 0
mysql> select * from maxdata where id = 17197;
+-------+-------+------------+
| num   | id    | data       |
+-------+-------+------------+
| 67385 | 17197 | 2004-12-13 |
+-------+-------+------------+
1 row in set (0.15 sec)
Come vedi ho selezionato tutte le transazione di un dato articolo (il 
17197).
Quindi ho creato la tabella temporanea che contiene l'ultima data per 
quell'articolo e il contatore che č la chiave primaria della tabella 
transazione.
Ma evidentemente la query che crea quella tabella temporanea non va bene...
Io volevo ottenere la riga numero 335361.
Come si puň risolvere?
Grazie ancora