Newsgroup: it.comp.programmare
Titolo: ancora SQL - distinct

altra domanda di sintassi SQL
con una SELECT ho la possibilità di eseguire un DISTINCT per alcuni campi,
ma ottenere nel ResultSet tutti i campi della tabella?
grazie
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 ma ottenere nel ResultSet tutti i campi della tabella?
SELECT DISTINCT serve a rimuovere le righe della risposta che sarebbero
_interamente_ duplicate.  Puoi anche usare una opzione DISTINCT entro le
funzioni aggregate (e.g. COUNT(DISTINCT name)), ma non mi pare che
questo ti avvicini molto al risultato che sembra che tu desideri.
In generale, si possono fare cose sorprendenti con SQL -- purche` si possa
definire esattamente cosa si intende per SQL, tipo "lo standard SQL-92"
ovvero "l'esatto dialetto implementato in Oracle-8" e simili.  Se invece sei
costretto ad usare l'intersezione di "tutti" i possibili motori che dicono 
di implementare un qualche dialetto di SQL, non ti resta praticamente nulla:
uno non ha le VIEWs, un altro manca dei SELECT annidati, ecc, ecc, sino
a che praticamente non devi escludere tutto.
Se sei interessato a risolvere con SQL problemi del genere, il miglior
testo che io conosca in merito e` "SQL for smarties", di Joe Celko, edito
da Morgan-Kaufmann.  Celko si concentra sull'SQL standard, soprattutto
SQL-92, ma qualche menzione di vari altri dialetti importanti la fa.  Per
un testo orientato soprattutto a illustrare le differenze fra alcuni 
dialetti importanti, e alcuni concetti di base applicabili estesamente,
consiglio invece "SQL in a Nutshell", edito da O'Reilly.
Sul tuo problema specifico, se puoi dare una specifica migliore, e il 
dialetto di tuo interesse e` anche di mia conoscenza, saro` contento
di darti una mano, se posso.  Presumibilmente la soluzione richiedera`
SELECT annidati (o costrutti ad essi equivalenti).
Supponiamo ad esempio di avere una tabella T con i seguenti campi:
    a TEXT, b TEXT, timestamp INTEGER UNIQUE, c TEXT, d TEXT
Vogliamo il singolo record con il massimo timestamp per ogni coppia
distinta di valori dei campi a e b.  Dunque, ad esempio:
SELECT * FROM T
WHERE timestamp IN
    (SELECT MAX(timestamp) FROM T
     GROUP BY a, b)
Ma se non avessimo uno UNIQUE su cui contare, non sarebbe,
credo, altrettanto semplice...
Alex

ti ringrazio per i sicuramente ottimi libri suggeriti purtoppo la mia
conoscenza SQL è vermante di base, anche perchè a livello di
programmazione non mi piace supporre che un determinato dato (alias
"attributo di un oggetto") sia sempre memorizzato su database e quindi
spesso è meglio spendere un po' di programmazione in +, ma avere soluzioni
+ flessibili.
comunque ritornando all'oggetto dei 2 precedenti messaggi, che come avrai
capito erano legati, il mio obiettvo era ottenere una sorta di risalita
sui dati con un unico statement SQL e non dovere scartare a programma dei
records.
ho risolto con questa sintassi che mi sembra abbstanza standard:
TAB_1: tabella di appoggio per ordinamenti: 
create table TAB_1(
 FIELD_1 char(10) NOT NULL,
 FIELD_2 integer NOT NULL,
 FIELD_3 char(10) NOT NULL,
 PRIMARY KEY(FIELD_1,FIELD_2)
)
TAB_2: tabella dati
create table TAB_2(
 FIELD_1 char(10) NOT NULL,
 FIELD_2 char(10) NOT NULL,
 FIELD_3 char(10) NOT NULL,
 PRIMARY KEY(FIELD_1,FIELD_2, FIELD_3)
)
SELECT * FROM tab_1 INNER JOIN tab_2 ON tab_1.field_3 = tab_2.field_1  
GROUP BY tab_1.field_1,tab_2.field_2,tab_2.field_3
HAVING(tab_2.field_2='YYY' or tab_2.field_2='ZZZ'))
ORDER BY tab_2.field_3
. ma forse non molta chiara
grazie comunque leggerò "SQL for smarties"


 grazie comunque leggerò "SQL for smarties"
Prego!  Comunque "SQL for smarties" e` MOLTO avanzato, e forse,
se come dici parti da una preparazione molto scarsa sul tema
specifico, ti conviene usare un qualche "passo intermedio" --
mi pare che lo stesso Celko abbia anche un buon manuale
intermedio di SQL e DB relazionali, ma non l'ho letto.
Alex

 motore SQL per evitare lavoro all'applicativo.
