SQL Lab: filtres¶
Exercici sql-lab-filters-annex.pdf · PDF
Algú t'allarga una capsa de sabates amb 949 cartes col·leccionables de Pokémon i et demana: quin és el més ràpid de tipus elèctric? No llegeixes en veu alta les 949 cartes. Treus les elèctriques, les ordenes per velocitat, mires la carta de dalt de tot i en llegeixes el nom.
Quatre moviments amb les mans. En una base de dades aquests quatre moviments tenen nom, i junts formen una frase que la base de dades entén. A la lliçó anterior vas connectar Superset a la base de dades de classe i vas pujar la taula pokemon. Ara aprens a demanar-li menys: menys columnes, menys files, en un ordre útil. En el joc de crafting d'aquest mòdul encara ets a l'etapa de farm i loot, però un bon jugador no es duu a casa tot el mapa, només el que necessita la recepta.
Què aprendràs
- Escriure una consulta que retorni només les columnes que necessites, en lloc de
SELECT * - Quedar-te només amb les files que necessites amb
WHERE, fent servir operadors de comparació iAND/OR - Ordenar un resultat amb
ORDER BYi retallar-lo ambLIMITper respondre preguntes de «top N» - Llistar els valors diferents d'una columna amb
DISTINCT - Triar el filtre especial adequat:
LIKE,IN,BETWEENoIS NULL - Desactivar la trampa del dia: per què
= NULLno troba res, i per què una consulta equivocada gairebé mai dona error
Una capsa de sabates amb 949 cartes¶
Una consulta és una pregunta escrita en un llenguatge que la base de dades entén. Aquest llenguatge és SQL (Structured Query Language).
Una sola analogia per a tota la pàgina: la taula pokemon és una capsa de sabates plena de cartes col·leccionables.
| A la base de dades | A la capsa de sabates |
|---|---|
La taula pokemon |
La capsa |
| Una fila | Una carta: un Pokémon |
| Una columna | Una línia impresa a totes les cartes: nom, tipus, atac... |
| Una consulta | El que fas amb les mans per respondre una pregunta |
La capsa conté 949 cartes, i cada carta té 22 línies impreses. En aquesta lliçó en fem servir vuit:
| Columna | Què conté | Exemple (charizard) |
|---|---|---|
pokemon |
El nom, en minúscules | charizard |
type_1 |
Primer tipus | fire |
type_2 |
Segon tipus, en blanc si no n'hi ha | flying |
hp, attack, speed |
Estadístiques base, nombres enters | 78, 84, 100 |
weight |
Pes en quilograms | 90.5 |
generation_id |
Número de generació, de l'1 al 7, en blanc en alguns | 1 |
Obre SQL → SQL Lab a Superset, tria la base de dades Dades classe i l'esquema public, i ja pots escriure. Executes una consulta amb el botó Run o amb Ctrl+Enter.
Per què SQL sembla anglès
El 1974, Donald Chamberlin i Raymond Boyce, dos investigadors d'IBM a San Jose (Califòrnia), van publicar un llenguatge per fer preguntes a les bases de dades. Volien que les persones que no eren programadores el poguessin llegir, així que el van anomenar SEQUEL: Structured English Query Language. El nom ja era una marca registrada d'una empresa d'aviació, així que va perdre les vocals i es va quedar en SQL. Més de cinquanta anys després, encara escrius SELECT, FROM i WHERE exactament com ells.
La forma d'una consulta¶
Una consulta té fins a cinc línies, sempre en aquest ordre. Cadascuna és un moviment de les mans.
| Línia | Amb la capsa de sabates | Regla |
|---|---|---|
SELECT |
Quines línies de la carta llegeixes | Noms de columna, separats per comes. * vol dir totes. |
FROM |
Quina capsa | La taula. |
WHERE |
Quines cartes treus | Una condició que és certa o falsa per a cada fila. |
ORDER BY |
Com ordenes el munt | ASC (primer els petits, per defecte) o DESC (primer els grans). |
LIMIT |
Quantes cartes guardes de dalt | Un número. Sempre l'última. |
flowchart LR
A["<b>FROM</b><br>obre la capsa:<br>949 cartes"] --> B["<b>WHERE</b><br>treu les cartes<br>que vols"]
B --> C["<b>ORDER BY</b><br>ordena el munt"]
C --> D["<b>LIMIT</b><br>guarda les de dalt"]
D --> E["<b>SELECT</b><br>llegeix només les línies<br>que has demanat"]
Aquí tens la pregunta de dalt de tot de la pàgina, escrita com a consulta:
SELECT pokemon, speed
FROM pokemon
WHERE type_1 = 'electric'
ORDER BY speed DESC
LIMIT 1;
| pokemon | speed |
|---|---|
| electrode | 150 |
Una fila, dues columnes. La resposta, i res més. Les seccions següents construeixen aquesta frase línia per línia.
SELECT: llegeix només les línies que necessites¶
SELECTtria les columnes del resultat.FROMindica la taula de la qual surten.
SELECT * FROM pokemon et dona les 22 columnes de les 949 files. Va bé per fer una primera ullada, i no serveix com a resposta. Posa-hi el nom de les columnes:
SELECT pokemon, type_1, attack FROM pokemon;
Continua retornant 949 files, però només tres columnes. Les quatre primeres:
| pokemon | type_1 | attack |
|---|---|---|
| bulbasaur | grass | 49 |
| ivysaur | grass | 62 |
| venusaur | grass | 82 |
| charmander | fire | 52 |
Compte: una coma que falta no dona error
Escriu SELECT pokemon type_1 FROM pokemon (sense coma) i la consulta s'executa. Però obtens una columna, anomenada type_1, plena de noms. Sense la coma, SQL llegeix la segona paraula com un nou nom per a la primera columna. Si et falta una columna que has demanat, compta les comes.
WHERE: treu cartes de la capsa¶
WHEREconserva només les files per a les quals una condició és certa. Una condició és una pregunta de sí o no que es fa a cada fila, una per una.
SELECT pokemon, type_1, attack FROM pokemon WHERE type_1 = 'fire';
Això retorna 59 files: charmander, charmeleon, charizard, vulpix... La condició type_1 = 'fire' s'ha preguntat 949 vegades, i 59 cartes han dit que sí.
El = és un operador de comparació. N'hi ha sis:
| Operador | Significat | Exemple | Files |
|---|---|---|---|
= |
igual a | type_1 = 'fire' |
59 |
<> |
diferent de | type_1 <> 'fire' |
890 |
> |
més gran que | attack > 150 |
19 |
>= |
més gran o igual que | attack >= 150 |
30 |
< |
més petit que | speed < 20 |
17 |
<= |
més petit o igual que | speed <= 20 |
33 |
Dues regles causen la majoria dels errors la primera setmana d'SQL:
| Regla | Correcte | Incorrecte | Què passa |
|---|---|---|---|
| El text va entre cometes simples, els nombres no | type_1 = 'fire', attack > 150 |
type_1 = fire |
Un error: la base de dades pensa que fire és una columna. SQL Lab diu We can't seem to resolve the column "fire". |
| El text distingeix majúscules i minúscules | 'fire' |
'Fire' |
Cap error, i 0 files. |
Compte: zero files no sempre vol dir «no n'hi ha»
WHERE type_1 = 'Fire' no retorna res perquè cap carta diu Fire amb F majúscula. La base de dades no s'ha queixat: ha respost la pregunta que has fet. Abans de creure't un resultat buit, revisa l'ortografia. I les cometes dobles no són una sortida: a PostgreSQL "fire" vol dir nom de columna, 'fire' vol dir text.
Dues condicions: AND, OR¶
Un operador lògic uneix dues condicions.
AND: les dues han de ser certes.OR: n'hi ha prou amb una.
SELECT pokemon, type_1, type_2 FROM pokemon
WHERE type_1 = 'dragon' AND type_2 = 'flying';
Sis files: dragonite, altaria, salamence, rayquaza i les formes Mega dels dos últims. Canvia AND per OR i pregunta alguna cosa més àmplia:
SELECT pokemon, type_1, type_2 FROM pokemon
WHERE type_1 = 'dragon' OR type_2 = 'dragon';
61 files: tots els Pokémon que són de tipus drac en qualsevol de les dues ranures. AND fa un resultat més petit, OR el fa més gran.
ORDER BY i LIMIT: ordena el munt, guarda el de dalt¶
ORDER BYordena el resultat per una columna.LIMITconserva només les primeres files.
SELECT pokemon, type_1, attack FROM pokemon
WHERE attack > 150
ORDER BY attack DESC;
19 files, primer els més forts. Juntes, aquestes dues línies responen qualsevol pregunta de «top N»:
SELECT pokemon, attack FROM pokemon ORDER BY attack DESC LIMIT 5;
| pokemon | attack |
|---|---|
| mewtwo-mega-x | 190 |
| heracross-mega | 185 |
| kartana | 181 |
| deoxys-attack | 180 |
| groudon-primal | 180 |
Mira les dues últimes files. Tres Pokémon tenen un atac de 180: deoxys-attack, groudon-primal i rayquaza-mega. Només n'hi caben dos en un top 5, i la base de dades ha triat com ha volgut. La teva pantalla pot mostrar un altre parell, i tots dos tindríeu raó.
Compte: LIMIT talla els empats arbitràriament
Quan diverses files comparteixen el valor pel qual ordenes, el seu ordre no està definit. Per decidir-lo tu, afegeix una segona columna d'ordenació: ORDER BY attack DESC, pokemon ordena els empats pel nom. I recorda que LIMIT 5 tot sol, sense ORDER BY, et dona unes cinc files qualssevol, no les cinc millors.
DISTINCT: conèixer una columna¶
DISTINCTelimina les files repetides del resultat, de manera que cada valor diferent apareix una sola vegada.
Abans de filtrar per una columna, esbrina quins valors pot tenir:
SELECT DISTINCT type_1 FROM pokemon ORDER BY type_1;
18 files, de bug a water: els 18 tipus, cadascun una vegada. Ara saps que el tipus s'escriu fire, no Fire ni FIRE. DISTINCT és el remei de la trampa de zero files de dalt.
Quatre filtres especials¶
Els operadors de comparació cobreixen els nombres i el text exacte. Quatre filtres més cobreixen la resta.
| Filtre | Amb la capsa de sabates | Exemple | Files |
|---|---|---|---|
LIKE |
Cartes amb un text que s'assembla a un patró | pokemon LIKE 'pika%' |
13 |
IN |
Cartes amb un valor que és a la meva llista | type_1 IN ('fire', 'water', 'grass') |
269 |
BETWEEN |
Cartes dins d'un interval, amb els dos extrems inclosos | speed BETWEEN 100 AND 120 |
126 |
IS NULL |
Cartes on aquella línia és en blanc | type_2 IS NULL |
439 |
LIKE fa servir dos comodins, símbols que representen text que no coneixes: % és qualsevol text (també cap), _ és exactament un caràcter. 'pika%' vol dir «comença per pika»: pikachu i les seves dotze disfresses (pikachu-rock-star, pikachu-phd...).
IN és una forma abreujada de diversos OR: type_1 = 'fire' OR type_1 = 'water' OR type_1 = 'grass'. Posa-hi NOT davant per al contrari: type_1 NOT IN ('fire', 'water', 'grass') retorna 680 files, i 269 + 680 = 949. Ningú s'ha perdut.
BETWEEN inclou els dos extrems: speed BETWEEN 100 AND 120 és el mateix que speed >= 100 AND speed <= 120. Tots dos retornen 126. Amb > i < n'obtindries 83, perquè els Pokémon que tenen exactament 100 i exactament 120 queden fora.
IS NULL troba els blancs: els 439 Pokémon que només tenen un tipus. IS NOT NULL troba els altres 510. Aquest es mereix una secció pròpia.
NULL: la línia en blanc de la carta¶
NULLvol dir desconegut: aquí no hi ha res escrit. No és zero, i no és un text buit.
Executa això i compta:
SELECT pokemon, type_1, type_2 FROM pokemon WHERE type_2 = NULL;
0 files. Cap error. Han desaparegut els 439 Pokémon d'un sol tipus?
No. Pensa en dues cartes amb una línia en blanc. Els dos blancs són iguals? No ho pots saber: potser hi hauria d'haver alguna cosa, i no saps què. Per tant, quan compares qualsevol cosa amb NULL, la base de dades respon «desconegut», i WHERE només conserva les files on la resposta és un sí clar.
| Tu escrius | La base de dades respon | Files |
|---|---|---|
type_2 = NULL |
«desconegut» per a totes les files | 0 |
type_2 = '' |
«no»: un blanc tampoc no és un text buit | 0 |
type_2 IS NULL |
«sí» per als que són en blanc | 439 |
type_2 IS NOT NULL |
«sí» per als que tenen valor | 510 |
Per això SQL té una pregunta a part per als blancs. Recorda-ho: IS NULL, mai = NULL.
Respostes errònies que semblen correctes¶
Totes les trampes d'aquesta pàgina tenen una cosa en comú: cap no dona error. La base de dades fa exactament el que has escrit i retorna un nombre creïble.
| Trampa | Què obtens | Lliçó |
|---|---|---|
LIKE '%mega%' per comptar les evolucions Mega |
50 en lloc de 48: meganium i yanmega s'hi colen |
Un patró coincideix amb el text, no amb el significat. Fes servir '%-mega%' i mira les files, no només el recompte. |
= NULL |
0 files | Els blancs necessiten IS NULL. |
Barrejar AND i OR sense parèntesis |
79 en lloc de 34 | AND s'aplica primer, com × abans de +. Fes servir parèntesis. |
LIMIT amb un empat |
Un top 5 diferent del del teu company | Afegeix una segona columna d'ordenació. |
La tercera, amb detall. Vols els Pokémon de foc o d'aigua amb un atac superior a 100:
SELECT COUNT(*) FROM pokemon
WHERE type_1 = 'fire' OR type_1 = 'water' AND attack > 100;
79. La base de dades ho ha llegit com «tots els Pokémon de foc (59), més els d'aigua amb atac superior a 100 (20)». Posa parèntesis al voltant de la part de l'OR:
SELECT COUNT(*) FROM pokemon
WHERE (type_1 = 'fire' OR type_1 = 'water') AND attack > 100;
34. Les mateixes paraules, una altra pregunta. (COUNT(*) compta files; és l'entrada de la lliçó següent.)
Prova-ho: la cacera de la Pokédex¶
Obre SQL Lab i respon cada pregunta amb una sola consulta. Escriu primer la consulta, després obre la solució i compara el teu número.
| N. | Pregunta |
|---|---|
| 1 | Nom i pes dels tres Pokémon més pesats. |
| 2 | Quantes evolucions Mega hi ha? El seu nom conté -mega. |
| 3 | Quants Pokémon no tenen generació (generation_id)? |
| 4 | Elèctrics, d'un sol tipus, amb velocitat de 100 a 120: noms, primer el més ràpid. |
| 5 | Nom i atac dels Pokémon d'un sol tipus amb un atac superior a 150, primer el més fort. |
Solucions
1 — SELECT pokemon, weight FROM pokemon ORDER BY weight DESC LIMIT 3; → celesteela i cosmoem (999.9), després groudon-primal (999.7).
2 — SELECT COUNT(*) FROM pokemon WHERE pokemon LIKE '%-mega%'; → 48.
3 — SELECT COUNT(*) FROM pokemon WHERE generation_id IS NULL; → 147. Tingues present aquest número: torna a les dues lliçons següents.
4 — SELECT pokemon, speed FROM pokemon WHERE type_1 = 'electric' AND type_2 IS NULL AND speed BETWEEN 100 AND 120 ORDER BY speed DESC; → 6 files, de zebstrika (116) fins a voltorb (100).
5 — SELECT pokemon, attack FROM pokemon WHERE type_2 IS NULL AND attack > 150 ORDER BY attack DESC; → 5 files, la primera deoxys-attack (180).
Si SQL Lab respon amb un quadre vermell, llegeix el missatge: normalment diu la paraula amb què ha ensopegat. Mira just abans d'aquesta paraula per veure si falta una cometa o hi ha una paraula clau mal escrita. I executa una sola consulta cada vegada: si n'hi ha diverses a l'editor, només veus el resultat de l'última.
Idees clau¶
- Una consulta té una forma fixa:
SELECT(columnes) ·FROM(taula) ·WHERE(files) ·ORDER BY(ordre) ·LIMIT(retall). WHEREpregunta una condició a cada fila. El text va entre cometes simples i distingeix majúscules i minúscules; els nombres no porten cometes.ANDestreny,OReixampla.ANDs'aplica primer: quan els barrejes, fes servir parèntesis.ORDER BY ... DESC LIMIT nrespon «top N», peròLIMITtalla els empats arbitràriament.DISTINCTmostra els valors diferents d'una columna: fes-lo servir abans de filtrar.LIKEcoincideix amb un patró,INamb una llista,BETWEENamb un interval amb els dos extrems,IS NULLamb un blanc.= NULLno és mai cert.- Els errors perillosos no donen error. Retornen un nombre que sembla correcte.
Comprovació ràpida¶
1. Quina consulta retorna només el nom i l'atac de cada Pokémon?
-
SELECT * FROM pokemon; -
SELECT pokemon, attack FROM pokemon; -
SELECT pokemon attack FROM pokemon; -
FROM pokemon SELECT pokemon, attack;
SELECT llista les columnes, separades per comes, i va abans de FROM. * retorna les 22 columnes. Sense la coma, la consulta s'executa però canvia el nom de la primera columna: una columna en lloc de dues.
2. WHERE type_1 = 'Fire' retorna 0 files i cap error. Quin és el motiu més probable?
- La taula no té cap Pokémon de foc
- El text ha d'anar entre cometes dobles
- El text distingeix majúscules i minúscules, i la taula desa
fireen minúscules -
WHEREno pot comparar text
La base de dades ha comparat cada carta amb Fire i cap no hi coincidia, perquè el text distingeix majúscules i minúscules. Zero files no prova que «no n'hi ha»: executa SELECT DISTINCT type_1 per veure com s'escriuen realment els valors.
3. Què retorna SELECT pokemon, speed FROM pokemon ORDER BY speed DESC LIMIT 3;?
- Tres Pokémon qualssevol
- Els tres Pokémon més lents
- Els tres Pokémon més ràpids
- Tots els Pokémon amb una velocitat superior a 3
ORDER BY speed DESC ordena el munt amb la velocitat més gran a dalt, i LIMIT 3 guarda les tres primeres cartes. Sense ORDER BY, LIMIT 3 donaria unes tres files qualssevol.
4. Per què WHERE type_2 = NULL retorna 0 files?
- Perquè tots els Pokémon tenen un segon tipus
- Perquè
NULLs'ha d'escriure entre cometes - Perquè NULL vol dir desconegut, i per tant una comparació amb ell no és mai un sí clar
- Perquè
=només funciona amb nombres
NULL no és un valor: vol dir «aquí no hi ha res escrit». Comparar-hi dona «desconegut», i WHERE només conserva les files que responen sí. La pregunta correcta és type_2 IS NULL, que troba 439 files.
5. Comptes les evolucions Mega amb LIKE '%mega%' i en surten 50. El nombre real és 48. Què ha passat?
-
LIKEignora la primera i l'última lletra d'un nom - El patró també coincideix amb
meganiumiyanmega, que no són evolucions Mega -
%només coincideix amb un caràcter - Dues evolucions Mega estan desades dues vegades
Un patró coincideix amb el text, no amb el significat. %mega% vol dir «conté mega en qualsevol lloc». Les evolucions Mega s'escriuen amb un guionet, així que '%-mega%' retorna els 48 correctes. Mira sempre les files, no només el recompte.
6. WHERE type_1 = 'fire' OR type_1 = 'water' AND attack > 100 retorna 79 files. Amb parèntesis al voltant de la part de l'OR en retorna 34. Per què?
- Els parèntesis fan la consulta més ràpida, i per això arriben menys files
-
ORs'aplica primer, així que la primera versió ignora l'atac -
ANDs'aplica primer: sense parèntesis, la condició de l'atac només s'aplica a l'aigua - La primera versió compta alguns Pokémon dues vegades
AND s'aplica abans que OR, com × abans de +. Sense parèntesis obtens els 59 Pokémon de foc més els 20 d'aigua forts. Amb parèntesis, la condició de l'atac s'aplica als dos tipus: 34.
7. Una taula songs té les columnes title, artist, year i streams. Tria les dues consultes que retornen correctament les cinc cançons més reproduïdes del 2020 al 2023.
-
SELECT title, streams FROM songs WHERE year BETWEEN 2020 AND 2023 ORDER BY streams DESC LIMIT 5; -
SELECT title, streams FROM songs WHERE year >= 2020 AND year <= 2023 ORDER BY streams DESC LIMIT 5; -
SELECT title, streams FROM songs WHERE year BETWEEN 2020 AND 2023 LIMIT 5; -
SELECT title, streams FROM songs WHERE year > 2020 AND year < 2023 ORDER BY streams DESC LIMIT 5;
BETWEEN inclou els dos extrems, de manera que equival a >= i <=. La tercera consulta no té ORDER BY: retorna cinc cançons qualssevol. La quarta fa servir > i <, que descarta sense avisar el 2020 i el 2023.
Fins ara cada resposta era una llista de cartes. I si la pregunta és «quants Pokémon de foc hi ha?», i després el mateix per als 18 tipus alhora? Tot seguit: SQL Lab: grups.