Ordina MySQL prima di raggruppare per


243

Ci sono molte domande simili che possono essere trovate qui, ma non credo che nessuna di esse risponda adeguatamente alla domanda.

Continuerò dall'attuale domanda più popolare e userò il loro esempio se va bene.

Il compito in questa istanza è quello di ottenere l'ultimo post per ciascun autore nel database.

La query di esempio produce risultati inutilizzabili in quanto non è sempre l'ultimo post restituito.

SELECT wp_posts.* FROM wp_posts
    WHERE wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
    GROUP BY wp_posts.post_author           
    ORDER BY wp_posts.post_date DESC

La risposta attualmente accettata è

SELECT
    wp_posts.*
FROM wp_posts
WHERE
    wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author
HAVING wp_posts.post_date = MAX(wp_posts.post_date) <- ONLY THE LAST POST FOR EACH AUTHOR
ORDER BY wp_posts.post_date DESC

Sfortunatamente questa risposta è chiaramente sbagliata e in molti casi produce risultati meno stabili rispetto alla query originale.

La mia soluzione migliore è utilizzare una sottoquery del modulo

SELECT wp_posts.* FROM 
(
    SELECT * 
    FROM wp_posts
    ORDER BY wp_posts.post_date DESC
) AS wp_posts
WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author 

La mia domanda è semplice: esiste un modo per ordinare le righe prima di raggruppare senza ricorrere a una sottoquery?

Modifica : questa domanda è stata una continuazione di un'altra domanda e i dettagli della mia situazione sono leggermente diversi. Puoi (e dovresti) presumere che ci sia anche un wp_posts.id che è un identificatore univoco per quel particolare post.


2
Come hai menzionato nei commenti alle risposte fornite, potrebbe essere possibile avere alcuni post con lo stesso timestamp. In tal caso, fornire un esempio con i dati e il risultato previsto. E per favore descrivi, perché ti aspetti questo risultato. post_authore post_datenon sono sufficienti per ottenere una riga univoca, quindi ci deve essere altro per ottenere una riga unica perpost_author
Sir Rufo,

@SirRufo Hai ragione, ho aggiunto una modifica per te.
Rob Forrest,

There are plenty of similar questions to be found on here but I don't think that any answer the question adequately.Ecco a cosa servono le taglie.
Corse di leggerezza in orbita,

@LightnessRacesinOrbit, se la domanda attuale ha già una risposta accettata che secondo me è sbagliata, cosa suggeriresti di fare?
Rob Forrest,

1
Ti chiedi perché hai accettato una risposta che utilizza una subquery - quando la tua domanda chiaramente pone ... "" Esiste un modo per ordinare le righe prima di raggruppare senza ricorrere a una subquery? "???
TV-C-15

Risposte:


373

L'uso ORDER BYdi una subquery non è la soluzione migliore a questo problema.

La soluzione migliore per ottenere l' max(post_date)autore è utilizzare una sottoquery per restituire la data massima e quindi unirla alla tabella sia nella post_authordata massima che in quella massima.

La soluzione dovrebbe essere:

SELECT p1.* 
FROM wp_posts p1
INNER JOIN
(
    SELECT max(post_date) MaxPostDate, post_author
    FROM wp_posts
    WHERE post_status='publish'
       AND post_type='post'
    GROUP BY post_author
) p2
  ON p1.post_author = p2.post_author
  AND p1.post_date = p2.MaxPostDate
WHERE p1.post_status='publish'
  AND p1.post_type='post'
order by p1.post_date desc

Se si dispone dei seguenti dati di esempio:

CREATE TABLE wp_posts
    (`id` int, `title` varchar(6), `post_date` datetime, `post_author` varchar(3))
;

INSERT INTO wp_posts
    (`id`, `title`, `post_date`, `post_author`)
VALUES
    (1, 'Title1', '2013-01-01 00:00:00', 'Jim'),
    (2, 'Title2', '2013-02-01 00:00:00', 'Jim')
;

La sottoquery restituirà la data massima e l'autore di:

MaxPostDate | Author
2/1/2013    | Jim

Quindi, poiché lo stai ricollegando alla tabella, su entrambi i valori restituirai i dettagli completi di quel post.