qui mi era possibile sfruttare a pieno il database, neanche a me piace
martellarmi gli zebedei inutilmente!
per quello che riguarda la sintassi "SQL impossibile" gira su MySql
3.23.41 x Linux, ma sicuramente approfondirņ il GROUP BY poichč lo
utilizzo per "aggirare" il DISTINCT
grazie ancora


 utilizzo per "aggirare" il DISTINCT
Gia`, da un piccolo esperimento vedo che MySQL sembra prendere
"group by" come una indicazione di "tornami una riga a caso fra
tutte quelle che hanno gli stessi valori di questi campi"...:
mysql> create table x1 (f1 char(10), f2 char(10), f3 char(10));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into x1 values('a','b','c');
Query OK, 1 row affected (0.00 sec)
mysql> insert into x1 values('a','b','z');
Query OK, 1 row affected (0.00 sec)
mysql> select * from x1 group by f1, f2 order by f3 desc;
+------+------+------+
| f1   | f2   | f3   |
+------+------+------+
| a    | b    | c    |
+------+------+------+
1 row in set (0.00 sec)
mysql> select * from x1 group by f1, f2 order by f3 asc;
+------+------+------+
| f1   | f2   | f3   |
+------+------+------+
| a    | b    | c    |
+------+------+------+
1 row in set (0.00 sec)
mysql>
Sia ordinando per f3 ascendente, sia discendente, torna "un
valore a caso" del campo f3 fra tutti quelli che hanno una
data coppia di valori per f1 e f2.  Non mi e` chiaro a cosa
serva questo comportamento, comunque e` ben lontano dall'SQL
standard!  Piu` vicino PostgreSQL, che immagino tu non abbia
problemi a provare essendo anche tu su Linux:
test=# select * from tab2;
   field1   |   field2   |   field3
------------+------------+------------
 a          | b          | c
 a          | b          | z
(2 rows)
test=# select * from tab2 group by field1, field2 order by field3 desc;
ERROR:  Attribute tab2.field3 must be GROUPed or used in an aggregate 
function
test=# select * from tab2 where field3 in (
test(# select max(field3) from tab2 group by field1, field2);
   field1   |   field2   |   field3
------------+------------+------------
 a          | b          | z
(1 row)
Naturalmente il select annidato (che ti permette di controllare
se vuoi ad esempio il minimo o massimo valore di field3 per
ciascun set di valori di field1, field2) e` previsto dallo
standard SQL, ma NON supportato da MySQL.
I subselect (select annidati) dovrebbero apparire in MySQL 3.24,
secondo il libro che uso come riferimento di MySQL (autore Paul
DuBois, editore New Riders).  Non so come scrivere questa
query in modo standard SENZA select annidati, se non ovviamente
come due query con una tabella temporanea di mezzo...:
test=# create temporary table xx (f1 char(10), f2 char(10), f3 char(10));
CREATE
test=# insert into xx select field1, field2, max(field3) from tab2 group by 
field1, field2;
INSERT 19290 1
test=# select tab2.* from tab2, xx where field1=f1 and field2=f2 and 
field3=f3;
   field1   |   field2   |   field3
------------+------------+------------
 a          | b          | z
(1 row)
test=#
Questo funziona con entrambi i motori:
mysql> create temporary table xx (f1 char(10), f2 char(10), f3 char(10));
Query OK, 0 rows affected (0.00 sec)
mysql> insert into xx select field1, field2, max(field3) from tab2 group by 
field1, field2;
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0
mysql> select tab2.* from tab2, xx where field1=f1 and field2=f2 and 
field3=f3;
+--------+--------+--------+
| field1 | field2 | field3 |
+--------+--------+--------+
| a      | b      | z      |
+--------+--------+--------+
1 row in set (0.00 sec)
mysql>
e dovrebbe funzionare con qualsiasi motore SQL.  Le prestazioni non
sono altrettanto sicure: dipende soprattutto, penso, da quanto grande
sia la tabella temporanea, che non e` indiciata (e non credo abbia
molto senso indicizzare a posteriori... ma se e` grossa, forse).
Alex