Newsgroup: it.comp.software.database
Titolo: Selezionare n record, ma non di più di m per tipo

Salve a tutti,
ho un certo numero di record di una tabella su due campi, A e B. Come faccio
a selezionare i
primi N risultati di una query relativa al campo B ma (arriva il bello) non
mostrando piů di M risultati che concordino su A?
Esempio:
A    B (colonne)
a    e
a    i
a    o
a    u
1    2
1    3
1    4
1    5
Dovrei mostrare i primi 10 record (o meno, come in questo caso) ma non piů
di 3 per
tipo (A)
Il risultato dovrebbe essere
A    B (colonne)
a    e <- prima di tipo a
a    i <- seconda di tipo a
a    o <- terza di tipo a
1    2 <- prima di tipo 1
1    3 <- seconda di tipo 1
1    4 <- terza di tipo 1
Pensavo ad aggiungere un campo che faccia da conteggio, e su cui poi avrei
messo delle condizioni... ma non so se e come si puň fare. L'ideale sarebbe
usare una bella UNION, ma su mysql V.quella.che.ho non č disponibile.
Mi serve perchč ho un elenco di news di varie fonti che vorrei mostrare in
modo abbastanza omogeneo, mostrando max 3 news per fonte.
Inizialmente volevo fare in modo che le news fossero in ordine di
aggiornamento, ma una delle fonti aggiorna molto di piů delle altre,
portando queste altre sempre fuori dai primi 15 posti (maledetta BBC).
Thanks
Ludovico


Con una sola query non si puo' fare.
Avendo un campo TIMESTAMP per filtrare, qualcosa si puo' fare, ma ci 
vuole l'ausilio di un linguaggio di programmazione esterno.
Partiamo da questa situazione:
mysql> select * from news;
+---+---+----------------+
| A | B | TS             |
+---+---+----------------+
| a | e | 20200406021210 |
| a | i | 20200406031810 |
| a | o | 20200406041810 |
| a | u | 20040605182520 |
| 1 | 2 | 20200406031810 |
| 1 | 3 | 20200406031910 |
| 1 | 4 | 20200406032110 |
| 1 | 5 | 20040605182520 |
| c | w | 20040605221238 |
| c | x | 20040605221245 |
| c | y | 20040605221250 |
| c | z | 20040605221256 |
| d | i | 20040605221321 |
| d | j | 20040605221324 |
| d | k | 20040605221329 |
| d | l | 20040605221334 |
| d | m | 20040605221337 |
+---+---+----------------+
17 rows in set (0.00 sec)
Con i requisiti da te imposti, ho fatto questo programmino di test, che 
ottiene il risultato appoggiandosi a una tabella temporanea. I tre 
risultati sono filtrati in base al timestamp, e vengono mostrati i tre 
piu' recenti:
#!/usr/bin/perl -w
use DBI;
use strict;
my $dbh = DBI->connect("DBI:mysql:test;host=localhost"
         . ";mysql_read_default_file=$ENV{HOME}/.my.cnf",
         undef, undef, {RaiseError => 1})
         or die "non posso connettermi\n";
my $max_news = 10;
my $tipi_news = $dbh->selectcol_arrayref(
     qq{select distinct A from news});
$dbh->do(qq{create temporary table if not exists tempnews
     (A char, B char, TS timestamp)});
for (@$tipi_news) {
     $dbh->do(qq{
         insert into tempnews
         select * from news
         where A = ?
         order by TS desc
         limit 3
     }, undef, $_);
     my ($count) = $dbh->selectrow_array(
         qq{SELECT count(*) from tempnews});
     last if $count > $max_news;
}
for (@{$dbh->selectall_arrayref(
     qq{select * from tempnews limit $max_news})})
{
     print "@$_\n"
}
E questo e' il risultato.
1 4 20200406032110
1 3 20200406031910
1 2 20200406031810
a o 20200406041810
a i 20200406031810
a e 20200406021210
c z 20040605221256
c y 20040605221250
c x 20040605221245
d m 20040605221337
Ho qualche perplessita' sui requisiti.
Come decidi quante righe mostrare?
Arrivati a quattro tipi, le dieci righe sono gia' impegnate. E se ci 
sono piu' di quattro tipi di news, cosa fai? Gia' in questo esempio si 
vede solo una riga dell'ultimo tipo.
Nota inoltre che non si puo' usare una UNION invece della tabella 
temporanea, perche' la clausola LIMIT, necessaria per filtrare i primi 
tre risultati, si applica una volta sola all'intera query.
Questi sono argomenti di riflessione buoni per la domenica. :-)
Ciao
gmax
-- 
   ____ ____  _____ _   _
  / _  |    \(____ ( \ / )
( (_| | | | / ___ |) X (
  \___ |_|_|_\_____(_/ \_)
(_____|
Sapere, saper fare, fare, far sapere
http://gmax.oltrelinux.com

 è disponibile.
[SNIP]
Ciao Ludovico,
l'idea e' proprio quella di usare un campo che faccia
il conteggio, anche senza UNION, in compenso l'engine
deve supportare le sub-query.
In coda un esempio che dovrebbe essere secondo standard
ANSI utilizzando delle viste, ma se l'engine supporta le
tabelle derivate puoi usare tranquillamente anche quelle.
Ciao,
--
Gianluca Hotz - SQL Server MVP
http://italy.mvps.org
 - 
http://www.ghotz.com
http://www.ugiss.org
  - 
http://www.ugidotnet.org
--
CREATE TABLE Test (
 A char(1) NOT NULL
, B char(1) NOT NULL
 CONSTRAINT pkTest
 PRIMARY KEY (A, B)
)
INSERT Test VALUES ('a', 'e')
INSERT Test VALUES ('a', 'i')
INSERT Test VALUES ('a', 'o')
INSERT Test VALUES ('a', 'u')
INSERT Test VALUES ('1', '2')
INSERT Test VALUES ('1', '3')
INSERT Test VALUES ('1', '4')
INSERT Test VALUES ('1', '5')
CREATE VIEW TestViewAsc
AS
SELECT T1.A
, T1.B
, (
 SELECT COUNT(*)
 FROM Test AS T2
 WHERE T2.A = T1.A
   AND T2.B < T1.B
 ) AS Num
FROM Test AS T1
GO
CREATE VIEW TestViewDesc
AS
SELECT T1.A
, T1.B
, (
 SELECT COUNT(*)
 FROM Test AS T2
 WHERE T2.A = T1.A
   AND T2.B > T1.B
 ) AS Num
FROM Test AS T1
GO
SELECT V1.A, V1.B
FROM TestViewAsc AS V1
WHERE V1.Num < 3
ORDER BY
 V1.A, V1.B ASC
SELECT V1.A, V1.B
FROM TestViewDesc AS V1
WHERE V1.Num < 3
ORDER BY
 V1.A, V1.B DESC