Aritmética en una consulta
En resumen: En SELECT puedes calcular con columnas (+, -, *, /) para cada fila y redondear con ROUND, pero en SQLite, PostgreSQL y SQL Server dividir dos enteros descarta la parte decimal.
Problema
¿Cuánto cuesta esta línea?
Contabilidad quiere saber, para cada línea de pedido, cuánto cuesta: la cantidad por el precio. La tabla order_items solo tiene los dos números:
El pedido 3 tiene manzanas, 4 a 2,10 €, y detergente en polvo, 3 a 12,50 €. Calcular a mano 152 líneas no es trabajo para una persona. Y guardar el total en otra columna más significa mantenerlo correcto después de cada cambio.
La idea
Una columna calculada
Además de columnas, SELECT puede contener expresiones: cálculos con las columnas. La base los calcula para cada fila:
Los operadores son +, -, *, / y % (el resto de una división). La columna calculada se llama como la propia expresión, así que le das un alias corto con AS. La tabla no cambia: el cálculo existe solo en el resultado.
También puedes ordenar por el alias. Las cinco líneas más caras de todos los pedidos:
Una expresión funciona también sin tabla. Entonces SELECT la calcula una vez, como una calculadora. La multiplicación va antes que la suma, y los paréntesis cambian el orden:
Pruébalo
El precio con IVA
Los precios de la base son sin IVA. Muestra el nombre, el precio y el precio con un 20 % de IVA en una columna llamada with_vat.
Solución
SELECT name, price, price * 1.2 AS with_vat FROM products;price * 1.2 AS with_vat. Con un 20 % más, el precio es el 120 % del anterior, es decir, 1,2 veces. El pan blanco sale a 1,44 €. Aquí la comprobación también mira los nombres de las columnas.
Míralo
La puntuación como porcentaje
El sitio web quiere mostrar las puntuaciones de 1 a 5 como porcentajes: 5 es 100 %, 4 es 80 %. Ejecuta:
Esto es la división entera. Cuando los dos números son enteros, el resultado también lo es:
En cuanto uno de los números es una fracción (2.0), o se convierte en una con CAST(… AS REAL), la división conserva la parte decimal. Para los porcentajes basta con multiplicar primero, por 100.0:
Con price esta trampa no ocurre: el precio es un número con decimales (REAL). Ojo con las columnas que guardan enteros, como rating, quantity y stock.
Más precisamente, para curiosos
PostgreSQL y SQL Server dividen los enteros igual: 5 / 2 es 2. MySQL hace lo contrario: allí 5 / 2 es 2.5000, y la división entera tiene su propio operador, DIV. Dividir entre cero da NULL en SQLite y un error en PostgreSQL.
La idea
ROUND: al céntimo
Una promoción: 15 % de descuento en los lácteos. El precio nuevo es el 85 % del anterior:
Nadie puede pagar 0,935 € por un yogur. ROUND(x, 2) redondea a dos dígitos después del punto, es decir, al céntimo. ROUND(x) redondea a un número entero.
Mira el queso blanco: 6.715 se volvió 6.71, no 6.72. Por qué, lo ves más abajo.
Más precisamente, para curiosos
Los números con decimales se guardan en la computadora en binario, y en binario el 0.1 no tiene una forma exacta, igual que 1/3 no la tiene en cifras decimales. Por eso:
La pantalla muestra 0.3, pero la comparación dice «no» (0). printf con %!.20f muestra lo que de verdad está guardado. El queso blanco es la misma historia: 7.9 × 0.85 es 6.71499… en memoria, y ROUND lo redondea hacia abajo con honestidad.
Por eso los sistemas reales no guardan el dinero como REAL. Lo guardan en céntimos enteros (1,20 € es 120), o en un tipo para números decimales exactos: NUMERIC(10, 2) o DECIMAL(10, 2) en PostgreSQL, MySQL y SQL Server. SQLite no tiene un tipo así, de modo que allí el camino son los céntimos:
En céntimos, 790 × 85 es exactamente 67 150, y al dividir entre 100 da 671.5 céntimos, que se redondean a 672, es decir, 6,72 €.
Pruébalo
La promoción
Muestra el nombre, el precio y el precio de oferta de cada producto. El precio de oferta es price * 0.85, redondeado al céntimo, en una columna llamada sale_price.
Solución
SELECT name, price, ROUND(price * 0.85, 2) AS sale_price FROM products;ROUND(price * 0.85, 2) AS sale_price. ROUND envuelve toda la expresión: primero se calcula, luego se redondea.
Ejercicio
Dos tareas
1. La aseguradora pregunta cuánto vale la mercancía del almacén. Muestra los cinco productos con mayor valor en existencias (precio por existencias), el mayor primero. La tarjeta de regalo no es mercancía en un estante: conserva solo los productos que tienen categoría.
Nombre, stock y stock_value, los cinco mayores:
Solución
SELECT name, stock, price * stock AS stock_value
FROM products
WHERE category_id IS NOT NULL
ORDER BY stock_value DESC
LIMIT 5;price * stock AS stock_value, WHERE category_id IS NOT NULL, ORDER BY stock_value DESC LIMIT 5. El café en grano va primero: 15 paquetes a 14,90 € son 223,50 €. Aquí la comprobación también mira el orden.
2. La mercancía llega en cajas de 12. Para cada producto con categoría que haya en existencia, muestra cuántas cajas completas hay (boxes) y cuántas unidades quedan fuera de ellas (loose).
Nombre, stock, boxes y loose:
Solución
SELECT name, stock, stock / 12 AS boxes, stock % 12 AS loose
FROM products
WHERE stock > 0 AND category_id IS NOT NULL;stock / 12 AS boxes, stock % 12 AS loose. Aquí la división entera es justo lo que quieres: 40 panes son 3 cajas completas y 4 sueltos.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: SELECT: elegir columnas · WHERE: filtrar filas · NULL: sin valor · ORDER BY, LIMIT y DISTINCT
- Continúa en: Funciones de texto · Funciones de fecha · CASE y los valores que faltan · Funciones de agregación: COUNT, SUM, AVG
- Ejercicios sobre el tema: Expresiones y funciones