A la lliçó anterior retornaves dades tal com estan desades. Però una base de dades no desa el preu amb IVA, ni el marge d'un producte, ni l'import d'una línia de comanda: desa les peces mínimes i la resta es calcula en consultar-ho. En aquesta lliçó aprendràs a construir aquestes columnes calculades amb expressions aritmètiques i de text, a posar-los un nom llegible amb AS, i a entendre —fent servir l'ordre lògic d'execució de 02-01— per què aquest nom es pot fer servir en uns llocs de la consulta i en uns altres no. Aquí apareix, a més, l'expressió més important de tot el curs: quantitat * preu_unitari * (1 - descompte).
Contingut
- Àlies de columna amb
AS - Quan l'àlies necessita cometes dobles
- Àlies de taula
- Columnes calculades: aritmètica sobre columnes
- L'expressió estrella: l'import d'una línia de comanda
- Concatenació de text:
||iCONCAT ROUNDper presentar diners- Per què l'àlies no funciona a
WHEREperò sí aORDER BY - Errors habituals i consells
- Exercicis
- Conclusió
- Àlies de columna amb
AS
ASUn àlies és el nom que vols que tingui una columna al resultat. Es declara amb AS:
Abans de res, comprovem per què cal. Sense àlies, una expressió no té nom:
| nom | ?column? |
|---|---|
| Oli d'oliva verge extra 500 ml | 15.1250 |
| ... | ... |
?column? és la manera que té PostgreSQL de dir "això no té nom". Un informe amb aquesta capçalera no serveix de res, i un programa que accedeixi al resultat pel nom de la columna no hi trobarà res. Amb àlies:
| producte | preu_sense_iva | preu_amb_iva |
|---|---|---|
| Oli d'oliva verge extra 500 ml | 12.50 | 15.1250 |
| Arròs integral ecològic 1 kg | 3.90 | 4.7190 |
| Mel de tarongina crua 500 g | 9.75 | 11.7975 |
| Pasta d'espelta 500 g | 2.80 | 3.3880 |
| Tomàquet triturat ecològic 400 g | 1.95 | 2.3595 |
| Crema facial d'àloe vera 50 ml | 18.90 | 22.8690 |
| Xampú sòlid de romaní 80 g | 8.40 | 10.1640 |
| Oli corporal d'ametlles 200 ml | 14.25 | 17.2425 |
| Bàlsam labial de calèndula 15 ml | 4.60 | 5.5660 |
| Detergent ecològic concentrat 1 L | 11.20 | 13.5520 |
(10 primeres de 20 files.)
La paraula AS és opcional per a les columnes. Aquestes dues línies són equivalents:
Tot i així, escriu-la sempre. Sense AS, oblidar una coma converteix una columna en l'àlies de l'anterior i la consulta s'executa sense error donant un resultat equivocat (ho vas veure a 01-03 i a 02-01):
SELECT nom preu FROM productes; -- una sola columna, anomenada "preu",
-- que conté els NOMS dels productes| preu |
|---|
| Oli d'oliva verge extra 500 ml |
| ... |
- Quan l'àlies necessita cometes dobles
Un àlies és un identificador, així que segueix les regles de 01-03: sense cometes es plega a minúscules i només admet lletres, dígits i guions baixos.
| Àlies | Necessita cometes? | Resultat |
|---|---|---|
AS preu_amb_iva |
No | Columna preu_amb_iva |
AS PreuAmbIVA |
No, però... | La columna es dirà preuambiva (plegada a minúscules) |
AS "Preu amb IVA" |
Sí (té espais) | Columna Preu amb IVA |
AS "Marge %" |
Sí (té %) |
Columna Marge % |
AS order |
Sí (order és paraula reservada) |
Error sense cometes |
AS 'Preu' |
Mai | Error: les cometes simples són per a cadenes |
| Producte | Preu (€) | Preu amb IVA (€) |
|---|---|---|
| Te verd matcha cerimonial 30 g | 22.00 | 26.6200 |
| ... | ... | ... |
Aquest és l'únic ús legítim de les cometes dobles en aquest curs: àlies de presentació destinats a un informe o a una exportació. Per a qualsevol àlies que hagis de reutilitzar dins de la consulta, fes servir snake_case en minúscules i estalvia't les cometes.
Nota de dialecte: MySQL i SQLite permeten a més fer servir cometes invertides (
`Preu amb IVA`) o cometes simples com a delimitador d'àlies. PostgreSQL no: cometes dobles o res. Escriu sempre la forma estàndard.
- Àlies de taula
També les taules admeten àlies, i aquí AS és igualment opcional:
Amb una sola taula sembla un caprici: p.nom no aporta res enfront de nom. El seu valor apareix al mòdul 3, quan una consulta combini diverses taules que tenen columnes amb el mateix nom:
-- Avanç del mòdul 3, NO ho executis encara
SELECT p.nom AS producte,
c.nom AS categoria
FROM productes AS p
JOIN categories AS c ON p.categoria_id = c.id;Sense els àlies p i c, nom seria ambigu i PostgreSQL respondria column reference "nom" is ambiguous. Per això, en SQL professional, gairebé totes les consultes porten àlies de taula.
Convencions útils per als àlies de taula:
| Pràctica | Exemple | Comentari |
|---|---|---|
| Inicial o abreviatura curta | productes AS p, linies_comanda AS lc |
El més estès |
| Nom significatiu si hi ha ambigüitat | empleats AS cap, clients AS referidor |
Imprescindible en unir una taula amb si mateixa (03-06) |
| Prefixar totes les columnes si hi ha àlies | p.nom, p.preu |
Evita sorpreses en afegir taules després |
| Àlies d'una sola lletra críptica | productes AS x |
Evitar: il·legible en consultes llargues |
Una diferència que sorprèn: si poses àlies a la taula, el nom original deixa d'estar disponible. Això falla:
ERROR: invalid reference to FROM-clause entry for table "productes" HINT: Perhaps you meant to reference the table alias "p".
- Columnes calculades: aritmètica sobre columnes
Una columna calculada és una expressió a la llista del SELECT. S'avalua fila a fila, amb els valors d'aquella fila.
4.1. Marge brut
| nom | preu | cost | marge |
|---|---|---|---|
| Oli d'oliva verge extra 500 ml | 12.50 | 7.80 | 4.70 |
| Arròs integral ecològic 1 kg | 3.90 | 2.10 | 1.80 |
| Mel de tarongina crua 500 g | 9.75 | 5.40 | 4.35 |
| Pasta d'espelta 500 g | 2.80 | 1.35 | 1.45 |
| Tomàquet triturat ecològic 400 g | 1.95 | 0.90 | 1.05 |
| Crema facial d'àloe vera 50 ml | 18.90 | 9.50 | 9.40 |
| Xampú sòlid de romaní 80 g | 8.40 | 3.60 | 4.80 |
| Oli corporal d'ametlles 200 ml | 14.25 | 7.10 | 7.15 |
| Bàlsam labial de calèndula 15 ml | 4.60 | 1.80 | 2.80 |
| Detergent ecològic concentrat 1 L | 11.20 | 6.00 | 5.20 |
(10 primeres de 20 files.)
En la resta, l'escala del resultat és la més gran de les dues, així que el marge surt amb dos decimals nets. En la multiplicació no serà així.
4.2. Marge percentual
| nom | preu | cost | marge_pct |
|---|---|---|---|
| Oli d'oliva verge extra 500 ml | 12.50 | 7.80 | 37.6000000000000000 |
| Arròs integral ecològic 1 kg | 3.90 | 2.10 | 46.1538461538461538 |
| Mel de tarongina crua 500 g | 9.75 | 5.40 | 44.6153846153846154 |
| Pasta d'espelta 500 g | 2.80 | 1.35 | 51.7857142857142857 |
| Tomàquet triturat ecològic 400 g | 1.95 | 0.90 | 53.8461538461538462 |
| Crema facial d'àloe vera 50 ml | 18.90 | 9.50 | 49.7354497354497354 |
(6 primeres de 20 files.)
Tres coses per aprendre d'aquí:
- Els parèntesis són obligatoris. Sense ells,
preu - cost / preu * 100s'avaluaria compreu - ((cost / preu) * 100), perquè*i/tenen més prioritat que-(taula de precedència de 01-03). El resultat per al producte 1 seria12.50 - 62.4 = -49.90. No dona error: dona un número absurd. - La divisió és decimal, no entera, perquè
preuésNUMERICi noINTEGER. Si les columnes fossin enteres,(preu - cost) / preudonaria0per a totes les files i després0 * 100 = 0. És la fallada clàssica en calcular percentatges; es resol convertint un operand aNUMERICambCAST(mòdul 6). - La cua de decimals és lletja. PostgreSQL calcula la divisió
NUMERICamb precisió àmplia. Per presentar-ho calROUND(secció 7).
4.3. Altres expressions útils sobre una sola taula
SELECT nom,
stock,
preu,
stock * preu AS valor_inventari_pvp,
stock * cost AS valor_inventari_cost
FROM productes;| nom | stock | preu | valor_inventari_pvp | valor_inventari_cost |
|---|---|---|---|---|
| Oli d'oliva verge extra 500 ml | 120 | 12.50 | 1500.00 | 936.00 |
| Arròs integral ecològic 1 kg | 200 | 3.90 | 780.00 | 420.00 |
| Mel de tarongina crua 500 g | 80 | 9.75 | 780.00 | 432.00 |
| Pasta d'espelta 500 g | 150 | 2.80 | 420.00 | 202.50 |
| Tomàquet triturat ecològic 400 g | 300 | 1.95 | 585.00 | 270.00 |
| Espelmes de cera de soja (pack 2) | 0 | 13.75 | 0.00 | 0.00 |
(Selecció de files de les 20.)
Aquí stock és INTEGER i preu és NUMERIC(10,2): en barrejar tipus, PostgreSQL promou l'enter a NUMERIC i el resultat conserva dos decimals.
Compte amb la divisió entre zero. Si en comptes de
stock * preucalculessisalguna_cosa / stock, el producte 13 (stock 0) faria fallar la consulta sencera ambERROR: division by zero. La protecció es fa ambNULLIF, que es veu al mòdul 6.
- L'expressió estrella: l'import d'una línia de comanda
A 01-06 va quedar fixat que comandes no té columna total i que l'import d'una línia és:
Aquesta expressió apareixerà pràcticament a tots els mòduls que queden. Escrivim-la per primera vegada:
SELECT id,
comanda_id,
producte_id,
quantitat,
preu_unitari,
descompte,
quantitat * preu_unitari * (1 - descompte) AS import
FROM linies_comanda;| id | comanda_id | producte_id | quantitat | preu_unitari | descompte | import |
|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 2 | 11.95 | 0.00 | 23.9000 |
| 2 | 1 | 2 | 3 | 3.90 | 0.00 | 11.7000 |
| 3 | 1 | 14 | 2 | 3.25 | 0.00 | 6.5000 |
| 4 | 2 | 6 | 1 | 17.50 | 0.00 | 17.5000 |
| 5 | 2 | 9 | 2 | 4.60 | 0.00 | 9.2000 |
| 6 | 3 | 5 | 6 | 1.95 | 0.10 | 10.5300 |
| 7 | 3 | 4 | 4 | 2.80 | 0.00 | 11.2000 |
| 8 | 3 | 2 | 2 | 3.90 | 0.00 | 7.8000 |
| 9 | 4 | 15 | 1 | 22.00 | 0.00 | 22.0000 |
| 10 | 4 | 3 | 1 | 9.75 | 0.00 | 9.7500 |
| 11 | 5 | 10 | 1 | 11.20 | 0.00 | 11.2000 |
| 12 | 5 | 11 | 2 | 5.50 | 0.00 | 11.0000 |
(12 primeres de 47 files.)
Desmuntem l'expressió, perquè cada peça importa:
| Tros | Per què hi és |
|---|---|
quantitat * |
Unitats venudes d'aquell producte en aquella comanda |
preu_unitari |
El preu del moment de la venda, no l'actual. Per això la línia 1 fa servir 11.95 € i no els 12.50 € que avui costa el producte 1 |
(1 - descompte) |
descompte és una fracció: 0.10 = 10 %. 1 - 0.10 = 0.90, és a dir "es cobra el 90 %" |
| Els parèntesis | Sense ells, quantitat * preu_unitari * 1 - descompte restaria 0.10 € al total en comptes d'aplicar un 10 % |
Comprova la línia 6 a mà: 6 unitats × 1.95 € = 11.70 €; amb un 10 % de descompte, 11.70 × 0.90 = 10.53 €. Coincideix.
I fixa't en els quatre decimals: 10.5300, no 10.53. La quantitat és entera i no aporta escala, preu_unitari n'aporta 2 i (1 - descompte) altres 2, així que el resultat surt amb 4. Aritmèticament és correcte i per sumar és el que vols, però per ensenyar-ho a algú cal arrodonir.
Sis línies de les 47 porten descompte; aquests són els seus imports exactes:
| id | comanda_id | quantitat | preu_unitari | descompte | import |
|---|---|---|---|---|---|
| 6 | 3 | 6 | 1.95 | 0.10 | 10.5300 |
| 18 | 8 | 3 | 12.50 | 0.05 | 35.6250 |
| 24 | 10 | 2 | 18.90 | 0.10 | 34.0200 |
| 27 | 11 | 8 | 1.95 | 0.15 | 13.2600 |
| 39 | 16 | 2 | 11.20 | 0.05 | 21.2800 |
| 45 | 19 | 6 | 4.95 | 0.10 | 26.7300 |
Aquí hi ha un detall revelador: la línia 24 val 34.0200 € i la devolució de la comanda 10 registrada a devolucions és de 34.02 €. Les dades són coherents entre taules, i comprovar-ho amb una consulta serà un dels exercicis del mòdul 3.
Error freqüent: escriure
quantitat * preu_unitari * descompte. Això calcula l'import descomptat, no l'import cobrat. Per a la línia 6 donaria 1.17 € en comptes de 10.53 €.
- Concatenació de text:
|| i CONCAT
|| i CONCATL'operador estàndard de concatenació en SQL és ||:
| client | ciutat | pais |
|---|---|---|
| Lucía Martínez Soler | València | Espanya |
| Carlos Ferrer Ibáñez | València | Espanya |
| Marta Sanchis Gil | Castelló | Espanya |
| Javier Ortega Ruiz | Madrid | Espanya |
| Ana Belmonte Roca | Barcelona | Espanya |
| Pau Llorens Vidal | València | Espanya |
| Sofia Moreira Costa | Lisboa | Portugal |
| Tiago Almeida Nunes | Porto | Portugal |
| Camille Dubois | Lió | França |
| Julien Moreau | París | França |
| Elena Navarro Puig | Alacant | Espanya |
| Diego Ramos Herrera | Sevilla | Espanya |
| Núria Bosch Ferrer | Barcelona | Espanya |
| Hugo Iglesias Pardo | Saragossa | Espanya |
| Inés Carrasco Vega | València | Espanya |
Pots concatenar text amb números: PostgreSQL converteix el número a text automàticament.
| nom | etiqueta |
|---|---|
| Oli d'oliva verge extra 500 ml | Ref. 1 - 12.50 EUR |
| Arròs integral ecològic 1 kg | Ref. 2 - 3.90 EUR |
| Mel de tarongina crua 500 g | Ref. 3 - 9.75 EUR |
(3 primeres de 20 files.)
6.1. El parany de || amb NULL
Concatenar qualsevol cosa amb NULL dona NULL. Tot el text es perd. Aquesta és una de les sorpreses més cares de SQL, i BotigaVerda té dades per demostrar-ho: set clients tenen referit_per_id a NULL.
| nom | referit_per_id | origen |
|---|---|---|
| Lucía | (null) | (null) |
| Carlos | 1 | Referit pel client 1 |
| Marta | 1 | Referit pel client 1 |
| Javier | (null) | (null) |
| Ana | 2 | Referit pel client 2 |
| Pau | (null) | (null) |
| Sofia | (null) | (null) |
| Tiago | 7 | Referit pel client 7 |
| Camille | (null) | (null) |
| Julien | 9 | Referit pel client 9 |
| Elena | 6 | Referit pel client 6 |
| Diego | (null) | (null) |
| Núria | 5 | Referit pel client 5 |
| Hugo | (null) | (null) |
| Inés | 1 | Referit pel client 1 |
Set files amb origen buit, no set files amb el text i un forat. El literal 'Referit pel client ' desapareix del tot, perquè la regla dels nuls és que qualsevol operació amb un valor desconegut produeix un valor desconegut.
6.2. CONCAT tracta els nuls d'una altra manera
La funció CONCAT ignora els NULL i els substitueix per una cadena buida:
| nom | referit_per_id | origen |
|---|---|---|
| Lucía | (null) | Referit pel client |
| Carlos | 1 | Referit pel client 1 |
| Javier | (null) | Referit pel client |
| Ana | 2 | Referit pel client 2 |
(Selecció de files de les 15.)
Ja no es perd el text, però el resultat tampoc no és correcte: diu "Referit pel client" sense dir quin. La solució de debò és substituir el nul per un text sensat amb COALESCE, que s'estudia a la lliçó 06-04:
-- Avanç del mòdul 6
SELECT nom,
COALESCE('Referit pel client ' || referit_per_id, 'Va arribar pel seu compte') AS origen
FROM clients;Comparativa per tenir a mà:
| Aspecte | a || b | CONCAT(a, b) |
|---|---|---|
| Estàndard SQL | Sí | No (però molt estesa) |
| Amb NULL | Retorna NULL | Tracta el NULL com a '' |
| A MySQL | Per defecte no concatena: || és l'OR lògic | És la forma habitual |
| A SQL Server | No existeix; es fa servir + | Existeix des del 2012 |
| A SQLite | Sí | No existeix |
Nota de dialecte important: a MySQL,
'a' || 'b'retorna0, perquè allà||significaOR. Només es comporta com a concatenació si el servidor té activat el modePIPES_AS_CONCAT. Si escrius SQL que hagi de funcionar a MySQL i a PostgreSQL, fes servirCONCAT.
ROUND per presentar diners
ROUND per presentar dinersROUND(expressió, decimals) arrodoneix a la quantitat de decimals que indiquis:
SELECT nom,
preu,
ROUND(preu * 1.21, 2) AS preu_amb_iva,
ROUND((preu - cost) / preu * 100, 2) AS marge_pct
FROM productes;| nom | preu | preu_amb_iva | marge_pct |
|---|---|---|---|
| Oli d'oliva verge extra 500 ml | 12.50 | 15.13 | 37.60 |
| Arròs integral ecològic 1 kg | 3.90 | 4.72 | 46.15 |
| Mel de tarongina crua 500 g | 9.75 | 11.80 | 44.62 |
| Pasta d'espelta 500 g | 2.80 | 3.39 | 51.79 |
| Tomàquet triturat ecològic 400 g | 1.95 | 2.36 | 53.85 |
| Crema facial d'àloe vera 50 ml | 18.90 | 22.87 | 49.74 |
| Xampú sòlid de romaní 80 g | 8.40 | 10.16 | 57.14 |
| Oli corporal d'ametlles 200 ml | 14.25 | 17.24 | 50.18 |
| Bàlsam labial de calèndula 15 ml | 4.60 | 5.57 | 60.87 |
| Detergent ecològic concentrat 1 L | 11.20 | 13.55 | 46.43 |
| Fregall vegetal de lufa (pack 3) | 5.50 | 6.66 | 60.00 |
| Bosses reutilitzables de cotó (pack 5) | 9.90 | 11.98 | 56.57 |
| Espelmes de cera de soja (pack 2) | 13.75 | 16.64 | 49.82 |
| Infusió de camamilla ecològica 20 u | 3.25 | 3.93 | 56.92 |
| Te verd matcha cerimonial 30 g | 22.00 | 26.62 | 43.18 |
| Kombutxa de gingebre 750 ml | 4.95 | 5.99 | 53.54 |
| Suc de taronja premsat en fred 1 L | 5.40 | 6.53 | 51.85 |
| Raspall de dents de bambú | 3.50 | 4.24 | 65.71 |
| Desodorant natural en barra 50 g | 7.80 | 9.44 | 57.69 |
| Càpsules d'espirulina 120 u | 16.40 | 19.84 | 46.95 |
Ara sí que és una taula presentable. I amb ella ja pots respondre a una pregunta de negoci: el producte amb més marge percentual és el raspall de dents de bambú (65.71 %), i el que menys, l'oli d'oliva verge extra (37.60 %) —el producte estrella del catàleg és, precisament, el que deixa menys marge relatiu.
El mateix per a l'import de línia:
SELECT id,
comanda_id,
ROUND(quantitat * preu_unitari * (1 - descompte), 2) AS import
FROM linies_comanda;| id | comanda_id | import |
|---|---|---|
| 6 | 3 | 10.53 |
| 18 | 8 | 35.63 |
| 24 | 10 | 34.02 |
| 27 | 11 | 13.26 |
| 39 | 16 | 21.28 |
| 45 | 19 | 26.73 |
(Les 6 línies amb descompte, de les 47.)
Observa la línia 18: el valor exacte és 35.6250 i ROUND el deixa en 35.63. Sobre tipus NUMERIC, PostgreSQL arrodoneix "mig cap amunt" (allunyant-se del zero), que és el que espera qualsevol comptable.
Regla del curs: calcula amb l'expressió completa i arrodoneix només al final, per presentar. Si arrodoneixes cada línia i després sumes, el total pot diferir en cèntims del total arrodonit. Les funcions numèriques (
ROUND,CEIL,FLOOR,TRUNC,ABS) s'estudien a fons a la lliçó 06-02.
- Per què l'àlies no funciona a
WHERE però sí a ORDER BY
WHERE però sí a ORDER BYAquí és on l'ordre lògic de 02-01 deixa de ser teoria. Intenta filtrar per una columna calculada:
La taula existeix, l'àlies està escrit just a sobre, i tot i així el motor diu que aquesta columna no existeix. L'explicació és al diagrama:
flowchart LR
A["1 · FROM<br/>productes"] --> B["2 · WHERE<br/>❌ l'àlies encara NO existeix"]
B --> C["3 · SELECT<br/>✅ aquí NEIX l'àlies"]
C --> D["4 · ORDER BY<br/>✅ l'àlies ja existeix"]
D --> E["5 · LIMIT"]
Quan s'avalua WHERE, el pas SELECT encara no s'ha executat, així que el nom preu_amb_iva encara no s'ha creat. Quan s'avalua ORDER BY, sí.
Les dues solucions per filtrar per una expressió:
-- Opció A: repetir l'expressió al WHERE (sempre funciona)
SELECT nom,
preu * 1.21 AS preu_amb_iva
FROM productes
WHERE preu * 1.21 > 20;| nom | preu_amb_iva |
|---|---|
| Crema facial d'àloe vera 50 ml | 22.8690 |
| Te verd matcha cerimonial 30 g | 26.6200 |
-- Opció B: embolcallar la consulta en una subconsulta (mòdul 7)
SELECT nom, preu_amb_iva
FROM (SELECT nom, preu * 1.21 AS preu_amb_iva FROM productes) AS t
WHERE preu_amb_iva > 20;I a ORDER BY l'àlies funciona sense més (lliçó 02-05):
| nom | marge |
|---|---|
| Te verd matcha cerimonial 30 g | 9.50 |
| Crema facial d'àloe vera 50 ml | 9.40 |
| Càpsules d'espirulina 120 u | 7.70 |
| Oli corporal d'ametlles 200 ml | 7.15 |
| Espelmes de cera de soja (pack 2) | 6.85 |
(5 primeres de 20 files.)
Resum per memoritzar:
| Clàusula | Es pot fer servir un àlies del SELECT? |
Motiu |
|---|---|---|
WHERE |
No | S'executa abans que SELECT |
GROUP BY |
Sí a PostgreSQL (extensió), no a l'estàndard | Mòdul 4 |
HAVING |
No | Mòdul 4 |
ORDER BY |
Sí | S'executa després de SELECT |
Errors habituals i consells
- Oblidar
ASi perdre una coma.SELECT nom preu FROM productesno falla: retorna els noms sota la capçalerapreu. Compta sempre les columnes del resultat. - Àlies amb cometes simples.
AS 'Preu'és un error de sintaxi a PostgreSQL. Cometes dobles per a identificadors, simples per a cadenes. - Esperar que
AS PreuIVAconservi les majúscules. Sense cometes es plega apreuiva. - Fer servir un àlies a
WHERE.column "..." does not exist. Repeteix l'expressió o fes servir una subconsulta. - Oblidar els parèntesis al marge percentual.
preu - cost / preu * 100no dona error i retorna números sense sentit. - Confondre el descompte amb l'import descomptat. L'import cobrat és
quantitat * preu_unitari * (1 - descompte); sense l'1 -calcules justament el contrari. - Concatenar amb
||sobre columnes que poden ser nul·les. Perds tota la cadena. Fes servirCONCATo, millor,COALESCE(mòdul 6). - Arrodonir massa aviat. Arrodoneix només a la capa de presentació; els càlculs intermedis, amb tota la precisió.
- Consell: anomena els àlies com a columnes reals.
snake_case, en minúscules, descriptius:preu_amb_iva,marge_pct,import. Els àlies "bonics" amb cometes, només per a l'informe final. - Consell: valida l'expressió amb
SELECTsenseFROM.SELECT 8 * 1.95 * (1 - 0.15);et confirma en un segon si la fórmula és la que creus.
Exercicis
Exercici 1
Escriu una consulta sobre productes que retorni, amb àlies llegibles: el nom del producte, el seu preu, el seu marge unitari en euros i el seu marge percentual arrodonit a un decimal. Explica per què els parèntesis del marge percentual són imprescindibles.
Exercici 2
Sobre empleats, construeix una única columna de text anomenada fitxa amb aquest format exacte: Cognoms, Nom (Càrrec) - Ciutat. Per exemple: Alcázar Vives, Rosa (Directora general) - València.
Exercici 3
Sobre linies_comanda, retorna l'id de la línia, la comanda a la qual pertany, l'import brut (sense aplicar descompte), l'import descomptat en euros i l'import final cobrat, els tres arrodonits a dos decimals. Comprova els teus resultats amb les sis línies que tenen descompte.
Solucions
Solució 1
SELECT nom AS producte,
preu,
preu - cost AS marge_eur,
ROUND((preu - cost) / preu * 100, 1) AS marge_pct
FROM productes;| producte | preu | marge_eur | marge_pct |
|---|---|---|---|
| Oli d'oliva verge extra 500 ml | 12.50 | 4.70 | 37.6 |
| Arròs integral ecològic 1 kg | 3.90 | 1.80 | 46.2 |
| Mel de tarongina crua 500 g | 9.75 | 4.35 | 44.6 |
| Pasta d'espelta 500 g | 2.80 | 1.45 | 51.8 |
| Tomàquet triturat ecològic 400 g | 1.95 | 1.05 | 53.8 |
| Crema facial d'àloe vera 50 ml | 18.90 | 9.40 | 49.7 |
| Xampú sòlid de romaní 80 g | 8.40 | 4.80 | 57.1 |
| Oli corporal d'ametlles 200 ml | 14.25 | 7.15 | 50.2 |
| Bàlsam labial de calèndula 15 ml | 4.60 | 2.80 | 60.9 |
| Detergent ecològic concentrat 1 L | 11.20 | 5.20 | 46.4 |
(10 primeres de 20 files.)
Raonament sobre els parèntesis. La precedència d'operadors de 01-03 diu que * i / s'avaluen abans que -. Sense parèntesis, preu - cost / preu * 100 significa preu - ((cost / preu) * 100). Per al producte 1: 12.50 - ((7.80/12.50) * 100) = 12.50 - 62.40 = -49.90. Un marge negatiu de -49.90 en un producte que guanya 4.70 € per unitat. La consulta s'executa sense cap avís: és un error silenciós, el pitjor tipus.
Solució 2
| fitxa |
|---|
| Alcázar Vives, Rosa (Directora general) - València |
| Company Talens, Andrés (Responsable de vendes) - València |
| Nadal Ripoll, Beatriz (Responsable de logística) - València |
| Peris Blasco, Óscar (Comercial) - València |
| Puig Sanchis, Laia (Comercial) - Castelló |
| Estévez Roig, Marc (Atenció al client) - València |
| Salvador Mira, Irene (Operària de magatzem) - València |
| Vercher Lluch, Daniel (Analista de dades) - València |
Raonament. S'alternen columnes i literals de text: els literals van entre cometes simples i porten a dins els espais, comes i parèntesis del format. Han sortit les 8 files completes perquè en aquesta taula cap de les quatre columnes utilitzades no és nul·la. Si ciutat ho fos —i podria ser-ho, perquè la columna admet nuls—, aquella fila retornaria NULL sencera. En una consulta destinada a producció convindria blindar-la amb COALESCE(ciutat, 'Sense assignar'), que veuràs a 06-04.
Solució 3
SELECT id,
comanda_id,
ROUND(quantitat * preu_unitari, 2) AS import_brut,
ROUND(quantitat * preu_unitari * descompte, 2) AS descompte_eur,
ROUND(quantitat * preu_unitari * (1 - descompte), 2) AS import_final
FROM linies_comanda;Les sis línies amb descompte, de les 47 que retorna la consulta:
| id | comanda_id | import_brut | descompte_eur | import_final |
|---|---|---|---|---|
| 6 | 3 | 11.70 | 1.17 | 10.53 |
| 18 | 8 | 37.50 | 1.88 | 35.63 |
| 24 | 10 | 37.80 | 3.78 | 34.02 |
| 27 | 11 | 15.60 | 2.34 | 13.26 |
| 39 | 16 | 22.40 | 1.12 | 21.28 |
| 45 | 19 | 29.70 | 2.97 | 26.73 |
Raonament. Les tres columnes comparteixen la base quantitat * preu_unitari; el que canvia és què es fa amb descompte: multiplicar per descompte dona el que el client s'estalvia, multiplicar per (1 - descompte) dona el que paga. La comprovació que la fórmula és correcta és que descompte_eur + import_final = import_brut a totes les files. A la línia 18 hi ha una diferència d'un cèntim aparent (1.88 + 35.63 = 37.51 ≠ 37.50): és l'efecte d'arrodonir cada columna per separat, ja que els valors exactes són 1.8750 i 35.6250. És exactament el motiu pel qual s'arrodoneix al final i no a cada pas intermedi.
Conclusió
Ara les teves consultes no només llegeixen: calculen.
- Un àlies amb
ASdona nom a qualsevol columna o expressió; sense ell veuràs?column?. EscriuASsempre, encara que sigui opcional. - Les cometes dobles en un àlies només són necessàries si conté espais, símbols o majúscules que vulguis conservar: fes-les servir únicament per a àlies de presentació.
- Els àlies de taula semblen superflus amb una sola taula i seran obligatoris al mòdul 3.
- Saps construir columnes calculades: preu amb IVA, marge en euros i marge percentual, amb els parèntesis al seu lloc i sense caure en la divisió entera.
- Domines l'expressió que sosté tot el curs:
quantitat * preu_unitari * (1 - descompte), i entens per què el descompte és una fracció i per què el resultat surt amb quatre decimals. - Concatenes text amb
||i coneixes el seu parany: qualsevol operandNULLanul·la tota la cadena.CONCATl'evita,COALESCE(mòdul 6) el resol bé. - Presentes imports amb
ROUND(expressió, 2), arrodonint només al final. - I, sobretot, entens per l'ordre lògic d'execució per què un àlies encara no existeix a
WHEREi sí aORDER BY.
A la lliçó següent, Filtrar dades amb WHERE, afegiràs el pas 2 del diagrama: deixaràs de portar les 20 files de productes o les 47 de linies_comanda i començaràs a demanar només les que compleixen una condició. Amb comparacions sobre números, text i dates, i amb AND, OR, NOT i uns parèntesis que, un cop més, marcaran la diferència entre un resultat correcte i un de silenciosament equivocat.
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
