pensa in termini di set, non iteratori; le istruzioni sql definiscono le proprietà del set di output desiderato (ovvero tabella / relazione)
all venueNames such that for every bandCountry there's a band from that country that plays in venue of that name
il risultato di questo (se ho compreso correttamente le tue intenzioni!) sarebbe l'insieme di luoghi che hanno almeno una band che suona in quella sede. L'iterazione su bandCountry non è necessaria, poiché la relazione PLAYS ha già le informazioni che cerchi, devi solo eliminare i duplicati
quindi in SQL questo sarebbe:
select
distinct venueName
from PLAYS
EDIT: ok, quindi il set attuale desiderato è un po 'più complicato. La domanda posta al database è: quali sedi hanno le bande ospitate dai tutti i paesi?
Quindi, definiamo i criteri di appartenenza per un elemento del set desiderato come obiettivo, quindi lavoriamo all'indietro per popolare il set. Un locale è membro del set di output se ha una riga PLAYS per almeno una banda da ogni paese. Come otteniamo questa informazione?
Un modo è contare i paesi distinti per ogni sede e confrontarli con il conteggio di tutti i paesi. Ma non abbiamo una relazione COUNTRY. Se pensiamo al modello dato per un momento, vediamo che l'insieme di tutti i paesi non è il criterio giusto; è l'insieme di tutti i paesi che hanno almeno una banda. Quindi non abbiamo bisogno di una tabella di paesi (anche se per un modello normalizzato dovremmo averne uno), e non ci interessa il paese della sede, possiamo semplicemente contare i paesi che hanno delle fasce, ad es. (in MS-SQL)
declare @BandCountryCount int
select
@BandCountryCount = COUNT(distinct bandCountry)
from BAND
Possiamo contare i paesi della banda per ogni sede
select
P.venueName, COUNT(distinct B.bandCountry) as VenueBandCountryCount
from PLAYS P
inner join BAND B on B.bandName = P.bandName
e possiamo dividere i due insieme usando una sottoquery
select
venueName
from (
select
P.venueName, COUNT(distinct B.bandCountry) as VenueBandCountryCount
from PLAYS P
inner join BAND B on B.bandName = P.bandName
) X
where X.VenueBandCountryCount = @BandCountryCount
Ora, questa non è la query più carina possibile (GROUP BY e HAVING potrebbero essere considerati una soluzione più "elegante" rispetto alle variabili temporanee e una sottoquery) ma è abbastanza ovvio quello che stiamo cercando, quindi lasceremo a quello per lo scopo dell'OP.
Lo scopo dell'OP era imparare come spostare la mentalità da imperativa a dichiarativa. A tal fine, guarda cosa stava facendo la soluzione imperativa descritta:
for each venueName iterate over all the bandCountries and for each bandCountry get the list of bands that come from it. If none of them play in venueName, go to next venueName. Else, at the end of the bandCountries iteration add venueName to the set of good venueNames
Quali sono i criteri determinanti di cui sopra? Penso che sia:
...If none of them [the set of bands from a particular country] play in venueName...
Questo è un criterio di squalifica . Il processo di pensiero imperativo inizia con un secchio pieno e butta fuori cose che non si adattano ai criteri. Stiamo filtrando dati
.
Va bene per cose semplici, ma aiuta a pensare in termini di costruzione del set di risultati desiderato; quali sono i criteri di qualificazione corrispondenti che consentirebbero invece di riempire il secchio?
- squalificatore: se non ci sono band di un gruppo musicale che gioca in una sede, la sede è squalificata
- (parziale) qualificatore: se almeno una banda di un gruppo musicale gioca in una sede, la sede potrebbe essere ok; continua a controllare il resto della bandCountries
- (completo) qualificatore: se almeno una banda di ogni gruppo musicale gioca in una sede, la sede è qualificata
Il qualificatore finale può essere semplificato usando i conteggi: un gruppo è "soddisfatto" se almeno una banda da lì suona in una sede; il numero di paesi della banda "soddisfatti" per una sede deve essere uguale al numero di paesi della banda per la sede da qualificare.
Ora possiamo ragionare attraverso le relazioni tramite la navigazione:
- inizia con la relazione VENUE [non ce n'è bisogno per la risposta, ma è il punto di partenza concettuale per la navigazione relazionale]
- unisciti a PLAY su venueName
- unisciti a BAND su bandName per ottenere il BandCountry
- non ci interessa il nome della band; seleziona solo venueName e bandCountry
- non ci preoccupiamo delle ridondanti bandCountries; eliminare i duplicati utilizzando DISTRICT o GROUP BY
- ci interessa solo il conteggio di bandCountries distinti, non i nomi
- vogliamo solo luoghi in cui il numero di gruppi distinti è uguale al numero totale di bandCountries
che riporta alla soluzione precedente (o un suo facsimile ragionevole)
SOMMARIO
- teoria degli insiemi
- percorsi di navigazione relazionale
- inclusi vs criteri esclusivi (qualificazione vs squalifica)