Vedi SQL Fiddle with Demo .

Per espandere i miei commenti sull'utilizzo di una sottoquery per restituire accuratamente questi dati.

MySQL non ti obbliga a GROUP BYtutte le colonne che includi SELECTnell'elenco. Di conseguenza, se solo GROUP BYuna colonna restituisce 10 colonne in totale, non vi è alcuna garanzia che gli altri valori della colonna che appartengono a quello post_authorche viene restituito. Se la colonna non è in un GROUP BYMySQL, sceglie quale valore deve essere restituito.

L'uso della subquery con la funzione aggregata garantirà che l'autore e il post corretti vengano restituiti ogni volta.

Come nota a margine, mentre MySQL ti consente di utilizzare un ORDER BYin una sottoquery e ti consente di applicare GROUP BYa non tutte le colonne SELECTdell'elenco, questo comportamento non è consentito in altri database incluso SQL Server.


4
Vedo quello che hai fatto lì, ma ciò restituisce semplicemente la data in cui è stato pubblicato il post più recente, non l'intera riga per quel post più recente.
Rob Forrest

1
@RobForrest è quello che fa il join. Restituisci la data di pubblicazione più recente nella sottoquery per autore e poi ti ricolleghi alla tua wp_postssu entrambe le colonne per ottenere l'intera riga.
Taryn

7
@RobForrest Per uno, quando si applica la GROUP BYa una sola colonna, non vi è alcuna garanzia che i valori nelle altre colonne saranno costantemente corretti. Sfortunatamente, MySQL consente a questo tipo di SELECT / GROUPing di accadere altri prodotti no. In secondo luogo, la sintassi dell'uso ORDER BYdi una sottoquery mentre è consentita in MySQL non è consentita in altri prodotti di database, incluso SQL Server. È necessario utilizzare una soluzione che restituirà il risultato corretto ogni volta che viene eseguita.
Taryn

2
Per il ridimensionamento, il composto INDEX(post_author, post_date)è importante.
Rick James

1
@ jtcotton63 Vero, ma se inserisci la post_idtua query interna, tecnicamente dovresti raggruppare anche per essa, il che probabilmente distorcerebbe i tuoi risultati.
Taryn

20

La tua soluzione utilizza un'estensione della clausola GROUP BY che consente di raggruppare per alcuni campi (in questo caso, solo post_author):

GROUP BY wp_posts.post_author

e seleziona colonne non aggregate:

SELECT wp_posts.*

che non sono elencati nella clausola group by o che non sono utilizzati in una funzione aggregata (MIN, MAX, COUNT, ecc.).

Uso corretto dell'estensione alla clausola GROUP BY

Ciò è utile quando tutti i valori delle colonne non aggregate sono uguali per ogni riga.

Ad esempio, supponiamo di avere un tavolo GardensFlowers( namedel giardino, flowerche cresce nel giardino):

INSERT INTO GardensFlowers VALUES
('Central Park',       'Magnolia'),
('Hyde Park',          'Tulip'),
('Gardens By The Bay', 'Peony'),
('Gardens By The Bay', 'Cherry Blossom');

e vuoi estrarre tutti i fiori che crescono in un giardino, dove crescono più fiori. Quindi devi usare una sottoquery, ad esempio puoi usare questo:

SELECT GardensFlowers.*
FROM   GardensFlowers
WHERE  name IN (SELECT   name
                FROM     GardensFlowers
                GROUP BY name
                HAVING   COUNT(DISTINCT flower)>1);

Se invece devi estrarre tutti i fiori che sono gli unici fiori del giardiniere, puoi semplicemente cambiare la condizione HAVING in HAVING COUNT(DISTINCT flower)=1, ma MySql ti consente anche di usare questo:

SELECT   GardensFlowers.*
FROM     GardensFlowers
GROUP BY name
HAVING   COUNT(DISTINCT flower)=1;

nessuna subquery, non standard SQL, ma più semplice.

Uso errato dell'estensione alla clausola GROUP BY

Ma cosa succede se selezioni colonne non aggregate che non sono uguali per ogni riga? Qual è il valore che MySql sceglie per quella colonna?

Sembra che MySql scelga sempre il PRIMO valore che incontra.

