Des de la primera lliçó del mòdul venim repetint el mateix advertiment: el conjunt de resultats no té ordre garantit. Ha arribat el moment de prendre'n el control. ORDER BY és l'única manera que una consulta retorni les files en un ordre concret, i encara que sembli la clàusula més senzilla de SQL, amaga mitja dotzena de detalls que separen una consulta que funciona per casualitat d'una que funciona sempre: què passa amb els empats, on van els nuls, per què una lletra accentuada pot aparèixer en un lloc estrany, i per què ordenar pel número de columna és una bomba de rellotgeria.
Contingut
- Sense
ORDER BYno hi ha ordre garantit ASCiDESC- Ordenar per diverses columnes i resoldre empats
- Ordenar per àlies, per expressió i per posició ordinal
- Els nuls:
NULLS FIRSTiNULLS LAST - Ordenar text: col·lació i accents
- Ordenar dates
ORDER BYa l'ordre lògic d'execució- Errors habituals i consells
- Exercicis
- Conclusió
- Sense
ORDER BY no hi ha ordre garantit
ORDER BY no hi ha ordre garantitFem-ho explícit d'una vegada. Aquesta consulta:
retorna, avui, al teu equip, els productes de l'1 al 20. I això et dona una falsa sensació de seguretat, perquè l'estàndard SQL no promet cap ordre quan no hi ha ORDER BY, i PostgreSQL tampoc. El que veus és l'ordre en què el motor va trobar les files en recórrer el fitxer de dades.
Circumstàncies reals en què aquest ordre canvia sense que tu toquis la consulta:
| Situació | Què passa |
|---|---|
S'actualitza una fila amb UPDATE |
PostgreSQL escriu una versió nova de la fila al final de la taula; aquesta fila passa a retornar-se l'última |
| L'optimitzador decideix fer servir un índex | Les files surten en l'ordre de l'índex, no en el físic |
| La taula és gran i s'activa el paral·lelisme | Diversos processos llegeixen trossos diferents i lliuren resultats entrellaçats |
S'executa VACUUM FULL o es reconstrueix la taula |
L'ordre físic canvia del tot |
S'afegeix una taula amb JOIN (mòdul 3) |
L'ordre depèn de l'algorisme d'unió triat |
Pots comprovar el primer cas tu mateix, si t'atreveixes a modificar les dades (recorda que l'script de 01-06 és idempotent i el pots recarregar):
El producte 1 apareixerà ara al final de la llista. Res no ha fallat, res no avisa: simplement l'ordre mai no va estar garantit.
Regla absoluta: si l'ordre de les files importa per al teu informe, la teva aplicació o la teva paginació, escriu
ORDER BY. No hi ha dreceres, no hi ha excepcions, i "és que sempre surt bé" no és cap argument.
ASC i DESC
ASC i DESCORDER BY s'escriu al final de la consulta i indica per quina columna ordenar i en quin sentit:
| id | nom | preu |
|---|---|---|
| 15 | Te verd matcha cerimonial 30 g | 22.00 |
| 6 | Crema facial d'àloe vera 50 ml | 18.90 |
| 20 | Càpsules d'espirulina 120 u | 16.40 |
| 8 | Oli corporal d'ametlles 200 ml | 14.25 |
| 13 | Espelmes de cera de soja (pack 2) | 13.75 |
| 1 | Oli d'oliva verge extra 500 ml | 12.50 |
| 10 | Detergent ecològic concentrat 1 L | 11.20 |
| 12 | Bosses reutilitzables de cotó (pack 5) | 9.90 |
| 3 | Mel de tarongina crua 500 g | 9.75 |
| 7 | Xampú sòlid de romaní 80 g | 8.40 |
| 19 | Desodorant natural en barra 50 g | 7.80 |
| 11 | Fregall vegetal de lufa (pack 3) | 5.50 |
| 17 | Suc de taronja premsat en fred 1 L | 5.40 |
| 16 | Kombutxa de gingebre 750 ml | 4.95 |
| 9 | Bàlsam labial de calèndula 15 ml | 4.60 |
| 2 | Arròs integral ecològic 1 kg | 3.90 |
| 18 | Raspall de dents de bambú | 3.50 |
| 14 | Infusió de camamilla ecològica 20 u | 3.25 |
| 4 | Pasta d'espelta 500 g | 2.80 |
| 5 | Tomàquet triturat ecològic 400 g | 1.95 |
El catàleg complet de més car a més barat. Ja tens aquí una resposta de negoci: el matcha és el producte més car (22.00 €) i el tomàquet triturat el més barat (1.95 €).
| Paraula clau | Significat | És el valor per defecte? |
|---|---|---|
ASC |
Ascendent: de menor a major, d'A a Z, de data antiga a recent | Sí |
DESC |
Descendent: al revés | No |
Com que ASC és el valor per defecte, aquestes dues són idèntiques:
Escriure ASC explícitament no és obligatori, però en consultes amb diverses columnes i sentits barrejats ajuda molt a la lectura.
- Ordenar per diverses columnes i resoldre empats
Quan dues files tenen el mateix valor a la columna d'ordenació, el seu ordre relatiu no està definit. És el mateix problema de la secció 1, en petit.
Les cinc files de la categoria 1 surten juntes, sí, però en quin ordre entre elles? El que el motor tingui a bé. Per fixar-lo s'afegeixen més columnes a l'ORDER BY, separades per comes: la segona desempata la primera, la tercera desempata la segona, i així successivament. Cada columna pot portar el seu propi ASC o DESC.
| id | nom | categoria_id | preu |
|---|---|---|---|
| 1 | Oli d'oliva verge extra 500 ml | 1 | 12.50 |
| 3 | Mel de tarongina crua 500 g | 1 | 9.75 |
| 2 | Arròs integral ecològic 1 kg | 1 | 3.90 |
| 4 | Pasta d'espelta 500 g | 1 | 2.80 |
| 5 | Tomàquet triturat ecològic 400 g | 1 | 1.95 |
| 6 | Crema facial d'àloe vera 50 ml | 2 | 18.90 |
| 8 | Oli corporal d'ametlles 200 ml | 2 | 14.25 |
| 7 | Xampú sòlid de romaní 80 g | 2 | 8.40 |
| 9 | Bàlsam labial de calèndula 15 ml | 2 | 4.60 |
| 13 | Espelmes de cera de soja (pack 2) | 3 | 13.75 |
| 10 | Detergent ecològic concentrat 1 L | 3 | 11.20 |
| 12 | Bosses reutilitzables de cotó (pack 5) | 3 | 9.90 |
| 11 | Fregall vegetal de lufa (pack 3) | 3 | 5.50 |
| 15 | Te verd matcha cerimonial 30 g | 4 | 22.00 |
| 17 | Suc de taronja premsat en fred 1 L | 4 | 5.40 |
| 16 | Kombutxa de gingebre 750 ml | 4 | 4.95 |
| 14 | Infusió de camamilla ecològica 20 u | 4 | 3.25 |
| 19 | Desodorant natural en barra 50 g | 5 | 7.80 |
| 18 | Raspall de dents de bambú | 5 | 3.50 |
| 20 | Càpsules d'espirulina 120 u | 6 | 16.40 |
Un catàleg perfectament presentable: agrupat per categoria i, dins de cadascuna, de l'article més car al més barat.
Tres columnes, amb dades de clients:
| id | nom | cognoms | ciutat | pais |
|---|---|---|---|---|
| 11 | Elena | Navarro Puig | Alacant | Espanya |
| 5 | Ana | Belmonte Roca | Barcelona | Espanya |
| 13 | Núria | Bosch Ferrer | Barcelona | Espanya |
| 3 | Marta | Sanchis Gil | Castelló | Espanya |
| 4 | Javier | Ortega Ruiz | Madrid | Espanya |
| 14 | Hugo | Iglesias Pardo | Saragossa | Espanya |
| 12 | Diego | Ramos Herrera | Sevilla | Espanya |
| 15 | Inés | Carrasco Vega | València | Espanya |
| 2 | Carlos | Ferrer Ibáñez | València | Espanya |
| 6 | Pau | Llorens Vidal | València | Espanya |
| 1 | Lucía | Martínez Soler | València | Espanya |
| 9 | Camille | Dubois | Lió | França |
| 10 | Julien | Moreau | París | França |
| 7 | Sofia | Moreira Costa | Lisboa | Portugal |
| 8 | Tiago | Almeida Nunes | Porto | Portugal |
Llegeix-ho de fora cap endins: primer tots els espanyols, dins d'ells les ciutats en ordre alfabètic, i dins de cada ciutat els cognoms. Els dos clients de Barcelona queden ordenats per cognom (Belmonte abans que Bosch) i els quatre de València també (Carrasco, Ferrer, Llorens, Martínez).
Consell professional: acaba sempre l'
ORDER BYamb una columna única. Afegir, idcom a últim criteri garanteix que l'ordre sigui determinista: la mateixa consulta retorna exactament el mateix ordre avui i d'aquí a un any. És imprescindible per a la paginació, que veuràs a 02-06, i perquè les proves automatitzades no fallin aleatòriament.
- Ordenar per àlies, per expressió i per posició ordinal
4.1. Per àlies
Aquí es cobra el deute de 02-02: com que ORDER BY s'executa després de SELECT, l'àlies ja existeix i es pot fer servir.
| nom | preu | cost | marge |
|---|---|---|---|
| Te verd matcha cerimonial 30 g | 22.00 | 12.50 | 9.50 |
| Crema facial d'àloe vera 50 ml | 18.90 | 9.50 | 9.40 |
| Càpsules d'espirulina 120 u | 16.40 | 8.70 | 7.70 |
| Oli corporal d'ametlles 200 ml | 14.25 | 7.10 | 7.15 |
| Espelmes de cera de soja (pack 2) | 13.75 | 6.90 | 6.85 |
| Bosses reutilitzables de cotó (pack 5) | 9.90 | 4.30 | 5.60 |
| Detergent ecològic concentrat 1 L | 11.20 | 6.00 | 5.20 |
| Xampú sòlid de romaní 80 g | 8.40 | 3.60 | 4.80 |
| Oli d'oliva verge extra 500 ml | 12.50 | 7.80 | 4.70 |
| Desodorant natural en barra 50 g | 7.80 | 3.30 | 4.50 |
| Mel de tarongina crua 500 g | 9.75 | 5.40 | 4.35 |
| Fregall vegetal de lufa (pack 3) | 5.50 | 2.20 | 3.30 |
| Bàlsam labial de calèndula 15 ml | 4.60 | 1.80 | 2.80 |
| Suc de taronja premsat en fred 1 L | 5.40 | 2.60 | 2.80 |
| Kombutxa de gingebre 750 ml | 4.95 | 2.30 | 2.65 |
| Raspall de dents de bambú | 3.50 | 1.20 | 2.30 |
| Infusió de camamilla ecològica 20 u | 3.25 | 1.40 | 1.85 |
| Arròs integral ecològic 1 kg | 3.90 | 2.10 | 1.80 |
| Pasta d'espelta 500 g | 2.80 | 1.35 | 1.45 |
| Tomàquet triturat ecològic 400 g | 1.95 | 0.90 | 1.05 |
Observa l'empat real a les files 13 i 14: el bàlsam labial (producte 9) i el suc de taronja (producte 17) deixen exactament 2.80 € de marge. El , id final és el que fa que el 9 surti abans que el 17 de manera reproduïble; sense ell, l'ordre entre tots dos seria cosa del motor.
I fixa't que hem ordenat per id sense projectar-lo. Això és perfectament legal (a diferència del que passava amb SELECT DISTINCT a 02-04): ORDER BY pot fer servir qualsevol columna de les taules del FROM, aparegui o no al resultat.
4.2. Per expressió
També pots repetir l'expressió completa en comptes de fer servir l'àlies. El resultat és idèntic:
| nom | preu | cost |
|---|---|---|
| Raspall de dents de bambú | 3.50 | 1.20 |
| Bàlsam labial de calèndula 15 ml | 4.60 | 1.80 |
| Fregall vegetal de lufa (pack 3) | 5.50 | 2.20 |
| Desodorant natural en barra 50 g | 7.80 | 3.30 |
| Xampú sòlid de romaní 80 g | 8.40 | 3.60 |
(5 primeres de 20 files.)
Aquest és el rànquing per marge percentual, no per marge absolut, i dona un resultat molt diferent: el raspall de bambú, que només deixa 2.30 € per unitat, és el producte que més percentatge de marge aporta (65.7 %). Ordenar per la mètrica correcta importa tant com calcular-la bé.
4.3. Per posició ordinal
SQL permet ordenar pel número de columna dins del SELECT:
Equival a ORDER BY preu DESC, perquè preu és la segona columna de la llista.
Funciona, és estàndard i està molt estès en consultes ràpides i exploratòries. Però és fràgil i no ha d'arribar a codi que es desi:
| Risc | Escenari |
|---|---|
Algú afegeix una columna al principi del SELECT |
ORDER BY 2 passa a ordenar per una altra cosa, sense error |
| Algú reordena la llista de columnes | Igual |
| Qui llegeixi la consulta | Ha de comptar columnes per entendre què fa |
Combinat amb SELECT * |
El significat depèn de la definició de la taula, que pot canviar |
Regla del curs:
ORDER BY 2per explorar apsql; nom de columna o àlies en qualsevol consulta que vulguis desar.
Un matís que sorprèn: l'ordinal només funciona a ORDER BY (i a GROUP BY, mòdul 4). A WHERE no significa res, i ORDER BY 2 + 1 no ordena per la tercera columna: PostgreSQL entén que allà hi ha una expressió constant (el número 3) i la ignora com a criteri d'ordenació, perquè val el mateix a totes les files.
- Els nuls:
NULLS FIRST i NULLS LAST
NULLS FIRST i NULLS LASTUn NULL no és més gran ni més petit que res: és desconegut. Però per ordenar cal col·locar-lo en algun lloc, així que cada motor pren una decisió arbitrària. PostgreSQL considera que NULL és el valor més gran.
D'aquí en surten els seus valors per defecte:
| Sentit | On van els nuls a PostgreSQL |
|---|---|
ASC |
Al final (equival a NULLS LAST) |
DESC |
Al principi (equival a NULLS FIRST) |
Vegem-ho amb comandes.empleat_id, que és NULL a les deu comandes que van entrar per la web:
| id | client_id | empleat_id | estat |
|---|---|---|---|
| 2 | 2 | 4 | lliurat |
| 6 | 5 | 4 | cancellat |
| 10 | 9 | 4 | lliurat |
| 16 | 4 | 4 | enviat |
| 4 | 4 | 5 | lliurat |
| 8 | 7 | 5 | lliurat |
| 12 | 10 | 5 | lliurat |
| 18 | 5 | 5 | pagat |
| 14 | 12 | 6 | lliurat |
| 20 | 9 | 6 | pendent |
| 1 | 1 | (null) | lliurat |
| 3 | 3 | (null) | lliurat |
| 5 | 1 | (null) | lliurat |
| 7 | 6 | (null) | lliurat |
| 9 | 8 | (null) | lliurat |
| 11 | 2 | (null) | lliurat |
| 13 | 11 | (null) | lliurat |
| 15 | 1 | (null) | lliurat |
| 17 | 7 | (null) | enviat |
| 19 | 6 | (null) | lliurat |
Les deu comandes gestionades per comercials (4, 5 i 6) primer, i les deu comandes web al final. Si vols els nuls a dalt, ho demanes explícitament:
Ara les comandes 1, 3, 5, 7, 9, 11, 13, 15, 17 i 19 encapçalen la llista, seguides per les del comercial 4, després el 5 i després el 6.
El mateix amb clients.referit_per_id:
| id | nom | cognoms | referit_per_id |
|---|---|---|---|
| 1 | Lucía | Martínez Soler | (null) |
| 4 | Javier | Ortega Ruiz | (null) |
| 6 | Pau | Llorens Vidal | (null) |
| 7 | Sofia | Moreira Costa | (null) |
| 9 | Camille | Dubois | (null) |
| 12 | Diego | Ramos Herrera | (null) |
| 14 | Hugo | Iglesias Pardo | (null) |
| 2 | Carlos | Ferrer Ibáñez | 1 |
| 3 | Marta | Sanchis Gil | 1 |
| 15 | Inés | Carrasco Vega | 1 |
| 5 | Ana | Belmonte Roca | 2 |
| 13 | Núria | Bosch Ferrer | 5 |
| 11 | Elena | Navarro Puig | 6 |
| 8 | Tiago | Almeida Nunes | 7 |
| 10 | Julien | Moreau | 9 |
Els set clients que van arribar pel seu compte a dalt, i a sota els vuit que van venir per recomanació, agrupats per qui els va portar: la Lucía n'ha portat tres (el Carlos, la Marta i la Inés), cosa que la converteix en la millor prescriptora de BotigaVerda.
5.1. Comparativa entre motors
Aquesta és una de les diferències de dialecte que més maldecaps dona en migrar consultes:
| Motor | NULL es considera |
ORDER BY col ASC |
ORDER BY col DESC |
Admet NULLS FIRST/LAST? |
|---|---|---|---|---|
| PostgreSQL | El més gran | Nuls al final | Nuls al principi | Sí |
| Oracle | El més gran | Nuls al final | Nuls al principi | Sí |
| MySQL / MariaDB | El més petit | Nuls al principi | Nuls al final | No |
| SQLite | El més petit | Nuls al principi | Nuls al final | Sí (des de 3.30) |
| SQL Server | El més petit | Nuls al principi | Nuls al final | No |
És a dir: la mateixa consulta ORDER BY empleat_id posa les deu comandes web al final a PostgreSQL i al principi a MySQL. Si el teu informe mostra les deu primeres files, veuràs dades completament diferents.
Als motors que no admeten NULLS FIRST/LAST s'emula amb una columna auxiliar d'ordenació, aprofitant que un booleà ordena false abans que true:
-- Portable a MySQL i SQL Server: nuls al final encara que sigui ASC
ORDER BY (empleat_id IS NULL), empleat_id;L'expressió empleat_id IS NULL val false (0) per a les files amb valor i true (1) per a les nul·les, així que ordenar-hi empeny els nuls al final. És un truc que convé tenir a la butxaca.
- Ordenar text: col·lació i accents
Ordenar números o dates és aritmètica. Ordenar text és cultura, i aquí les coses es posen interessants.
Una col·lació (collation) és el conjunt de regles que decideix si 'Àlber' va abans o després de 'Bosc', si 'cafè' i 'CAFE' es consideren iguals en ordenar, i si la ç compta com una c o com una lletra a part. Cada base de dades PostgreSQL es crea amb una col·lació per defecte, que pots consultar:
Els dos escenaris habituals:
| Col·lació | Com ordena | Efecte sobre els accents i la ç |
|---|---|---|
C o POSIX |
Per valor de byte en UTF-8 | Les majúscules van abans que totes les minúscules, i les lletres accentuades i la ç van després de tota la A-Z. Àlber acaba després de Zulema |
ca_ES.UTF-8, en_US.UTF-8, ICU |
Regles lingüístiques | La À s'ordena com una A i la ç com una c; els accents només desempaten; les majúscules s'intercalen amb les minúscules |
Ho pots comprovar a la teva instal·lació amb una comparació directa:
SELECT 'Àlber' < 'Bosc' AS collacio_de_la_base,
('Àlber' COLLATE "C") < ('Bosc' COLLATE "C") AS collacio_c;En una base creada amb col·lació lingüística (l'habitual):
| collacio_de_la_base | collacio_c |
|---|---|
| true | false |
'Àlber' < 'Bosc' és cert amb regles lingüístiques —la À es tracta com una A, i la A va abans que la B— i fals amb la col·lació C, perquè en UTF-8 la À es codifica amb dos bytes que comencen per 0xC3, molt per damunt del 0x42 de la B. La mateixa consulta, dos ordres diferents, segons com s'hagi creat la base de dades.
Per forçar una col·lació concreta en una consulta:
| id | nom | cognoms | ciutat |
|---|---|---|---|
| 8 | Tiago | Almeida Nunes | Porto |
| 5 | Ana | Belmonte Roca | Barcelona |
| 13 | Núria | Bosch Ferrer | Barcelona |
| 15 | Inés | Carrasco Vega | València |
| 9 | Camille | Dubois | Lió |
| 2 | Carlos | Ferrer Ibáñez | València |
| 14 | Hugo | Iglesias Pardo | Saragossa |
| 6 | Pau | Llorens Vidal | València |
| 1 | Lucía | Martínez Soler | València |
| 10 | Julien | Moreau | París |
| 7 | Sofia | Moreira Costa | Lisboa |
| 11 | Elena | Navarro Puig | Alacant |
| 4 | Javier | Ortega Ruiz | Madrid |
| 12 | Diego | Ramos Herrera | Sevilla |
| 3 | Marta | Sanchis Gil | Castelló |
COLLATE "ca-ES-x-icu" aplica les regles del català segons la biblioteca ICU, que PostgreSQL inclou des de la versió 10. Fixa't en Moreau abans que Moreira: comparteixen More, i després la a va abans que la i.
Pots veure les col·lacions disponibles al teu servidor amb:
Notes pràctiques sobre col·lacions:
- La col·lació afecta també
WHERE,LIKEi els índexs. Un índex creat amb una col·lació no serveix per ordenar amb una altra (mòdul 8). - Ordenar amb
COLLATEexplícit és més lent que fer servir la col·lació per defecte, perquè impedeix reutilitzar l'índex. - Canviar la col·lació d'una base existent és una operació major: cal reconstruir tots els índexs de text. És una decisió que es pren en crear la base de dades.
- Si necessites un ordre "sense accents ni majúscules", la via moderna a PostgreSQL són les col·lacions no deterministes (
CREATE COLLATION ... deterministic = false); la via clàssica és ordenar perLOWER(unaccent(columna)), amb funcions del mòdul 6.
- Ordenar dates
Les dates ordenen cronològicament, sense sorpreses, perquè el tipus DATE és un número per dins:
SELECT id, client_id, data_comanda, estat, despeses_enviament
FROM comandes
ORDER BY data_comanda DESC;| id | client_id | data_comanda | estat | despeses_enviament |
|---|---|---|---|---|
| 20 | 9 | 2026-02-21 | pendent | 12.50 |
| 19 | 6 | 2026-02-09 | pagat | 4.95 |
| 18 | 5 | 2026-01-27 | pagat | 4.95 |
| 17 | 7 | 2026-01-13 | enviat | 9.90 |
| 16 | 4 | 2025-12-19 | enviat | 4.95 |
| 15 | 1 | 2025-12-02 | lliurat | 0.00 |
| 14 | 12 | 2025-11-14 | lliurat | 4.95 |
| 13 | 11 | 2025-10-22 | lliurat | 4.95 |
| 12 | 10 | 2025-10-01 | lliurat | 12.50 |
| 11 | 2 | 2025-09-09 | lliurat | 0.00 |
(10 primeres de 20 files.)
Les comandes de la més recent a la més antiga: l'ordre natural de qualsevol safata de treball. En aquest conjunt de dades la data creix amb l'id, així que ordenar per data descendent coincideix amb ordenar per id descendent; en una base real això no ha de complir-se per força (una comanda es pot gravar amb data retroactiva) i confiar-hi seria un error.
Avís important: això funciona perquè les columnes són de tipus DATE. Si una data estigués desada com a text, l'ordre seria alfabètic:
| Format desat com a text | Ordre alfabètic resultant |
|---|---|
'2026-01-13' (ISO) |
Coincideix amb el cronològic, per casualitat afortunada |
'13/01/2026' (europeu) |
Desastrós: el 13 de gener del 2026 aniria al costat del 13 de març del 1998 |
És una raó més per desar les dates en columnes de tipus data, com es va decidir a 01-04 i 01-06.
ORDER BY a l'ordre lògic d'execució
ORDER BY a l'ordre lògic d'execucióORDER BY és el penúltim pas: s'executa després que les files estiguin filtrades, projectades i deduplicades, i només LIMIT ve després.
flowchart LR
A["1 · FROM"] --> B["2 · WHERE"]
B --> C["3 · SELECT<br/>neixen els àlies"]
C --> D["3b · DISTINCT"]
D --> E["4 · ORDER BY<br/>✅ pot fer servir àlies<br/>✅ i columnes no projectades"]
E --> F["5 · LIMIT<br/>(02-06)"]
Conseqüències que ja has vist en acció:
Pot ORDER BY... |
Resposta | Per què |
|---|---|---|
Fer servir un àlies del SELECT? |
Sí | L'àlies ja existeix: SELECT s'ha executat abans |
Fer servir una columna que no és al SELECT? |
Sí (llevat que hi hagi DISTINCT) |
Les columnes de la taula continuen disponibles |
| Fer servir una expressió calculada? | Sí | S'avalua sobre les files del resultat |
| Fer servir l'ordinal de columna? | Sí | És una comoditat de l'estàndard |
Fer servir un àlies amb SELECT DISTINCT sobre una altra columna? |
No | Restricció vista a 02-04 |
I una consideració de rendiment que reprendràs al mòdul 8: ordenar costa. PostgreSQL pot evitar la feina si existeix un índex que ja retorna les files en l'ordre demanat; si no, ha d'ordenar tot el conjunt a la memòria (o al disc, si no hi cap). Un ORDER BY sobre una taula de milions de files sense índex adequat és una de les causes més freqüents de consultes lentes.
Un últim apunt: si una consulta amb ORDER BY es fa servir com a subconsulta (mòdul 7) o dins d'una vista (mòdul 10), aquest ordre no es propaga necessàriament a la consulta exterior. L'ORDER BY que mana és el del nivell més extern.
Errors habituals i consells
- Confiar en l'ordre sense
ORDER BY. Funciona fins al dia que no. És l'error més car d'aquesta lliçó. - Oblidar el desempat. Dues files amb el mateix valor poden sortir en qualsevol ordre, i aquest ordre pot canviar entre execucions. Acaba sempre amb una columna única.
- Posar
DESCuna sola vegada creient que afecta tota la llista.ORDER BY a, b DESCordenaaascendent ibdescendent. Si vols les dues descendents:ORDER BY a DESC, b DESC. - Ordenar per ordinal en codi de producció.
ORDER BY 2es trenca en silenci quan algú reordena elSELECT. - Suposar que els nuls van on tu creus. PostgreSQL els posa al final en
ASC; MySQL, al principi. Si importa, escriuNULLS FIRSToNULLS LAST. - Ordenar dates desades com a text. Ordre alfabètic, no cronològic. Fes servir el tipus
DATE. - Ordenar números desats com a text.
'10' < '9'és cert alfabèticament. Mateix problema. - Sorprendre's del lloc dels accents o de la
ç. Depèn de la col·lació de la base. Comprova-la ambSHOW lc_collate;. - Consell: fes servir
COLLATEnomés quan de debò calgui, perquè impedeix aprofitar els índexs. - Consell: per als informes, ordena per allò que el lector busca. Un llistat de productes s'ordena per nom si en van a buscar un de concret, i per preu si van a comparar.
- Consell: comprova l'ordre amb els extrems. Mira la primera i l'última fila: solen delatar de seguida un
ASC/DESCinvertit o uns nuls mal col·locats.
Exercicis
Exercici 1
Direcció vol el llistat del catàleg tal com apareixerà al web: només productes actius, agrupats per categoria de menor a major, i dins de cada categoria per nom alfabètic. Mostra categoria_id, id, nom i preu. Explica per què el resultat té 19 files.
Exercici 2
Recursos humans demana la plantilla ordenada per salari de major a menor, mostrant nom, cognoms, carrec, salari i cap_id. Afegeix el que calgui perquè l'ordre sigui determinista i respon: on apareix la Rosa Alcázar Vives i per què el seu cap_id nul no afecta l'ordre?
Exercici 3
Sobre linies_comanda, obtén les línies ordenades per import de major a menor, mostrant id, comanda_id, producte_id, quantitat i l'import arrodonit a dos decimals. Escriu la consulta de dues maneres —fent servir l'àlies i repetint l'expressió— i explica per què totes dues funcionen aquí però només una d'elles funcionaria en un WHERE.
Solucions
Solució 1
| categoria_id | id | nom | preu |
|---|---|---|---|
| 1 | 2 | Arròs integral ecològic 1 kg | 3.90 |
| 1 | 3 | Mel de tarongina crua 500 g | 9.75 |
| 1 | 1 | Oli d'oliva verge extra 500 ml | 12.50 |
| 1 | 4 | Pasta d'espelta 500 g | 2.80 |
| 1 | 5 | Tomàquet triturat ecològic 400 g | 1.95 |
| 2 | 9 | Bàlsam labial de calèndula 15 ml | 4.60 |
| 2 | 6 | Crema facial d'àloe vera 50 ml | 18.90 |
| 2 | 8 | Oli corporal d'ametlles 200 ml | 14.25 |
| 2 | 7 | Xampú sòlid de romaní 80 g | 8.40 |
| 3 | 12 | Bosses reutilitzables de cotó (pack 5) | 9.90 |
| 3 | 10 | Detergent ecològic concentrat 1 L | 11.20 |
| 3 | 13 | Espelmes de cera de soja (pack 2) | 13.75 |
| 3 | 11 | Fregall vegetal de lufa (pack 3) | 5.50 |
| 4 | 14 | Infusió de camamilla ecològica 20 u | 3.25 |
| 4 | 16 | Kombutxa de gingebre 750 ml | 4.95 |
| 4 | 17 | Suc de taronja premsat en fred 1 L | 5.40 |
| 4 | 15 | Te verd matcha cerimonial 30 g | 22.00 |
| 5 | 19 | Desodorant natural en barra 50 g | 7.80 |
| 5 | 18 | Raspall de dents de bambú | 3.50 |
19 files perquè WHERE actiu descarta el producte 20 (Càpsules d'espirulina), l'únic descatalogat. I per això la categoria 6 no apareix al llistat: era el seu únic producte.
Dues observacions sobre l'ordre:
- Dins de cada categoria, l'
idja no és creixent: la categoria 2 comença pel producte 9 perquè "Bàlsam labial" va abans alfabèticament que "Crema", "Oli" i "Xampú". És la prova que l'ordre el mana l'ORDER BYi no la taula. - A la categoria 1, "Oli d'oliva" va després de "Mel de tarongina" perquè la
Mprecedeix laO, i els accents d'"Arròs" i de "Tomàquet" no hi intervenen: en una col·lació lingüística els accents només desempaten quan la resta de lletres coincideix. Si algun producte comencés per una lletra accentuada, en una base amb col·lacióCapareixeria al final de tot el llistat. És l'efecte de la secció 6.
Solució 2
| nom | cognoms | carrec | salari | cap_id |
|---|---|---|---|---|
| Rosa | Alcázar Vives | Directora general | 62000.00 | (null) |
| Andrés | Company Talens | Responsable de vendes | 41000.00 | 1 |
| Beatriz | Nadal Ripoll | Responsable de logística | 39500.00 | 1 |
| Daniel | Vercher Lluch | Analista de dades | 35000.00 | 1 |
| Óscar | Peris Blasco | Comercial | 28500.00 | 2 |
| Laia | Puig Sanchis | Comercial | 27800.00 | 2 |
| Marc | Estévez Roig | Atenció al client | 24500.00 | 2 |
| Irene | Salvador Mira | Operària de magatzem | 22000.00 | 3 |
La Rosa Alcázar Vives apareix la primera, i no pel seu cap_id nul sinó perquè té el salari més alt (62 000 €). El seu cap_id nul no influeix gens ni mica en l'ordre, perquè aquella columna no participa en l'ORDER BY: apareix al resultat però no com a criteri d'ordenació. És una distinció important: els nuls només alteren l'ordre de les columnes per les quals ordenes.
El , id final garanteix el determinisme. En aquestes dades cap salari no es repeteix, així que avui no canvia res; el dia que es contractin dos comercials amb el mateix sou, el llistat continuarà sortint sempre igual.
Solució 3
Versió amb àlies:
SELECT id,
comanda_id,
producte_id,
quantitat,
ROUND(quantitat * preu_unitari * (1 - descompte), 2) AS import
FROM linies_comanda
ORDER BY import DESC, id;Versió amb l'expressió repetida:
SELECT id,
comanda_id,
producte_id,
quantitat,
ROUND(quantitat * preu_unitari * (1 - descompte), 2) AS import
FROM linies_comanda
ORDER BY quantitat * preu_unitari * (1 - descompte) DESC, id;Totes dues retornen el mateix. Les deu primeres files de les 47:
| id | comanda_id | producte_id | quantitat | import |
|---|---|---|---|---|
| 28 | 12 | 15 | 2 | 44.00 |
| 18 | 8 | 1 | 3 | 35.63 |
| 24 | 10 | 6 | 2 | 34.02 |
| 45 | 19 | 16 | 6 | 26.73 |
| 41 | 17 | 1 | 2 | 25.00 |
| 1 | 1 | 1 | 2 | 23.90 |
| 9 | 4 | 15 | 1 | 22.00 |
| 42 | 17 | 15 | 1 | 22.00 |
| 39 | 16 | 10 | 2 | 21.28 |
| 16 | 7 | 16 | 4 | 19.80 |
Per què totes dues funcionen aquí. ORDER BY s'executa després de SELECT, així que en aquell moment l'àlies import ja existeix i l'expressió també es pot reavaluar. Les dues formes són vàlides i PostgreSQL genera el mateix pla.
Per què només una funcionaria en un WHERE. WHERE s'executa abans que SELECT, així que l'àlies encara no ha nascut: WHERE import > 30 donaria column "import" does not exist. Únicament la versió amb l'expressió completa serveix per filtrar, com vas veure a 02-03. Tota aquesta lliçó es recolza en aquesta mateixa asimetria de l'ordre lògic d'execució.
Fixa't a més en l'empat de les files 7 i 8: les línies 9 i 42 valen exactament 22.00 € (una unitat de matcha en tots dos casos). El , id final és el que decideix que surti abans la 9. Sense ell, l'ordre entre totes dues seria impredictible, i un informe paginat podria arribar a mostrar la mateixa línia dues vegades o cap.
Conclusió
Ja controles l'ordre dels teus resultats:
- Sense
ORDER BYno hi ha ordre garantit. UnUPDATE, un índex o el paral·lelisme el poden canviar sense avís previ. ASC(per defecte) iDESCdecideixen el sentit, i cada columna de l'ORDER BYporta el seu.- Ordenar per diverses columnes resol els empats, i acabar amb una columna única fa l'ordre determinista: imprescindible per paginar i perquè les proves no fallin a l'atzar.
- Pots ordenar per àlies, per expressió i per posició ordinal; aquesta última només per explorar, perquè es trenca en silenci.
- Els nuls van al final en
ASCi al principi enDESCa PostgreSQL, just al revés que a MySQL, SQLite i SQL Server.NULLS FIRST/NULLS LASTho fa explícit. - L'ordre del text depèn de la col·lació de la base: amb
Cels accents i laçvan al final de tot; amb regles lingüístiques o ICU, al seu lloc.COLLATE "ca-ES-x-icu"força el criteri català. - Les dates ordenen cronològicament si —i només si— estan desades en columnes de tipus data.
ORDER BYés el pas 4 de l'ordre lògic: ja existeixen els àlies, encara es veuen totes les columnes, i només quedaLIMITal davant.
A l'última lliçó del mòdul, Limitar resultats amb LIMIT, afegiràs el pas 5 i tancaràs el cicle complet d'una consulta. Veuràs per què LIMIT és el primer que s'escriu en explorar una taula desconeguda, com es construeix una paginació amb OFFSET, per què aquesta paginació es degrada i es descompensa en taules grans, i què es fa en el seu lloc a les aplicacions que van de debò.
Curs de SQL
Mòdul 1: Introducció a SQL
- Què és SQL?
- Configurar el teu entorn SQL
- Sintaxi bàsica de SQL
- Entendre bases de dades i taules
- El model relacional: claus primàries i foranes
- La base de dades del curs: BotigaVerda
Mòdul 2: Consultes bàsiques de SQL
- Instrucció SELECT
- Àlies, expressions i columnes calculades
- Filtrar dades amb WHERE
- DISTINCT i eliminació de duplicats
- Ordenar dades amb ORDER BY
- Limitar resultats amb LIMIT
Mòdul 3: Treballar amb múltiples taules
- Operacions JOIN
- INNER JOIN
- LEFT JOIN
- RIGHT JOIN
- FULL OUTER JOIN
- SELF JOIN i CROSS JOIN
- Unions de conjunts: UNION, INTERSECT i EXCEPT
Mòdul 4: Filtratge avançat de dades
- Utilitzar LIKE per a coincidència de patrons
- Operadors IN i BETWEEN
- Valors NULL i IS NULL
- Funcions d'agregació: COUNT, SUM, AVG, MIN i MAX
- Agregar dades amb GROUP BY
- Clàusula HAVING
Mòdul 5: Manipulació de dades
- Crear taules i restriccions amb CREATE TABLE
- Instrucció INSERT
- Instrucció UPDATE
- Instrucció DELETE
- Instrucció UPSERT (MERGE)
- Modificar l'esquema: ALTER TABLE i migracions segures
Mòdul 6: Funcions avançades de SQL
- Funcions de cadena
- Funcions numèriques
- Funcions de data i hora
- Conversió de tipus i tractament dels NULL: CAST i COALESCE
- Expressions condicionals
Mòdul 7: Subconsultes i consultes imbricades
- Introducció a les subconsultes
- Subconsultes correlacionades
- EXISTS i NOT EXISTS
- Utilitzar subconsultes en les clàusules SELECT, FROM i WHERE
- Subconsultes o JOIN: quin triar
Mòdul 8: Índexs i optimització del rendiment
- Entendre els índexs
- Creació i gestió d'índexs
- Tipus d'índex i quan no indexar
- Tècniques d'optimització de consultes
- Anàlisi del rendiment de les consultes
Mòdul 9: Transaccions i concurrència
- Introducció a les transaccions
- Propietats ACID
- Instruccions de control de transaccions
- Nivells d'aïllament i anomalies de concurrència
- Gestió de la concurrència: bloquejos i interbloquejos
Mòdul 10: Temes avançats
- Vistes
- Expressions de taula comunes (CTE)
- Funcions de finestra
- Procediments emmagatzemats
- Disparadors (triggers)
- JSON i dades semiestructurades
Mòdul 11: SQL a la pràctica
- Casos d'ús al món real
- Bones pràctiques
- Seguretat: injecció SQL, permisos i rols
- SQL per a l'anàlisi de dades
- SQL en el desenvolupament web
