2011-01-13 6 views
1

J'ai une base de données avec:Requête SQL complexe avec MySQL?

[business] must have a [location] 
[location] may have many [business] 
[location] may have many [postcode] 
[postcode] may be for many [location] 
[postcode] must have a [state] 

Je veux une requête pour renvoyer les 10 premiers sites de chaque Etat en fonction du nombre d'affaires.

Pour plus de sens, il peut sortir:

Western Australia 
    - perth 
    - bunbury 
    - etc. up to 10 

(c.-à-perth a la plupart des entreprises cotées en Australie occidentale)

Victoria 
    - melbourne 
    - st kilda 
    - etc. up to 10 

Etc.

J'espérais réaliser ceci sans utiliser UNION. Je n'ai pas fait de SQL complexe depuis un moment et ça me fait mal à la tête.

J'utilise MySQL.

Une façon similaire de mettre cela serait si vous aviez des catégories, des produits et des commandes et que vous vouliez les dix premiers produits en termes de nombre de commandes pour chaque catégorie.

+1

Vous aurez besoin d'inclure vos définitions de table si vous voulez que les gens vous aident à créer une requête MySQL – Dancrumb

+0

Si vous utilisez l'exemple des catégories, produits et commandes à la fin, vous pouvez imaginer une définition de table standard. C'est aussi une question conceptuelle sur la façon d'y parvenir. Je suis heureux d'écrire la requête que je n'ai aucune idée de la façon de le structurer sans utiliser l'union. – oak

+0

Étiqueté avec 'most-n-per-group' pour vous guider vers des questions similaires - J'ai vu quelqu'un d'autre le faire (et a pris le commentaire exact! :-). Quoi qu'il en soit, cela aurait été fait avec SQL Server avec 'ROW_NUMBER (... PARTITION ON ...)', il s'agit donc de trouver un (gentil) équivalent MySQL, s'il se termine. –

Répondre

1

Cette requête devrait fonctionner.

select * from (
    select a.state, a.location_id, C, 
     @n:=case when @s=a.state then @n+1 else 1 end counter, 
     @s:=a.state 
    from (select @s:=null) b, (
     select pc.state, b.location_id, COUNT(b.location_id) C 
     from postcode pc 
     inner join location_postcode lp on lp.postcode_id=pc.id 
     inner join business b on b.location_id=lp.location_id 
     group by pc.state, b.location_id 
     order by pc.state, C desc 
    ) a 
) c 
where counter <= 10 

J'utilisé les noms de champs qui devraient être faciles à suivre, en supposant ces tableaux existent des relations indiquées:

business M-1 location 
location M-M postcode 
    (expands to) => location 1-M location_postcode M-1 postcode 
postcode M-1 state 

La requête a beentested avec ces données:

create table business (location_id int); 
insert into business select floor(rand()*10); 
insert into business select floor(rand()*10) from business; 
insert into business select floor(rand()*10) from business; 
insert into business select floor(rand()*10) from business; 
insert into business select floor(rand()*10) from business; 
insert into business select floor(rand()*10) from business; 
insert into business select floor(rand()*10) from business; 
insert into business select floor(rand()*10) from business; 
insert into business select floor(rand()*10) from business; 
insert into business select floor(rand()*10) from business; 
create table location_postcode (location_id int, postcode_id int); 
insert into location_postcode select 1,1; 
insert into location_postcode select 2,1; 
insert into location_postcode select 3,1; 
insert into location_postcode select 4,2; 
insert into location_postcode select 5,1; 
insert into location_postcode select 5,2; 
insert into location_postcode select 6,1; 
insert into location_postcode select 6,3; 
insert into location_postcode select 7,1; 
insert into location_postcode select 7,4; 
insert into location_postcode select 8,5; 
insert into location_postcode select 9,6; 
insert into location_postcode select 10,7; 
create table postcode (id int, state int); 
insert into postcode select 1,1; 
insert into postcode select 2,2; 
insert into postcode select 3,3; 
insert into postcode select 4,4; 
insert into postcode select 5,4; 
insert into postcode select 6,5; 
insert into postcode select 7,5; 

qui doesn Ne créez pas assez d'enregistrements pour un "top 10" de chacun, mais vous verrez comment la colonne COUNTER se positionne correctement. Pour voir travailler contre ce petit jeu de données, d'abord laisser ce filtre il

where counter <= 10 

pour vérifier la colonne COMPTEUR, puis le réduire à quelque chose comme 2 ou 3, pour afficher uniquement le top 2 ou 3 par État.

+0

Connexe: http://explainextended.com/2009/03/05/row-sampling/ –