Per assicurarsi che il primo valore che incontra sia esattamente il valore desiderato, è necessario applicare GROUP BYa una query ordinata, quindi la necessità di utilizzare una sottoquery. Non puoi farlo diversamente.

Dato che MySql sceglie sempre la prima riga che incontra, stai ordinando correttamente le righe prima di GROUP BY. Ma sfortunatamente, se leggi attentamente la documentazione, noterai che questa ipotesi non è vera.

Quando si selezionano colonne non aggregate che non sono sempre le stesse, MySql è libero di scegliere qualsiasi valore, quindi il valore risultante che mostra effettivamente è indeterminato .

Vedo che questo trucco per ottenere il primo valore di una colonna non aggregata viene usato molto e di solito / quasi sempre funziona, lo uso anche a volte (a mio rischio). Ma poiché non è documentato, non puoi fare affidamento su questo comportamento.

Questo link (grazie a ypercube!) Il trucco GROUP BY è stato ottimizzato per mostrare una situazione in cui la stessa query restituisce risultati diversi tra MySql e MariaDB, probabilmente a causa di un motore di ottimizzazione diverso.

Quindi, se questo trucco funziona, è solo una questione di fortuna.

La risposta accettata sull'altra domanda mi sembra sbagliata:

HAVING wp_posts.post_date = MAX(wp_posts.post_date)

wp_posts.post_dateè una colonna non aggregata e il suo valore sarà ufficialmente indeterminato, ma sarà probabilmente il primo post_daterilevato. Ma poiché il trucco GROUP BY viene applicato a una tabella non ordinata, non è sicuro quale sia il primo che si post_dateincontra.

Probabilmente restituirà post che sono gli unici post di un singolo autore, ma anche questo non è sempre certo.

Una possibile soluzione

Penso che questa potrebbe essere una possibile soluzione:

SELECT wp_posts.*
FROM   wp_posts
WHERE  id IN (
  SELECT max(id)
  FROM wp_posts
  WHERE (post_author, post_date) = (
    SELECT   post_author, max(post_date)
    FROM     wp_posts
    WHERE    wp_posts.post_status='publish'
             AND wp_posts.post_type='post'
    GROUP BY post_author
  ) AND wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
  GROUP BY post_author
)

Nella query interna sto restituendo la data massima di pubblicazione per ogni autore. Sto quindi prendendo in considerazione il fatto che lo stesso autore potrebbe teoricamente avere due post contemporaneamente, quindi ottengo solo l'ID massimo. E poi sto restituendo tutte le righe che hanno quegli ID massimi. Potrebbe essere reso più veloce usando i join anziché la clausola IN.

(Se sei sicuro che IDsta solo aumentando, e se ID1 > ID2significa anche quello post_date1 > post_date2, allora la query potrebbe essere resa molto più semplice, ma non sono sicuro che sia così).


Questa extension to GROUP Byè una lettura interessante, grazie per quello.
Rob Forrest

2
Un esempio in cui fallisce: il trucco GROUP BY è stato ottimizzato via
ypercubeᵀᴹ

Colonne non aggregate in espressioni selezionate con GROUP BY non funzionano più per impostazione predefinita con MySQL 5.7: stackoverflow.com/questions/34115174/… . Quale IMHO è molto più sicuro e costringe alcune persone a scrivere query più efficienti.
rink.attendant.6

Questa risposta non utilizza una subquery? Il Poster originale non richiede una soluzione che NON utilizza una sottoquery?
TV-C-15,

