Ja tens totes les peces d'una consulta menys una: decidir quantes files vols rebre. Amb les 20 files de productes sembla irrellevant, però el dia que et connectis a una taula de producció amb cinquanta milions de registres, un SELECT * FROM comandes; sense més pot col·lapsar el teu terminal, saturar la xarxa i fer que un administrador de sistemes et busqui amb cara de pocs amics. LIMIT és la primera línia de defensa. I és també la base de la paginació, un d'aquells problemes que semblen resolts en dos minuts i que en taules grans es converteixen en un maldecap clàssic. En aquesta lliçó aprendràs totes dues coses: l'ús quotidià i l'ús seriós.
Contingut
LIMIT: acotar el resultat- Per què
LIMITsenseORDER BYno és determinista OFFSETi la paginació clàssica- Els dos problemes d'
OFFSETen taules grans - Paginació per cursor o keyset
FETCH FIRST n ROWS ONLY: la forma estàndard- Casos d'ús típics
LIMITa l'ordre lògic d'execució- Errors habituals i consells
- Exercicis
- Conclusió
LIMIT: acotar el resultat
LIMIT: acotar el resultatLIMIT n indica quantes files, com a màxim, vols rebre. S'escriu al final de la consulta, després d'ORDER BY:
| 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 |
Els cinc productes més cars del catàleg. Aquest patró —ordenar i retallar— és la forma canònica de respondre a qualsevol pregunta de tipus "top N".
Comportament de LIMIT als casos límit:
| Escriptura | Què retorna |
|---|---|
LIMIT 5 |
Com a molt 5 files |
LIMIT 100 sobre productes |
Les 20 que hi ha. LIMIT és un màxim, no una exigència |
LIMIT 0 |
Cap fila, però sí les capçaleres. Útil per inspeccionar els tipus de columna d'una consulta sense executar-la del tot |
LIMIT ALL |
Totes. Equival a no posar-hi LIMIT; serveix per construir consultes per programa |
LIMIT NULL |
Totes, igual que LIMIT ALL |
LIMIT -1 |
ERROR: LIMIT must not be negative |
L'ús més freqüent en el dia a dia ni tan sols porta ORDER BY: és fer un cop d'ull a una taula que no coneixes.
| id | comanda_id | producte_id | quantitat | preu_unitari | descompte |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 2 | 11.95 | 0.00 |
| 2 | 1 | 2 | 3 | 3.90 | 0.00 |
| 3 | 1 | 14 | 2 | 3.25 | 0.00 |
| 4 | 2 | 6 | 1 | 17.50 | 0.00 |
| 5 | 2 | 9 | 2 | 4.60 | 0.00 |
Aquí SELECT * i l'absència d'ORDER BY són perfectament legítims: no vols unes files concretes, vols veure quina pinta tenen les dades. És exploració, no un informe.
Costum professional: quan et connectis a una base de dades que no coneixes, escriu
LIMIT 10abans d'escriure la resta de la consulta. Costa vuit caràcters i evita la vergonya de bloquejar una sessió en producció.
- Per què
LIMIT sense ORDER BY no és determinista
LIMIT sense ORDER BY no és deterministaReprenem l'advertiment de 02-05, perquè amb LIMIT es torna molt més perillós.
| id | nom | preu |
|---|---|---|
| 1 | Oli d'oliva verge extra 500 ml | 12.50 |
| 2 | Arròs integral ecològic 1 kg | 3.90 |
| 3 | Mel de tarongina crua 500 g | 9.75 |
Què has demanat exactament? Tres files qualssevol. No les tres primeres per id, no les tres més barates: tres files arbitràries, les que el motor tingués més a mà. Que avui en surtin la 1, la 2 i la 3 és casualitat de l'ordre físic.
La diferència amb una consulta sense LIMIT és subtil però crucial:
| Consulta | Sense ORDER BY |
|---|---|
SELECT ... FROM productes |
Retorna les 20 files, en ordre impredictible. El conjunt és correcte; només l'ordre és incert |
SELECT ... FROM productes LIMIT 3 |
Retorna tres files impredictibles. El conjunt mateix és incert |
En el primer cas, ordenar el resultat a la teva aplicació arregla el problema. En el segon no hi ha cap arranjament possible: has perdut 17 files i no saps quines.
Regla:
LIMITsenseORDER BYnomés és acceptable per explorar. Tan bon punt el resultat es faci servir per a alguna cosa, l'ORDER BYés obligatori, i ha de ser determinista (acabat en una columna única, com vas veure a 02-05).
OFFSET i la paginació clàssica
OFFSET i la paginació clàssicaOFFSET m descarta les primeres m files del resultat abans d'aplicar LIMIT. Combinats, permeten recórrer un resultat gran a trossos:
Vegem-ho amb el catàleg de BotigaVerda ordenat per preu descendent i pàgines de cinc productes.
Pàgina 1 — LIMIT 5 OFFSET 0:
| 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 |
Pàgina 2 — LIMIT 5 OFFSET 5:
| id | nom | preu |
|---|---|---|
| 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 |
Pàgina 3 — LIMIT 5 OFFSET 10:
| id | nom | preu |
|---|---|---|
| 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 |
I la quarta i última tancaria amb els productes 2, 18, 14, 4 i 5.
Resum del càlcul:
| Pàgina | OFFSET |
LIMIT |
Productes retornats |
|---|---|---|---|
| 1 | 0 | 5 | 15, 6, 20, 8, 13 |
| 2 | 5 | 5 | 1, 10, 12, 3, 7 |
| 3 | 10 | 5 | 19, 11, 17, 16, 9 |
| 4 | 15 | 5 | 2, 18, 14, 4, 5 |
Detalls importants:
- L'
ORDER BYés obligatori. Sense ell, cada pàgina es calcula sobre un ordre diferent i podries veure el mateix producte a dues pàgines i un altre a cap. - L'
ORDER BYha de ser determinista. Per això hem escritORDER BY preu DESC, id: si dos productes costessin el mateix, el desempat peridgaranteix que sempre caiguin a la mateixa pàgina. OFFSETsenseLIMITés vàlid:OFFSET 15retorna les files de la 16 endavant.OFFSETmés gran que el total retorna zero files, sense error.OFFSET 100sobreproductesno dona res.
- Els dos problemes d'
OFFSET en taules grans
OFFSET en taules gransAquesta paginació funciona, és la que aprèn tothom, i té dos defectes seriosos que només es manifesten quan les dades creixen.
4.1. El cost creix amb el número de pàgina
OFFSET m no salta les primeres m files: les calcula i les descarta. El motor no té manera d'endevinar quina és la fila número 500 001 sense haver produït les 500 000 anteriors.
| Pàgina | Files que el motor produeix | Files que et lliura |
|---|---|---|
| 1 | 20 | 20 |
| 50 | 1 000 | 20 |
| 500 | 10 000 | 20 |
| 50 000 | 1 000 000 | 20 |
L'última pàgina d'un llistat gran pot trigar centenars de vegades més que la primera. És un patró conegut: els usuaris es queixen que "el web va lent al final del catàleg", i la causa és aquí. Amb EXPLAIN ANALYZE (mòdul 8) es veu amb tota claredat al node Limit, que informa de quantes files ha descartat.
4.2. Les dades es mouen entre pàgina i pàgina
Aquest és pitjor, perquè no és lent: és incorrecte.
Imagina que un usuari està veient la pàgina 1 del catàleg ordenat per preu descendent i, en aquell instant, algú dona d'alta un producte de 25 € (més car que el matcha). Quan l'usuari premi "següent":
| Moment | Què passa |
|---|---|
| Pàgina 1 (abans) | 15, 6, 20, 8, 13 |
| S'insereix un producte nou de 25.00 € | Tot el llistat es desplaça una posició |
Pàgina 2 (OFFSET 5) |
Ara la posició 6 l'ocupa el producte 13, que ja era a la pàgina 1 |
L'usuari veu el producte 13 dues vegades. I amb un esborrat passa el contrari: una fila desapareix sense haver-se mostrat mai.
| Canvi a les dades | Símptoma per a l'usuari |
|---|---|
| S'insereix una fila que va abans de la pàgina actual | Veu una fila repetida |
| S'esborra una fila anterior a la pàgina actual | Una fila se salta i no la veu mai |
Cada pàgina és una consulta independent, executada en un moment diferent i sobre un estat diferent de la taula. OFFSET no té memòria del que ja et va ensenyar.
Quan es pot conviure amb OFFSET?
| Escenari | OFFSET és acceptable? |
|---|---|
| Panell intern amb pocs milers de files | Sí, sense problema |
| Dades que no canvien durant la sessió (un informe històric) | Sí |
| Necessites "anar a la pàgina 47" directament | Sí: és l'únic que ho permet |
| Catàleg públic amb milions de files i escriptures constants | No |
| Un scroll infinit en una aplicació mòbil | No |
| Exportar una taula sencera a trossos | No: fes servir keyset |
- Paginació per cursor o keyset
L'alternativa consisteix a deixar de dir "salta't 500 000 files" i començar a dir "dona'm el que ve després d'això". En comptes d'una posició, es recorda l'últim valor vist.
Tornem al nostre catàleg. La pàgina 1 acabava amb el producte 13, amb preu 13.75 €. La pàgina 2 es demana així:
| id | nom | preu |
|---|---|---|
| 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 |
Idèntica a la pàgina 2 de la secció 3, però obtinguda sense descartar res: el motor va directe a les files que compleixen preu < 13.75.
Què passa si hi ha empats. Si dos productes costessin exactament 13.75 €, WHERE preu < 13.75 es saltaria el segon. La solució és comparar la tupla completa de les columnes d'ordenació, cosa que SQL permet:
SELECT id, nom, preu
FROM productes
WHERE (preu, id) < (13.75, 13)
ORDER BY preu DESC, id DESC
LIMIT 5;La comparació (preu, id) < (13.75, 13) és lexicogràfica: es compleix si preu < 13.75, o si preu = 13.75 i a més id < 13. És exactament la condició "estrictament després de l'últim element vist" per a aquest ordre. Compte amb un detall: perquè la comparació de tuples encaixi, totes les columnes de l'ORDER BY han d'anar en el mateix sentit, i per això aquí hi apareix id DESC.
Comparativa dels dos enfocaments:
| Aspecte | OFFSET |
Keyset |
|---|---|---|
| Cost de la pàgina N | Creix linealment amb N | Constant |
| Aprofita un índex? | Només per ordenar | Sí, per posicionar-se directament |
| Files repetides o saltades si les dades canvien | Sí | No |
| Permet saltar a la pàgina 47? | Sí | No: només "següent" i "anterior" |
| Permet mostrar "pàgina 3 de 120"? | Sí | No sense una consulta addicional |
| Complexitat d'implementació | Trivial | Mitjana: cal arrossegar el cursor |
A la pràctica: si la teva interfície és un scroll infinit o un botó "carrega'n més", el keyset és sempre la resposta correcta. Si necessites numerets de pàgina clicables, OFFSET és l'únic viable i cal assumir-ne els límits (o limitar el nombre de pàgines navegables, que és el que fan gairebé tots els cercadors).
Perquè el keyset rendeixi cal un índex sobre les columnes d'ordenació, en aquest cas (preu, id). Sense ell, PostgreSQL ha d'ordenar tota la taula igualment i no hi guanyes res. Els índexs són el mòdul 8.
FETCH FIRST n ROWS ONLY: la forma estàndard
FETCH FIRST n ROWS ONLY: la forma estàndardLIMIT és còmode, universalment conegut... i no és SQL estàndard. El va introduir MySQL, el va adoptar PostgreSQL i avui l'entenen gairebé tots els motors, però la sintaxi oficial de l'estàndard SQL:2008 és una altra:
| 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 |
Exactament el mateix resultat. PostgreSQL admet totes dues formes i les tracta igual.
PostgreSQL afegeix a més WITH TIES, que amplia el resultat per incloure totes les files empatades amb l'última:
Sobre aquestes dades retorna les mateixes 5 files, perquè no hi ha dos productes amb el mateix preu. Però si hi hagués tres productes a 13.75 €, WITH TIES retornaria 7 files en comptes de 5: és la forma correcta de fer un "top 5" honest en una competició. WITH TIES exigeix ORDER BY i no funciona amb LIMIT, només amb FETCH.
Taula comparativa entre motors:
| Motor | Sintaxi principal | Alternatives |
|---|---|---|
| Estàndard SQL:2008 | OFFSET m ROWS FETCH FIRST n ROWS ONLY |
— |
| PostgreSQL | LIMIT n OFFSET m |
FETCH FIRST n ROWS ONLY, WITH TIES |
| MySQL / MariaDB | LIMIT n OFFSET m |
LIMIT m, n (els arguments al revés!) |
| SQLite | LIMIT n OFFSET m |
LIMIT m, n |
| SQL Server 2012+ | OFFSET m ROWS FETCH NEXT n ROWS ONLY |
SELECT TOP (n) ... (sense offset) |
| Oracle 12c+ | OFFSET m ROWS FETCH FIRST n ROWS ONLY |
— |
| Oracle 11g i anteriors | WHERE ROWNUM <= n sobre una subconsulta ordenada |
— |
Dos paranys d'aquesta taula que convé subratllar:
LIMIT m, nde MySQL inverteix el significat: el primer número és el desplaçament i el segon la quantitat.LIMIT 5, 10a MySQL ésLIMIT 10 OFFSET 5a PostgreSQL. Una consulta copiada sense llegir-la retorna dades equivocades.ROWNUMd'Oracle s'assigna abans de l'ORDER BY.WHERE ROWNUM <= 5 ORDER BY preu DESCretorna cinc files qualssevol i després les ordena: no és el top 5. Cal ordenar en una subconsulta i aplicarROWNUMa fora.
Quina fer servir? En aquest curs, LIMIT: és el que veuràs al 99 % del codi PostgreSQL. Si escrius SQL que s'hagi d'executar en diversos motors, OFFSET ... FETCH FIRST ... ROWS ONLY és l'aposta segura.
- Casos d'ús típics
7.1. Top N
Ja ho has vist amb els productes més cars. Una altra variant, els cinc de més marge:
SELECT nom,
preu,
cost,
preu - cost AS marge
FROM productes
WHERE actiu
ORDER BY marge DESC, id
LIMIT 5;| 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 |
| 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 |
Fixa't que les Càpsules d'espirulina (marge 7.70 €, tercera del catàleg) no hi apareixen: el WHERE actiu les descarta abans d'ordenar. L'ordre lògic mana: primer es filtra, després s'ordena, i només al final es retalla.
7.2. Els últims registres
SELECT id, client_id, data_comanda, estat, metode_pagament
FROM comandes
ORDER BY data_comanda DESC, id DESC
LIMIT 3;| id | client_id | data_comanda | estat | metode_pagament |
|---|---|---|---|---|
| 20 | 9 | 2026-02-21 | pendent | contrareemborsament |
| 19 | 6 | 2026-02-09 | pagat | targeta |
| 18 | 5 | 2026-01-27 | pagat | transferencia |
Les tres últimes comandes rebudes: el contingut natural d'un panell d'"activitat recent".
7.3. El registre extrem
| id | nom | cognoms | data_registre |
|---|---|---|---|
| 1 | Lucía | Martínez Soler | 2025-01-10 |
La primera clienta de BotigaVerda. Aquest patró —ORDER BY ... LIMIT 1— és equivalent a fer servir MIN/MAX, però amb un avantatge: et retorna la fila sencera, no només el valor mínim. Amb MIN(data_registre) sabries la data, però no qui és. Les funcions d'agregació arriben a la lliçó 04-04.
7.4. Mostreig ràpid per a exploració
| id | producte_id | client_id | puntuacio | comentari | data |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 5 | Oli excel·lent, gust intens i envàs molt cuidat. | 2025-03-15 |
| 2 | 2 | 1 | 4 | Bon arròs, tot i que triga una mica més a bullir del normal. | 2025-03-16 |
| 3 | 6 | 2 | 5 | La crema deixa la pell molt suau. Repetiré sens dubte. | 2025-03-25 |
LIMIT a l'ordre lògic d'execució
LIMIT a l'ordre lògic d'execucióAmb LIMIT es completa el cicle que vam començar a 02-01. Aquest és el diagrama definitiu del mòdul:
flowchart LR
A["1 · FROM<br/>origen de les files"] --> B["2 · WHERE<br/>filtra files"]
B --> C["3 · SELECT<br/>projecta i calcula<br/>neixen els àlies"]
C --> D["3b · DISTINCT<br/>elimina duplicats"]
D --> E["4 · ORDER BY<br/>ordena el resultat"]
E --> F["5 · LIMIT / OFFSET<br/>retalla"]
LIMIT és sempre l'últim. D'aquí en surten conseqüències que convé tenir clares:
| Pregunta | Resposta |
|---|---|
LIMIT 5 fa que WHERE examini només 5 files? |
No. WHERE s'aplica a totes les files de la taula |
LIMIT 5 amb ORDER BY ordena només 5 files? |
No. Lògicament s'ordena tot i després es retalla |
Aleshores, LIMIT no estalvia feina? |
Sí que n'estalvia, però al pla físic, no al lògic |
Aquest últim punt mereix un matís. Encara que lògicament s'ordeni tot, PostgreSQL és més llest que això: quan veu un ORDER BY ... LIMIT n petit, fa servir un algorisme anomenat top-N heapsort, que manté a la memòria només les n millors files vistes fins al moment en comptes d'ordenar el conjunt sencer. I si existeix un índex que ja retorna les files en l'ordre demanat, pot llegir les n primeres i aturar-se, sense tocar la resta de la taula.
És l'exemple perfecte de la distinció de 02-01: l'ordre lògic defineix el significat de la consulta, i el pla físic que tria l'optimitzador pot ser radicalment més eficient mentre produeixi el mateix resultat. Ho veuràs amb els teus propis ulls al mòdul 8 amb EXPLAIN.
Errors habituals i consells
LIMITsenseORDER BYen qualsevol consulta que no sigui exploratòria. Retorna files arbitràries i el problema no es pot arreglar després.ORDER BYno determinista en paginar. Si hi ha empats i no els desempates amb una columna única, una mateixa fila pot aparèixer a dues pàgines i una altra a cap.- Copiar
LIMIT 10, 20d'un exemple de MySQL. A MySQL significa "20 files des de l'11"; a PostgreSQL ni tan sols és sintaxi vàlida. - Creure que
OFFSETsalta files sense cost. Les produeix i les llença. A la pàgina 5 000 ho notaràs. - Paginar amb
OFFSETsobre dades que canvien. Files repetides i files saltades, sense cap error que ho delati. - Aplicar el keyset amb un
ORDER BYque no coincideix amb la condició delWHERE. Les columnes han de ser les mateixes, en el mateix ordre i en el mateix sentit. - Fer servir
LIMITper "arreglar" una consulta lenta. Si la consulta és lenta per manca d'índex,LIMITpot continuar sent lent: el motor ha de trobar les files abans de retallar-les. - Esperar que
LIMIT 1substitueixi unWHEREben escrit. Retornar una fila qualsevol de les que compleixen la condició rarament és el que es vol. - Consell:
LIMITprimer, consulta després. En explorar una base desconeguda, escriu-lo abans de res. - Consell:
LIMIT 0és útil. Et dona les columnes i els seus tipus sense portar dades, ideal per comprovar la forma d'una consulta complexa. - Consell: per a un "top N" honest, planteja't
FETCH FIRST n ROWS WITH TIES. Tallar pel número 5 exacte quan el 5 i el 6 empaten és enganyós.
Exercicis
Exercici 1
Atenció al client necessita un panell amb les cinc comandes més antigues que encara no estan lliurades ni cancel·lades, mostrant id, client_id, data_comanda, estat i despeses_enviament. Escriu la consulta i explica quantes files retorna realment i per què.
Exercici 2
Construeix la segona pàgina d'un llistat de clients ordenat per país i, dins de cada país, per cognoms, amb pàgines de quatre clients. Escriu-la primer amb OFFSET i després amb paginació keyset. Explica quina informació necessita l'aplicació en cada cas per demanar la pàgina següent.
Exercici 3
L'equip de compres vol les tres línies de comanda de més import. Escriu la consulta fent servir la sintaxi estàndard FETCH FIRST, i indica què canviaria si fessis servir WITH TIES. Després respon: per què aquesta consulta no et pot dir de quin producte es tracta?
Solucions
Solució 1
SELECT id,
client_id,
data_comanda,
estat,
despeses_enviament
FROM comandes
WHERE estat <> 'lliurat'
AND estat <> 'cancellat'
ORDER BY data_comanda, id
LIMIT 5;| id | client_id | data_comanda | estat | despeses_enviament |
|---|---|---|---|---|
| 16 | 4 | 2025-12-19 | enviat | 4.95 |
| 17 | 7 | 2026-01-13 | enviat | 9.90 |
| 18 | 5 | 2026-01-27 | pagat | 4.95 |
| 19 | 6 | 2026-02-09 | pagat | 4.95 |
| 20 | 9 | 2026-02-21 | pendent | 12.50 |
5 files, que resulten ser totes les que compleixen la condició: de les 20 comandes, 14 estan lliurades i 1 cancel·lada, així que només en queden 5 en curs. El LIMIT 5 no ha retallat res, i aquest és un comportament normal: LIMIT és un màxim, no una promesa.
El raonament per l'ordre lògic: FROM porta 20 files → WHERE en deixa 5 → SELECT projecta → ORDER BY data_comanda, id les ordena de més antiga a més recent → LIMIT 5 no en descarta cap. Si demà entren deu comandes noves, la consulta continuarà retornant les cinc més antigues sense tocar-hi ni una coma.
Al mòdul 4 escriuràs aquesta condició de manera més neta com a WHERE estat NOT IN ('lliurat', 'cancellat').
Solució 2
Amb OFFSET, la pàgina 2 (clients 5 a 8 del llistat):
El llistat complet ordenat per pais, cognoms comença així: Belmonte Roca (5), Bosch Ferrer (13), Carrasco Vega (15), Ferrer Ibáñez (2) —pàgina 1—, i continua:
| id | nom | cognoms | ciutat | pais |
|---|---|---|---|---|
| 14 | Hugo | Iglesias Pardo | Saragossa | Espanya |
| 6 | Pau | Llorens Vidal | València | Espanya |
| 1 | Lucía | Martínez Soler | València | Espanya |
| 11 | Elena | Navarro Puig | Alacant | Espanya |
Amb paginació keyset, partint de l'últim element de la pàgina 1 —Carlos Ferrer Ibáñez, país Espanya, cognoms Ferrer Ibáñez, id 2—:
SELECT id, nom, cognoms, ciutat, pais
FROM clients
WHERE (pais, cognoms, id) > ('Espanya', 'Ferrer Ibáñez', 2)
ORDER BY pais, cognoms, id
LIMIT 4;Retorna exactament les mateixes quatre files.
Què necessita l'aplicació en cada cas:
| Enfocament | Què arrossega entre peticions |
|---|---|
OFFSET |
Només un número: la pàgina actual. Fàcil de posar en una URL (?page=2) i permet saltar a qualsevol pàgina |
| Keyset | Els valors d'ordenació de l'última fila mostrada (aquí pais, cognoms i id). Es desen en un "cursor" que l'aplicació retorna en demanar la pàgina següent |
Fixa't en dos detalls del keyset: la tupla del WHERE conté exactament les mateixes columnes de l'ORDER BY i en el mateix ordre, i s'hi inclou id com a última columna precisament per desempatar dos clients que compartissin país i cognoms. Sense aquest id, un cognom repetit faria que es perdés un client entre pàgina i pàgina.
Solució 3
SELECT id,
comanda_id,
quantitat,
preu_unitari,
descompte,
ROUND(quantitat * preu_unitari * (1 - descompte), 2) AS import
FROM linies_comanda
ORDER BY quantitat * preu_unitari * (1 - descompte) DESC, id
FETCH FIRST 3 ROWS ONLY;| id | comanda_id | quantitat | preu_unitari | descompte | import |
|---|---|---|---|---|---|
| 28 | 12 | 2 | 22.00 | 0.00 | 44.00 |
| 18 | 8 | 3 | 12.50 | 0.05 | 35.63 |
| 24 | 10 | 2 | 18.90 | 0.10 | 34.02 |
Què canviaria amb WITH TIES. Res, en aquest cas: la quarta línia val 26.73 €, molt lluny dels 34.02 € de la tercera, així que no hi ha cap empat a arrossegar. Però convé notar que WITH TIES no pot portar un desempat artificial a l'ORDER BY: si hi deixes el , id final, cada fila té un valor d'ordenació únic i mai no hi haurà empats a incloure. Perquè WITH TIES serveixi d'alguna cosa cal ordenar només pel criteri real:
Amb aquestes dades retorna les mateixes 3 files. Si hi hagués dues línies empatades a 34.02 €, en retornaria 4.
Per què no pots saber de quin producte es tracta. Perquè linies_comanda desa producte_id, un número, i el nom del producte viu a la taula productes. Amb les eines d'aquest mòdul només pots consultar una taula alhora: el màxim que pots dir és que la línia 28 correspon al producte 15. Per escriure "Te verd matcha cerimonial 30 g" a l'informe cal combinar totes dues taules, i això és precisament el que comença a la lliçó següent.
Conclusió
Has tancat el cicle complet d'una consulta:
LIMIT nacota el resultat a un màxim denfiles i és la primera línia de defensa en explorar taules grans o desconegudes.LIMITsenseORDER BYno és determinista: retorna files arbitràries, i aquest dany no es pot reparar després.OFFSET mdescarta les primeresmfiles i permet la paginació clàssicaLIMIT mida OFFSET (N-1)*mida, que exigeix unORDER BYdeterminista.- Aquesta paginació té dos defectes en taules grans: el cost creix amb el número de pàgina, i les insercions o esborrats fan que es repeteixin o se saltin files.
- La paginació per cursor o keyset —
WHERE (columnes) < (últims valors vistos)— té cost constant i no es descompensa, a canvi de no poder saltar a una pàgina arbitrària. FETCH FIRST n ROWS ONLYés la forma estàndard, iWITH TIESamplia el resultat amb les files empatades. Cada motor té el seu dialecte, iLIMIT m, nde MySQL inverteix els arguments.LIMITés el pas 5 i últim de l'ordre lògic; l'optimitzador, en canvi, sí que aprofita la seva presència amb estratègies com el top-N heapsort.
I amb això tanques el mòdul 2 complet. Saps construir una consulta de principi a fi: triar-ne l'origen amb FROM, filtrar files amb WHERE, projectar i calcular columnes amb SELECT i els seus àlies, eliminar repeticions amb DISTINCT, imposar un ordre amb ORDER BY i retallar el resultat amb LIMIT. I saps en quin ordre lògic passa tot això, que és el que t'ha permès entendre per què un àlies funciona en un lloc i en un altre no.
Però fixa't en el sostre amb el qual has topat una vegada i una altra: comandes et diu client_id = 9 i no "Camille Dubois"; linies_comanda et diu producte_id = 15 i no "Te verd matcha cerimonial"; productes et diu categoria_id = 2 i no "Cosmètica natural". Totes les teves consultes han mirat una sola taula, i les preguntes que de debò interessen a BotigaVerda —què va comprar cada client, quina categoria factura més, quin comercial tanca més comandes, quins productes no ha comprat ningú— viuen precisament a les relacions entre taules que vas dibuixar al diagrama de 01-06. Al mòdul 3, Consultes amb múltiples taules, aprendràs a recórrer aquestes relacions amb JOIN: l'INNER JOIN per al que casa a banda i banda, el LEFT i el RIGHT per conservar el que no casa —allà apareixeran per fi els tres clients sense comandes i els tres productes mai venuts—, el FULL OUTER per a totes dues coses alhora, el SELF JOIN per a les relacions reflexives d'empleats i clients, i UNION, INTERSECT i EXCEPT per combinar resultats sencers. Les nou taules de BotigaVerda deixen de ser nou illes.
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
