4 Selección de datos

La sentencia SELECT es, con diferencia, la más compleja de SQL. Permite desde mostrar valores de constantes o funciones, a hacer consultas en una tabla o composiciones en varias tablas juntas, limitando las columnas a mostrar, renombrándolas o creándolas; limitando el número de columnas, ordenandolas, etc.

Pero la sentencia SELECT no se limita a mostrar el contenido de una tabla o parte de ella, lo que hace en realidad es crear una tabla, o más precisamente, una relación (recordemos que SQL maneja bases de datos relacionales). Es decir, el resultado de una sentencia SELECT sobre una tabla o un conjunto de tablas, es una tabla. Esa tabla resultado tendrá un número determinado de filas, y un número de columnas, cada una con su nombre.

Esta es una de las sentencias que menos diferencias tiene con el SQL estándar en SQLite, de modo que en este capítulo repasaremos un poco sus diferentes posibilidades.

Mostrar constantes y funciones

Esta es la forma más sencilla. Podemos mostrar un valor:

sqlite> SELECT sqlite_version();
3.7.3
sqlite>

O varios, separados por comas:

sqlite> .headers on
sqlite> SELECT round(122.32), "Hola", random();
round(122.32)|"Hola"|random()
122.0|Hola|-3071908159697118318
sqlite>

Hemos usado el comando de consola .headers on para que se muestren las cabeceras en los listados, indicando los nombres de las columnas.

Renombrar columnas

Siempre es posible cambiar el nombre de cada columna en la tabla resultado, usando la cláusula AS. Así, por ejemplo, la última consulta puede ser modificada para que cada columna tenga un nombre más manejable:

sqlite> SELECT round(122.32) AS numero, "Hola" AS saludo, random() AS aleatorio;
numero|saludo|aleatorio
122.0|Hola|8855590400098358693
sqlite>

Más adelante usaremos este mecanismo para renombrar columnas calculadas por la aplicaciones de funciones agregadas (de grupos).

Contenido de tablas

Donde se complica la sintaxis de SELECT es al mostrar el contenido de tablas y composiciones.

Limitar columnas

La principal aplicación de las sentencias SELECT es mostrar todo o parte del contenido de una tabla. Es su forma más general mostraremos todas las filas y columnas, las columnas se muestran en el orden en que fueron creadas en la sentencia CREATE TABLE. Las filas en un orden arbitrario:

sqlite> SELECT * FROM usuario;
Fulano|fulano@dominio.com
Mengano|mengano@dominio.com
Tulano|tulano@dominio.com
Sillano|sillano@dominio.com
Cascasano|
sqlite>

Podemos seleccionar algunas columnas, indicando sus nombres, y separadas con comas:

sqlite> SELECT rowid,nombre FROM usuario;
rowid|nombre
1|Fulano
2|Mengano
3|Tulano
4|Sillano
5|Cascasano
sqlite>

Podemos renombrar columnas cuando se

Limitar filas

Para limitar el número de filas hay dos caminos diferentes, limitar filtrando por ciertos valores de columnas o grupos de columnas o limitar el rango de filas a mostrar.

Cláusula WHERE

La cláusula WHERE permite filtrar los resultados, dejando sólo aquellas filas que cumplan determinadas condiciones. Después de una cláusula WHERE se puede colocar cualquier expresión booleana:

sqlite> SELECT * FROM usuario WHERE 1;
nombre|email
Fulano|fulano@dominio.com
Mengano|mengano@dominio.com
Tulano|tulano@dominio.com
Sillano|sillano@dominio.com
Cascasano|
sqlite>

Aunque suele ser más útil usar expresiones que involucren a alguna columna:

sqlite> SELECT * FROM usuario WHERE nombre LIKE "%lano";
nombre|email
Fulano|fulano@dominio.com
Tulano|tulano@dominio.com
Sillano|sillano@dominio.com
sqlite>

Este último ejemplo muestra una relación con las filas de usuarios cuyo nombre termina en "lano".

Cláusula HAVING

El uso de esta cláusula es más esquivo. Sirve para lo mismo que WHERE, pero se aplica sobre columnas creadas con funciones agregadas. Para ver su uso crearemos y poblaremos una nueva tabla:

sqlite> CREATE TABLE pedidos (
   ...> fecha DATE,
   ...> referencia TEXT,
   ...> cantidad INTEGER);
sqlite> INSERT INTO pedidos VALUES(date('now', '-10 days'), 123, 321);
sqlite> INSERT INTO pedidos VALUES(date('now', '-10 days'), 125, 120);
sqlite> INSERT INTO pedidos VALUES(date('now', '-10 days'), 132, 100);
sqlite> INSERT INTO pedidos VALUES(date('now', '-5 days'), 123, 95);
sqlite> INSERT INTO pedidos VALUES(date('now', '-5 days'), 132, 174);
sqlite> INSERT INTO pedidos VALUES(date('now', '-5 days'), 154, 98);
sqlite> INSERT INTO pedidos VALUES(date('now', '-5 days'), 178, 150);
sqlite> INSERT INTO pedidos VALUES(date('now', '-2 days'), 125, 50);
sqlite> INSERT INTO pedidos VALUES(date('now', '-2 days'), 126, 150);
sqlite> INSERT INTO pedidos VALUES(date('now', '-2 days'), 132, 250);
sqlite> INSERT INTO pedidos VALUES(date('now', '-2 days'), 178, 140);
sqlite> INSERT INTO pedidos VALUES(date('now', '-2 days'), 180, 100);
sqlite> SELECT * FROM pedidos;
fecha|referencia|cantidad
2012-03-13|123|321
2012-03-13|125|120
2012-03-13|132|100
2012-03-18|123|95
2012-03-18|132|174
2012-03-18|154|98
2012-03-18|178|150
2012-03-21|125|50
2012-03-21|126|150
2012-03-21|132|250
2012-03-21|178|140
2012-03-21|180|100
sqlite>