1
@ TV-C-15 il problema è con il ricorso alla sottoquery e sto spiegando perché il ricorso a una sottoquery non funzionerà. Anche la risposta accettata usa una sottoquery ma inizia a spiegare perché il ricorso è una cattiva idea (L' uso di un ORDER BY in una sottoquery non è la soluzione migliore a questo problema )
fthiella

9

Quello che stai per leggere è piuttosto confuso, quindi non provarlo a casa!

In SQL in generale la risposta alla tua domanda è NO , ma a causa della modalità rilassata di GROUP BY(menzionata da @bluefeet ), la risposta è in MySQL.

Supponiamo di avere un indice BTREE su (post_status, post_type, post_author, post_date). Come appare l'indice sotto il cofano?

(post_status = 'publishing', post_type = 'post', post_author = 'user A', post_date = '2012-12-01') (post_status = 'publishing', post_type = 'post', post_author = 'user A', post_date = '2012-12-31') (post_status = 'publishing', post_type = 'post', post_author = 'user B', post_date = '2012-10-01') (post_status = 'publishing', post_type = ' post ', post_author =' user B ', post_date =' 2012-12-01 ')

Cioè i dati sono ordinati per tutti quei campi in ordine crescente.

Quando si esegue un GROUP BYper impostazione predefinita, ordina i dati in base al campo di raggruppamento ( post_author, nel nostro caso; post_status, post_type sono richiesti dalla WHEREclausola) e se esiste un indice corrispondente, prende i dati per ogni primo record in ordine crescente. Cioè la query recupererà quanto segue (il primo post per ciascun utente):

(post_status = 'publishing', post_type = 'post', post_author = 'user A', post_date = '2012-12-01') (post_status = 'publishing', post_type = 'post', post_author = 'user B', POST_DATE = '2012-10-01')

Ma GROUP BYin MySQL ti consente di specificare l'ordine esplicitamente. E quando richiedi post_userin ordine decrescente, percorrerà il nostro indice nell'ordine opposto, mantenendo comunque il primo record per ciascun gruppo che è effettivamente l'ultimo.

Questo è

...
WHERE wp_posts.post_status='publish' AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author DESC

ci darà

(post_status = 'publisher', post_type = 'post', post_author = 'user B', post_date = '2012-12-01') (post_status = 'publishing', post_type = 'post', post_author = 'user A', POST_DATE = '2012-12-31')

Ora, quando ordini i risultati del raggruppamento per post_date, ottieni i dati desiderati.

SELECT wp_posts.*
FROM wp_posts
WHERE wp_posts.post_status='publish' AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author DESC
ORDER BY wp_posts.post_date DESC;

NB :

Questo non è ciò che consiglierei per questa particolare query. In questo caso, utilizzerei una versione leggermente modificata di ciò che suggerisce @bluefeet . Ma questa tecnica potrebbe essere molto utile. Dai un'occhiata alla mia risposta qui: recupero dell'ultimo record in ciascun gruppo

Insidie : gli svantaggi dell'approccio è quello

  • il risultato della query dipende dall'indice, che è contrario allo spirito dell'SQL (gli indici dovrebbero solo accelerare le query);
  • L'indice non sa nulla della sua influenza sulla query (tu o qualcun altro in futuro potresti trovare l'indice troppo dispendioso in termini di risorse e modificarlo in qualche modo, rompendo i risultati della query, non solo le sue prestazioni)
  • se non capisci come funziona la query, molto probabilmente dimenticherai la spiegazione in un mese e la query confonderà te e i tuoi colleghi.

Il vantaggio è la prestazione in casi difficili. In questo caso, le prestazioni della query dovrebbero essere le stesse della query di @ bluefeet, a causa della quantità di dati coinvolti nell'ordinamento (tutti i dati vengono caricati in una tabella temporanea e quindi ordinati; a proposito, anche la sua query richiede l' (post_status, post_type, post_author, post_date)indice) .

Cosa suggerirei :

Come ho detto, queste query fanno perdere tempo a MySQL nell'ordinamento di enormi quantità di dati in una tabella temporanea. Nel caso in cui sia necessario il paging (vale a dire LIMIT è coinvolto) la maggior parte dei dati viene persino eliminata. Quello che vorrei fare è minimizzare la quantità di dati ordinati: questo è l'ordinamento e limita un minimo di dati nella sottoquery e poi ricollego all'intera tabella.

SELECT * 
FROM wp_posts
INNER JOIN
(
  SELECT max(post_date) post_date, post_author
  FROM wp_posts
  WHERE post_status='publish' AND post_type='post'
  GROUP BY post_author
  ORDER BY post_date DESC
  -- LIMIT GOES HERE
) p2 USING (post_author, post_date)
WHERE post_status='publish' AND post_type='post';

La stessa query utilizzando l'approccio sopra descritto:

SELECT *
FROM (
  SELECT post_id
  FROM wp_posts
  WHERE post_status='publish' AND post_type='post'
  GROUP BY post_author DESC
  ORDER BY post_date DESC
  -- LIMIT GOES HERE
) as ids
JOIN wp_posts USING (post_id);

Tutte quelle query con i loro piani di esecuzione su SQLFiddle .


Questa è una tecnica interessante che devi andare lì. Due cose: dici di non provarlo a casa, quali sono le potenziali insidie? in secondo luogo, citi una versione leggermente modificata della risposta di bluefeet, quale sarebbe?
Rob Forrest,

Grazie per questo, è interessante vedere qualcuno che attacca il problema in un modo diverso. Dato che il mio set di dati non è vicino alle tue 18M + righe, non penso che le prestazioni siano cruciali quanto la manutenibilità, quindi penso che le tue opzioni successive siano probabilmente più adatte. Mi piace l'idea del limite all'interno della sottoquery.
Rob Forrest,

8

Prova questo. Basta ottenere l'elenco delle ultime date dei post da ciascun autore . Questo è tutto

SELECT wp_posts.* FROM wp_posts WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post' AND wp_posts.post_date IN(SELECT MAX(wp_posts.post_date) FROM wp_posts GROUP BY wp_posts.post_author) 

@Rob Forrest, controlla la mia soluzione. Risolve la tua domanda, si spera!
sanchitkhanna26,

1
Mi dispiace, non penso che funzionerebbe. Ad esempio, se sia l'autore 1 che l'autore 2 pubblicano qualcosa l'01 / 02/13 e quindi l'autore 2 pubblica qualcosa di nuovo l'08 / 02/13, verranno restituiti tutti e 3 i post. Sì, il campo datetime include il tempo, quindi la situazione è meno probabile, ma non è affatto garantita su un set di dati abbastanza grande.
Rob Forrest,

+1 per l'utilizzo di post_date IN (select max(...) ...). Questo è più efficiente che fare un gruppo in una sottoselezione
Seaux

solo per chiarire, questo è solo più ottimale se hai indicizzato post_author.
Seaux,

1
IN ( SELECT ... )è molto meno efficiente dell'equivalente JOIN.
Rick James

3

No. Non ha senso ordinare i record prima del raggruppamento, poiché il raggruppamento modificherà il set di risultati. Il modo subquery è il modo preferito. Se ciò sta andando troppo lentamente, dovresti cambiare il design della tua tabella, ad esempio memorizzando l'id dell'ultimo post per ciascun autore in una tabella separata, o introdurre una colonna booleana che indica per ciascun autore quale dei suoi post è l'ultimo uno.


Dennish, come risponderesti ai commenti di Bluefeet secondo cui questo tipo di query non è una sintassi SQL corretta e quindi non portabile su piattaforme di database? Si teme inoltre che non vi sia alcuna garanzia che ciò produca sempre i risultati corretti.
Rob Forrest

2

Basta usare la funzione max e la funzione di gruppo

    select max(taskhistory.id) as id from taskhistory
            group by taskhistory.taskid
            order by taskhistory.datum desc

3
Cosa succede se quello con l'ID più alto non è l'ultimo pubblicato? Un esempio di ciò potrebbe essere che l'autore ha tenuto il suo posto in bozza per un lungo periodo di tempo prima di pubblicarlo.
Rob Forrest,

0

Giusto per ricapitolare, la soluzione standard utilizza una sottoquery non correlata e si presenta così:

SELECT x.*
  FROM my_table x
  JOIN (SELECT grouping_criteria,MAX(ranking_criterion) max_n FROM my_table GROUP BY grouping_criteria) y
    ON y.grouping_criteria = x.grouping_criteria
   AND y.max_n = x.ranking_criterion;

Se stai utilizzando una versione antica di MySQL o un set di dati abbastanza piccolo, puoi utilizzare il seguente metodo:

SELECT x.*
  FROM my_table x
  LEFT
  JOIN my_table y
    ON y.joining_criteria = x.joining_criteria
   AND y.ranking_criteria < x.ranking_criteria
 WHERE y.some_non_null_column IS NULL;  

Quando dici una versione antica, su quale versione di MySQL funzionerebbe? E scusate no, il set di dati è abbastanza grande nel mio esempio.
Rob Forrest,