Ahora haremos una cosulta en la que sumaremos las columnas 'cantidad' para cada 'referencia' distinta:

sqlite> SELECT referencia,sum(cantidad) FROM pedidos GROUP BY referencia;
referencia|sum(cantidad)
123|416
125|170
126|150
132|524
154|98
178|290
180|100
sqlite>

Si queremos limitar el número de filas a las que la suma de cantidades sea menor de 160 no podremos usar la cláusula WHERE:

sqlite> SELECT referencia,sum(cantidad) FROM pedidos WHERE sum(cantidad)<160 GROUP BY referencia;
Error: misuse of aggregate: sum()
sqlite>

En su lugar debemos usar HAVING:

sqlite> SELECT referencia,sum(cantidad) FROM pedidos GROUP BY referencia HAVING sum(cantidad)<160;
referencia|sum(cantidad)
126|150
154|98
180|100
sqlite> 

O, renombrando la columna de la suma:

sqlite> SELECT referencia,sum(cantidad) AS suma FROM pedidos GROUP BY referencia HAVING suma<160;
referencia|suma
126|150
154|98
180|100
sqlite>

Cláusula LIMIT

Por último, la cláusula LIMIT nos permite limitar el número de filas de la rabla de salida:

sqlite> SELECT * FROM pedidos LIMIT 4;
fecha|referencia|cantidad
2012-03-13|123|321
2012-03-13|125|120
2012-03-13|132|100
2012-03-18|123|95
sqlite> 

La cláusula opcional OFFSET permite indicar un desplazamiento, por ejemplo, para obtener las cuatro filas a partir de la tercera, indicaremos un límite de 4 con un desplazamiento de 2:

SELECT * FROM pedidos LIMIT 4 OFFSET 2;
fecha|referencia|cantidad
2012-03-13|132|100
2012-03-18|123|95
2012-03-18|132|174
2012-03-18|154|98

Si no se especifica una cláusula ORDER BY el orden es el mismo en que se almacenan en la tabla de origen.

Ordenar las filas

Mediante la cláusula ORDER BY podemos establecer distintos criterios para ordenar las filas. A continuación de la cláusula se especifica un nombre de columna o varios, separados por comas. Para cada columna podemos elegir un orden ascendente ASC, que es el orden por defecto; o descendente DESC:

sqlite> SELECT * FROM pedidos ORDER BY fecha DESC;
fecha|referencia|cantidad
2012-03-21|125|50
2012-03-21|126|150
2012-03-21|132|250
2012-03-21|178|140
2012-03-21|180|100
2012-03-18|123|95
2012-03-18|132|174
2012-03-18|154|98
2012-03-18|178|150
2012-03-13|123|321
2012-03-13|125|120
2012-03-13|132|100
sqlite> SELECT * FROM pedidos ORDER BY fecha DESC, cantidad ASC;
fecha|referencia|cantidad
2012-03-21|125|50
2012-03-21|180|100
2012-03-21|178|140
2012-03-21|126|150
2012-03-21|132|250
2012-03-18|123|95
2012-03-18|154|98
2012-03-18|178|150
2012-03-18|132|174
2012-03-13|132|100
2012-03-13|125|120
2012-03-13|123|321
sqlite>

Agrupar filas

Usando la cláusula GROUP BY podemos agrupar filas por una o varias columnas, separadas con comas:

sqlite> SELECT * FROM pedidos GROUP BY referencia;
fecha|referencia|cantidad
2012-03-18|123|95
2012-03-21|125|50
2012-03-21|126|150
2012-03-21|132|250
2012-03-18|154|98
2012-03-21|178|140
2012-03-21|180|100
sqlite> SELECT fecha,count(*) AS items FROM pedidos GROUP BY fecha;
fecha|items
2012-03-13|3
2012-03-18|4
2012-03-21|5
sqlite>

Por supuesto, si queremos filtrar los resultados por algún criterio, hay que tener en cuenta que esta última consulta es agregada, y por lo tanto, hay que usar la cláusula HAVING.

sqlite> SELECT fecha,count(*) AS items FROM pedidos GROUP BY fecha HAVING items>3;
fecha|items
2012-03-18|4
2012-03-21|5
sqlite>

Eliminar filas duplicadas

En toda relación (o tabla) en una base de datos relacional, no debe haber filas repetidas. Esto es parte de la definición de las bases de datos relacionales. La sentencia SELECT permite eliminar filas duplicadas añadiendo la cláusula DISTINT:

sqlite> SELECT DISTINCT referencia FROM pedidos;
referencia
123
125
126
132
154
178
180
sqlite>