Funzionerà (lentamente) su qualsiasi versione. Le versioni precedenti non possono utilizzare le subquery.
Fragola

Sì, il metodo n. 2 (la versione che ho provato è da qui ) non funzionerà su un set di dati di grandi dimensioni (milioni di righe), genera un errore di connessione perso . Il metodo n. 1 richiede ~ 15 secondi per eseguire una query. Inizialmente volevo evitare di utilizzare query nidificate, ma questo mi ha fatto riconsiderare. Grazie!
aexl,

@TheSexiestManinJamaica Sì. Non è cambiato molto in 3,5 anni. Supponendo che una query sia di per sé efficiente, il tempo necessario per l'esecuzione della query dipende in gran parte dalla dimensione del set di dati, dalla disposizione degli indici e dall'hardware disponibile.
Fragola,

-1

** Le query secondarie possono avere un impatto negativo sulle prestazioni se utilizzate con set di dati di grandi dimensioni **

Query originale

SELECT wp_posts.*
FROM   wp_posts
WHERE  wp_posts.post_status = 'publish'
       AND wp_posts.post_type = 'post'
GROUP  BY wp_posts.post_author
ORDER  BY wp_posts.post_date DESC; 

Query modificata

SELECT p.post_status,
       p.post_type,
       Max(p.post_date),
       p.post_author
FROM   wp_posts P
WHERE  p.post_status = "publish"
       AND p.post_type = "post"
GROUP  BY p.post_author
ORDER  BY p.post_date; 

perché sto usando maxin select clause==> max(p.post_date)è possibile evitare le query di sub-selezione e l'ordine per la colonna max dopo il gruppo per.


1
Questo in effetti restituisce il post_date più recente per autore, ma non vi è alcuna garanzia che il resto dei dati restituiti si riferisca al post con il post_date più recente.
Rob Forrest,

@RobForrest -> Non capisco perché? è una buona idea elaborare la tua risposta e buttare via i reclami. Per quanto ho capito, i dati sono garantiti come correlati in quanto utilizzo la clausola where per filtrare i dati correlati.
guykaplan,

1
In una certa misura, sei del tutto corretto, ciascuno dei 4 campi che stai selezionando si riferisce a quel massimo post_date, ma questo non risponde alla domanda che è stata posta. Ad esempio, se hai aggiunto il post_id o il contenuto del post, non sarà garantito che quelle colonne provengano dallo stesso record della data massima. Per ottenere la query sopra per restituire il resto dei dettagli del post, è necessario eseguire una seconda query. Se la domanda riguardava la ricerca della data del post più recente, allora sì, la tua risposta andrebbe bene.
Rob Forrest,

@guykaplan, Le subquery non sono lente. Le dimensioni del set di dati non contano. Dipende da come lo usi. Vedi percona.com/blog/2010/03/18/when-the-subselect-runs-faster
Pacerier

@Pacerier: l'articolo mostra in effetti come ottenere vantaggi in termini di prestazioni dalle sottoquery, ma mi piacerebbe vederti convertire lo scenario dato per ottenere prestazioni migliori. e la dimensione dei dati è importante, sempre nel dato articolo che hai pubblicato stai assumendo che ci sia una sola tabella con cui lavorare. la dimensione dei dati non è la dimensione della riga, è la dimensione della complessità. detto questo, se si lavora con tabelle di dimensioni molto grandi (non molte tabelle coinvolte) la sottoquery può funzionare molto meglio.
guykaplan,

-4

Innanzitutto, non utilizzare * in select, influisce sulle loro prestazioni e ostacola l'utilizzo del gruppo per e ordina per. Prova questa query:

SELECT wp_posts.post_author, wp_posts.post_date as pdate FROM wp_posts
WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post'
GROUP BY wp_posts.post_author           
ORDER BY pdate DESC

Quando non si specifica la tabella in ORDER BY, solo l'alias, ordineranno il risultato della selezione.


Ignora i * selezionati, sono per brevità in questo esempio. La tua risposta è esattamente la stessa del primo esempio che ho dato.
Rob Forrest

L'alias non ha alcun effetto su quale riga viene restituita né sull'ordinamento dei risultati.
Rob Forrest,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.