Sintaxis de consultas

Las instrucciones de consulta analizan una o más tablas o expresiones y muestran las filas de resultados calculados. En esta sección, se describe la sintaxis para consultas de SQL en SQL de Cloud Spanner.

Sintaxis de SQL

query_statement:
    [ statement_hint_expr ][ table_hint_expr ][ join_hint_expr ]
query_expr statement_hint_expr: '@{' statement_hint_key = statement_hint_value [, ...] '}' statement_hint_key: { USE_ADDITIONAL_PARALLELISM } query_expr: [ WITH with_query_name AS ( query_expr ) [, ...] ] { select | ( query_expr ) | query_expr set_op query_expr } [ ORDER BY expression [{ ASC | DESC }] [, ...] ] [ LIMIT count [ OFFSET skip_rows ] ] select: SELECT [{ ALL | DISTINCT }] { [ expression. ]* | expression [ [ AS ] alias ] } [, ...] [ FROM from_item [ tablesample_type ] [, ...] ] [ WHERE bool_expression ] [ GROUP BY expression [, ...] ] [ HAVING bool_expression ] set_op: UNION { ALL | DISTINCT } | INTERSECT { ALL | DISTINCT } | EXCEPT { ALL | DISTINCT } from_item: { table_name [ table_hint_expr ] [ [ AS ] alias ] | join | ( query_expr ) [ table_hint_expr ] [ [ AS ] alias ] | field_path | { UNNEST( array_expression ) | UNNEST( array_path ) | array_path } [ table_hint_expr ] [ [ AS ] alias ] [ WITH OFFSET [ [ AS ] alias ] ] | with_query_name [ table_hint_expr ] [ [ AS ] alias ] } table_hint_expr: '@{' table_hint_key = table_hint_value '}' table_hint_key: { FORCE_INDEX | GROUPBY_SCAN_OPTIMIZATION } join: from_item [ join_type ] [ join_method ] JOIN [ join_hint_expr ] from_item [ { ON bool_expression | USING ( join_column [, ...] ) } ] join_type: { INNER | CROSS | FULL [OUTER] | LEFT [OUTER] | RIGHT [OUTER] }

join_method:
{ HASH }
join_hint_expr: '@{' join_hint_key = join_hint_value [, ...] '}' join_hint_key: { FORCE_JOIN_ORDER | JOIN_METHOD } tablesample_type: TABLESAMPLE sample_method (sample_size percent_or_rows ) sample_method: { BERNOULLI | RESERVOIR } sample_size: numeric_value_expression percent_or_rows: { PERCENT | ROWS }

Notación:

  • Los corchetes “[ ]” indican cláusulas opcionales.
  • Los paréntesis “( )” indican paréntesis literales.
  • La barra vertical “|” indica un OR lógico.
  • Las llaves “{ }” encierran un conjunto de opciones.
  • Una coma seguida de puntos suspensivos entre corchetes “[, … ]” indica que el elemento anterior se puede repetir en una lista separada por comas.

Sugerencias de instrucciones

Las siguientes sugerencias son compatibles con las instrucciones de consulta:

Sugerencia de clave Valores posibles Descripción
USE_ADDITIONAL_PARALLELISM TRUE
FALSE (valor predeterminado)
Si fuese TRUE, el motor de ejecución favorecerá el uso de más paralelismo cuando sea posible. Debido a que esto puede reducir los recursos disponibles para otras operaciones, es recomendable que evites esta sugerencia si ejecutas operaciones sensibles a la latencia en la misma instancia.

Lista SELECT

Sintaxis:

SELECT  [{ ALL | DISTINCT }]
    { [ expression. ]* | expression [ [ AS ] alias ] } [, ...]

La lista SELECT define las columnas que mostrará la consulta. Las expresiones de la lista SELECT se pueden referir a columnas en cualquiera de los from_item en su cláusula FROM correspondiente.

Cada elemento de la lista SELECT es uno de los siguientes:

  • *
  • expression
  • expression.*

SELECT *

SELECT *, conocida como seleccionar Destacar, genera una columna de salida para cada columna que es visible después de ejecutar la consulta completa.

SELECT * FROM (SELECT "apple" AS fruit, "carrot" AS vegetable);

+-------+-----------+
| fruit | vegetable |
+-------+-----------+
| apple | carrot    |
+-------+-----------+

expression de SELECT

Los elementos en una lista SELECT pueden ser expresiones. Estas expresiones se evalúan en un solo valor y producen una columna de salida, con un alias explícito opcional.

Si la expresión no tiene un alias explícito, de ser posible, recibe un alias implícito según las reglas de los alias implícitos. De lo contrario, la columna será anónima y no se podrá hacer referencia a ella por su nombre en ninguna otra parte de la consulta.

expression.* de SELECT

Un elemento de una lista SELECT también puede adoptar la forma de expression.*. Esto produce una columna de salida para cada columna o campo de nivel superior expression. La expresión debe ser un alias de tabla o evaluar un solo valor de un tipo de datos con campos, como un STRUCT.

La siguiente consulta genera una columna de salida para cada columna en la tabla groceries, con un alias g.

WITH groceries AS
  (SELECT "milk" AS dairy,
   "eggs" AS protein,
   "bread" AS grain)
SELECT g.*
FROM groceries AS g;

+-------+---------+-------+
| dairy | protein | grain |
+-------+---------+-------+
| milk  | eggs    | bread |
+-------+---------+-------+

Más ejemplos:

WITH locations AS
  (SELECT STRUCT("Seattle" AS city, "Washington" AS state) AS location
  UNION ALL
  SELECT STRUCT("Phoenix" AS city, "Arizona" AS state) AS location)
SELECT l.location.*
FROM locations l;

+---------+------------+
| city    | state      |
+---------+------------+
| Seattle | Washington |
| Phoenix | Arizona    |
+---------+------------+
WITH locations AS
  (SELECT ARRAY<STRUCT<city STRING, state STRING>>[("Seattle", "Washington"),
    ("Phoenix", "Arizona")] AS location)
SELECT l.LOCATION[offset(0)].*
FROM locations l;

+---------+------------+
| city    | state      |
+---------+------------+
| Seattle | Washington |
+---------+------------+

Modificadores SELECT

Puedes modificar los resultados que se muestran de una consulta SELECT, de la siguiente manera.

SELECT DISTINCT

Una declaración SELECT DISTINCT descarta las filas duplicadas y muestra solo las filas restantes. SELECT DISTINCT no puede mostrar las columnas de los siguientes tipos:

  • STRUCT
  • ARRAY

SELECT ALL

Una declaración SELECT ALL muestra todas las filas, incluidas las filas duplicadas. SELECT ALL es el comportamiento predeterminado de SELECT.

Usa STRUCT con SELECT

  • No se admiten las consultas que muestran un STRUCT en la raíz del tipo de datos que se muestra. Por ejemplo, no se admite la siguiente consulta:

    SELECT STRUCT(1, 2) FROM Users;
    
  • Sí se admite la muestra de un arreglo de structs en la raíz del tipo de datos que se muestra. Por ejemplo, se admite la siguiente consulta:

    SELECT ARRAY(SELECT STRUCT(1, 2)) FROM Users;
    
  • Sin embargo, no se admiten las formas de consulta que pueden mostrar un struct NULL en el resultado de una consulta, por lo que la siguiente consulta no es compatible:

    SELECT ARRAY(SELECT IF(TRUE, STRUCT(1, 2), NULL)) FROM Users;
    

Consulta también las notas sobre el uso de STRUCTs en subconsultas.

Alias

Consulta la sección Alias para obtener información sobre la sintaxis y la visibilidad de los alias de la lista SELECT.

Cláusula FROM

La cláusula FROM indica la tabla o tablas de las cuales se pueden recuperar filas y especifica cómo unir esas filas a fin de producir una sola secuencia de filas para procesar en el resto de la consulta.

Sintaxis

from_item: {
    table_name [ table_hint_expr ] [ [ AS ] alias ] |
    join |
    ( query_expr ) [ table_hint_expr ] [ [ AS ] alias ] |
    field_path |
    { UNNEST( array_expression ) | UNNEST( array_path ) | array_path }
        [ table_hint_expr ] [ [ AS ] alias ] [ WITH OFFSET [ [ AS ] alias ] ] |
    with_query_name [ table_hint_expr ] [ [ AS ] alias ]
}
table_hint_expr: '@{' table_hint_key = table_hint_value '}' table_hint_key: { FORCE_INDEX | GROUPBY_SCAN_OPTIMIZATION }

table_name

El nombre de una tabla existente.

SELECT * FROM Roster;
Sugerencias de tablas

Las siguientes sugerencias son compatibles con las tablas:

Sugerencia de clave Valores posibles Descripción
FORCE_INDEX String. El nombre de un índice existente en la base de datos o _BASE_TABLE para usar la tabla base en lugar de un índice.
  • Si se establece en el nombre de un índice, usa ese índice en lugar de la tabla base. Si el índice no puede proporcionar todas las columnas necesarias, realiza una unión posterior con la tabla base.
  • Si se establece en la string _BASE_TABLE, usa la tabla base para la estrategia de índice en lugar de un índice. Ten en cuenta que este es el único valor válido cuando se usa FORCE_INDEX en una expresión de sugerencia de instrucción.

Nota: En realidad, FORCE_INDEX es una directiva, no una sugerencia, lo que significa que se genera un error si el índice no existe.

GROUPBY_SCAN_OPTIMIZATION TRUE
FALSE

La optimización de análisis de agrupación puede acelerar las consultas si se usa GROUP BY o SELECT DISTINCT. Se puede aplicar si las claves de agrupación pueden formar un prefijo de la tabla subyacente o la clave de índice (o una coincidencia exacta con ellas) y, también, si la consulta solo requiere la primera fila de cada grupo.

Por lo general, esta optimización se aplica cuando el optimizador decide que la consulta será más eficiente. La sugerencia anula esa decisión. Si la sugerencia se establece en FALSE, no se considera la optimización. Si la sugerencia se establece en TRUE, la optimización se aplicará siempre que sea legal hacerlo.

En el siguiente ejemplo, se muestra cómo usar un índice secundario cuando se lee desde una tabla, mediante la adición de una directiva de índice del formulario @{FORCE_INDEX=index_name} al nombre de la tabla:

SELECT s.SingerId, s.FirstName, s.LastName, s.SingerInfo
FROM Singers@{FORCE_INDEX=SingersByFirstLastName} AS s
WHERE s.FirstName = "Catalina" AND s.LastName > "M";

Puedes incluir varios índices en una consulta, aunque solo se admite un único índice para cada referencia de tabla. Ejemplo:

SELECT s.SingerId, s.FirstName, s.LastName, s.SingerInfo, c.ConcertDate
FROM Singers@{FORCE_INDEX=SingersByFirstLastName} AS s JOIN
     Concerts@{FORCE_INDEX=ConcertsBySingerId} AS c ON s.SingerId = c.SingerId
WHERE s.FirstName = "Catalina" AND s.LastName > "M";

Obtén más información sobre las directivas de índice en la sección sobre índices secundarios.

join

Consulta la sección Tipos de JOIN, que se muestra a continuación.

select

( select ) [ [ AS ] alias ] es una subconsulta de tabla.

field_path

En la cláusula FROM, field_path es cualquier ruta que se resuelva en un campo dentro de un tipo de datos. field_path puede analizar una estructura de datos anidada, de manera arbitraria, en más profundidad.

Estos son algunos ejemplos de valores válidos de field_path que incluyen lo siguiente:

SELECT * FROM T1 t1, t1.array_column;

SELECT * FROM T1 t1, t1.struct_column.array_field;

SELECT (SELECT ARRAY_AGG(c) FROM t1.array_column c) FROM T1 t1;

SELECT a.struct_field1 FROM T1 t1, t1.array_of_structs a;

SELECT (SELECT STRING_AGG(a.struct_field1) FROM t1.array_of_structs a) FROM T1 t1;

Las rutas de campo en la cláusula FROM deben terminar en un campo de arreglo. Además, las rutas de campo no pueden contener arreglos antes del final de la ruta de acceso. Por ejemplo, la ruta array_column.some_array.some_array_field no es válida, ya que contiene un arreglo antes del final de la ruta de acceso.

Nota: Si una ruta de acceso tiene solo un nombre, se interpreta como una tabla. Para solucionar esto, une la ruta con UNNEST o usa la ruta de acceso calificada por completo.

Nota: Si una ruta de acceso tiene más de un nombre y coincide con un nombre de campo, se interpreta como un nombre de campo. Para forzar que la ruta se interprete como un nombre de tabla, une la ruta mediante `.

UNNEST

El operador UNNEST toma un ARRAY y muestra una tabla con una fila por cada elemento en el ARRAY. También puedes usar UNNEST fuera de la cláusula FROM con el operador IN.

Para los ARRAY de entrada de la mayoría de los tipos de elementos, la salida de UNNEST, por lo general, tiene una columna. Esta columna única tiene un alias opcional, que puedes usar para referirte a la columna en otras partes de la consulta. Los ARRAYS con estos tipos de elementos muestran varias columnas:

  • STRUCT

UNNEST destruye el orden de los elementos en el ARRAY de entrada. Usa la cláusula WITH OFFSET opcional para mostrar una segunda columna con los índices de los elementos del arreglo (consulta la información que se detalla a continuación).

Para un ARRAY de entrada de STRUCT, UNNEST muestra una fila de cada STRUCT, con una columna aparte de cada campo en STRUCT. El alias de cada columna es el nombre del campo STRUCT correspondiente.

Ejemplo

SELECT *
FROM UNNEST(ARRAY<STRUCT<x INT64, y STRING>>[(1, 'foo'), (3, 'bar')]);

+---+-----+
| x | y   |
+---+-----+
| 3 | bar |
| 1 | foo |
+---+-----+

El ARRAY desanidado puede ser explícito o implícito. En el desanidado explícito, array_expression debe mostrar un valor de ARRAY, pero no necesita resolverse en un ARRAY y, además, se requiere la palabra clave UNNEST.

Ejemplo:

SELECT * FROM UNNEST ([1, 2, 3]);

En el desanidado implícito, array_path debe resolverse en un ARRAY y, además, la palabra clave UNNEST es opcional.

Ejemplo:

SELECT x
FROM mytable AS t,
  t.struct_typed_column.array_typed_field1 AS x;

En este caso, array_path puede analizar una estructura de datos, de manera arbitraria, en más profundidad, pero el último campo debe ser de tipo ARRAY. Ningún campo anterior en la expresión puede ser de tipo ARRAY, ya que no es posible extraer un campo nombrado de un ARRAY.

UNNEST trata los NULL de la siguiente manera:

  • Los NULL y ARRAY vacíos no producen filas.
  • Un ARRAY que contiene NULL produce filas que contienen valores NULL.

La cláusula opcional OFFSET WITH muestra una columna aparte que contiene el valor de “desplazamiento” (es decir, el conteo comienza en cero) de cada fila que genera la operación UNNEST. Esta columna tiene un alias opcional. El alias predeterminado es el desplazamiento.

Ejemplo:

SELECT * FROM UNNEST ( ) WITH OFFSET AS num;

Consulta Arrays topic para conocer más formas de usar UNNEST, incluida la construcción, la compactación y el filtrado.

with_query_name

Los nombres de consulta en una cláusula WITH (consulta la Cláusula WITH) actúan como nombres de tablas temporales a las que puedes hacer referencia en cualquier parte de la cláusula FROM. En el siguiente ejemplo, subQ1 y subQ2 son with_query_names.

Ejemplo:

WITH
  subQ1 AS (SELECT * FROM Roster WHERE SchoolID = 52),
  subQ2 AS (SELECT SchoolID FROM subQ1)
SELECT DISTINCT * FROM subQ2;

La cláusula WITH oculta las tablas permanentes que compartan el mismo nombre mientras dure la consulta, a menos que califiques el nombre de la tabla; p. ej., db.Roster.

Subconsultas

Una subconsulta es una consulta que aparece dentro de otra declaración y se escribe entre paréntesis. También se las conoce como “sub-SELECT” o “SELECT anidadas”. La sintaxis completa de SELECT es válida en las subconsultas.

Existen dos tipos de subconsultas:

  • Subconsultas de expresión, que puedes usar en una consulta en la que las expresiones sean válidas. Las subconsultas de expresión muestran un solo valor.
  • Subconsultas de tabla, que solo puedes usar en una cláusula FROM. La consulta externa trata el resultado de la subconsulta como una tabla.

Ten en cuenta que debe haber paréntesis en ambos tipos de subconsultas.

Ejemplo:

SELECT AVG ( PointsScored )
FROM
( SELECT PointsScored
  FROM Stats
  WHERE SchoolID = 77 )

De manera opcional, una subconsulta de tabla puede tener un alias.

Ejemplo:

SELECT r.LastName
FROM
( SELECT * FROM Roster) AS r;

Notas sobre las subconsultas

Cuando uses subconsultas, ten en cuenta lo siguiente:

  • Si una subconsulta de expresión muestra más de un valor, los resultados de esa subconsulta deben mostrarse en un arreglo mediante la palabra clave ARRAY. Si ARRAY no está presente, la sintaxis de la subconsulta es legal, pero cuando se ejecuta la consulta, no se permite que esa subconsulta muestre más de un valor cada vez que se invoca. Si muestra más de un valor, la consulta fallará durante la ejecución.
  • Las subconsultas de expresión que seleccionan más de una columna deben mostrar los valores de columna en un struct mediante AS STRUCT.

A continuación, se muestra un ejemplo de una consulta de este tipo:

SELECT r.LastName, r.SchoolId,
       ARRAY(SELECT AS STRUCT p.OpponentID, p.PointsScored
             FROM PlayerStats AS p
             WHERE p.LastName = r.LastName) AS PlayerStats
FROM Roster AS r;

Usar una selección secundaria para recuperar filas de una tabla intercalada es un patrón común cuando se leen datos de bases de datos de Cloud Spanner. Es importante tener en cuenta que la relación de intercalación no forma parte del modelo de datos de SQL, y que la subselección debe unirse a las filas relacionadas en este caso.

Este es un ejemplo de una subconsulta que selecciona filas relacionadas de una tabla intercalada y, también, incluye una condición de unión explícita:

SELECT ...
  ARRAY(
      SELECT AS STRUCT ...
      FROM ChildTable ct
      WHERE ct.parent_key = pt.parent_key
            -- The second part of the condition applies when the key is nullable
            OR (ct.parent_key IS NULL AND pt.parent_key IS NULL)) as child_rows
FROM ParentTable pt
WHERE ...;

Consulta también las notas sobre el uso de STRUCT en las listas SELECT.

Operador TABLESAMPLE

Puedes usar el operador TABLESAMPLE para seleccionar una muestra aleatoria de un conjunto de datos. Este operador es útil cuando se trabaja con tablas que tienen grandes cantidades de datos y no se requieren respuestas precisas.

Sintaxis:

tablesample_type:
    TABLESAMPLE sample_method (sample_size percent_or_rows)

sample_method:
    { BERNOULLI | RESERVOIR }

sample_size:
    numeric_value_expression

percent_or_rows:
    { PERCENT | ROWS }

Cuando uses el operador TABLESAMPLE, debes especificar el algoritmo de muestreo que usarás:

  • BERNOULLI: Cada fila se selecciona de forma independiente con la probabilidad determinada en la cláusula percent. Como resultado, obtienes una cantidad aproximada de N * percent/100 de filas.

  • RESERVOIR: Toma como parámetro un valor K de tamaño de muestra real (expresado como un número de filas). Si la entrada es menor que K, se muestra toda la relación de entrada. Si la entrada es mayor que K, el muestreo de reservoir exhibe una muestra de tamaño igual a K, en la que cualquier muestra de tamaño K es igual de probable.

El operador TABLESAMPLE requiere que selecciones ROWS o PERCENT. Si seleccionas PERCENT, el valor debe ser entre 0 y 100. Si seleccionas ROWS, el valor debe ser mayor o igual que 0.

En los siguientes ejemplos, se ilustra el uso del operador TABLESAMPLE.

Selecciona de una tabla mediante el método de muestreo RESERVOIR:

SELECT MessageId
FROM Messages TABLESAMPLE RESERVOIR (100 ROWS);

Selecciona de una tabla mediante el método de muestreo BERNOULLI:

SELECT MessageId
FROM Messages TABLESAMPLE BERNOULLI (0.1 PERCENT);

Usa TABLESAMPLE con una subconsulta:

SELECT Subject FROM
(SELECT MessageId, Subject FROM Messages WHERE ServerId="test")
TABLESAMPLE BERNOULLI(50 PERCENT)
WHERE MessageId > 3;

Usa una operación de TABLESAMPLE con una unión para otra tabla.

SELECT S.Subject
FROM
(SELECT MessageId, ThreadId FROM Messages WHERE ServerId="test") AS R
TABLESAMPLE RESERVOIR(5 ROWS),
Threads AS S
WHERE S.ServerId="test" AND R.ThreadId = S.ThreadId;

Alias

Consulta Alias para obtener información sobre la sintaxis y la visibilidad de los alias de la cláusula FROM.

Tipos de JOIN

Sintaxis

join:
    from_item [ join_type ] [ join_method ] JOIN  [ join_hint_expr ] from_item
    [ ON bool_expression | USING ( join_column [, ...] ) ]

join_type:
    { INNER | CROSS | FULL [OUTER] | LEFT [OUTER] | RIGHT [OUTER] }

join_method:
{ HASH }
join_hint_expr: '@{' join_hint_key = join_hint_value [, ...] '}' join_hint_key: { FORCE_JOIN_ORDER | JOIN_METHOD }

La cláusula JOIN combina dos from_item para que la cláusula SELECT pueda consultarlos como una sola fuente. La cláusula join_type y ON o USING (una “condición JOIN”) especifica cómo combinar y descartar las filas de los dos from_item para formar una sola fuente.

Todas las cláusulas JOIN requieren un join_type.

Una cláusula JOIN requiere una condición de unión, a menos que se cumpla una de las siguientes condiciones:

  • join_type es CROSS.
  • Uno de los from_item no es una tabla (o ninguno de ellos), p. ej., un array_path o un field_path.

Sugerencias de uniones

Las siguientes sugerencias son compatibles con JOIN:

Sugerencia de clave Valores posibles Descripción
FORCE_JOIN_ORDER TRUE
FALSE (valor predeterminado)
Si se configura como verdadero, usa el orden de uniones que se especifica en la consulta.
JOIN_METHOD HASH_JOIN
APPLY_JOIN
Cuando implementes una unión lógica, elige una alternativa específica para usar en el método de unión subyacente. Obtén más información en Métodos de unión.
Para usar una unión HASH, usa HASH JOIN o JOIN@{JOIN_METHOD=HASH_JOIN}, pero no ambos.

Métodos de unión

Los métodos de unión son implementaciones específicas de los distintos tipos de unión lógica. Algunos métodos de unión están disponibles solo para ciertos tipos de unión. La elección del método de unión que se usará depende de los detalles de tu consulta y de los datos que se consulten. La mejor manera de saber si un método de unión en particular contribuye al rendimiento de tu consulta es probar el método y ver el plan de ejecución de consultas resultante. Para obtener más detalles, consulta la página sobre operadores de ejecución de consultas, en especial, las secciones sobre los operadores de unión apply y hash.

Método de unión Descripción Operandos
HASH_JOIN El operador de unión hash compila una tabla de hash de un lado (el lado de la compilación) y sondea la tabla de hash para todos los elementos del otro lado (el lado del sondeo). Para diferentes tipos de unión, se usan distintos tipos de variantes. Consulta el plan de ejecución de consultas para tu consulta a fin de ver qué variante se usa. Obtén más información sobre el operador de unión hash.
APPLY_JOIN El operador de unión apply obtiene cada elemento de un lado (el lado de entrada) y evalúa la subconsulta en el otro lado (el lado de la asignación) mediante los valores del elemento del lado de entrada. Para diferentes tipos de unión, se usan distintos tipos de variantes. El operador de aplicación cruzada (cross apply) se usa para la unión interna, y el operador de aplicación externa (outer apply) se usa para las uniones izquierdas. Obtén más información sobre los operadores de aplicación cruzada y aplicación externa.

[INNER] JOIN

Una INNER JOIN, o tan solo JOIN, calcula de manera efectiva el producto cartesiano de los dos from_item y descarta todas las filas que no cumplen con la condición JOIN. “De manera efectiva” significa que es posible implementar una INNER JOIN sin calcular el producto cartesiano.

CROSS JOIN

CROSS JOIN muestra el producto cartesiano de los dos from_item. En otras palabras, combina cada fila del primer from_item con cada fila del segundo from_item. Si hay M filas del primero y N filas del segundo, el resultado es M * N filas. Ten en cuenta que si cualquiera de los from_item tiene cero filas, el resultado es cero filas.

CROSS JOIN con coma

CROSS JOIN se puede escribir de forma explícita (consulta la sección anterior) o de forma implícita con una coma que separe los from_item.

Ejemplo de una “CROSS JOIN con coma” implícita:

SELECT * FROM Roster, TeamMascot;

Este es el equivalente explícito de la CROSS JOIN:

SELECT * FROM Roster CROSS JOIN TeamMascot;

No puedes escribir CROSS JOIN con comas entre paréntesis.

No válido: CROSS JOIN con coma entre paréntesis:

SELECT * FROM t CROSS JOIN (Roster, TeamMascot);  // INVALID.

Consulta Secuencias de JOIN para obtener detalles sobre cómo se comporta una CROSS JOIN con coma en una secuencia de JOIN.

FULL [OUTER] JOIN

Una FULL OUTER JOIN (o simplemente FULL JOIN) muestra todos los campos de todas las filas de ambos from_item que cumplen con la condición JOIN.

FULL indica que todas las filas de ambos from_item se muestran, incluso si no cumplen con la condición JOIN.

OUTER indica que si una fila determinada de un from_item no se une a ninguna fila del otro from_item, la fila mostrará NULL para todas las columnas del otro from_item.

LEFT [OUTER] JOIN

El resultado de una LEFT OUTER JOIN (o tan solo LEFT JOIN) para dos from_item siempre conserva todas las filas del from_item de la izquierda en la cláusula JOIN, incluso si ninguna fila en el from_item de la derecha satisface el predicado de JOIN.

LEFT indica que se muestran todas las filas from_item de la izquierda. Si una fila determinada del from_item de la izquierda no se une a ninguna fila del from_item de la derecha, se mostrarán en la fila todas las columnas del from_item de la derecha como NULL. Las filas del from_item de la derecha que no se unen a ninguna fila del from_item de la izquierda se descartan.

RIGHT [OUTER] JOIN

El resultado de una RIGHT OUTER JOIN (o tan solo RIGHT JOIN) es similar y simétrico al de una LEFT OUTER JOIN.

Cláusula ON

La cláusula ON contiene una bool_expression. Una fila combinada (el resultado de la unión de dos filas) cumple con la condición JOIN si la bool_expression muestra TRUE.

Ejemplo:

SELECT * FROM Roster INNER JOIN PlayerStats
ON Roster.LastName = PlayerStats.LastName;

Cláusula USING

La cláusula USING requiere una column_list de una o más columnas que aparecen en ambas tablas de entrada. Realiza una comparación de igualdad en esa columna y las filas cumplen la condición JOIN si la comparación de igualdad muestra TRUE.

En la mayoría de los casos, una declaración con la palabra clave USING es equivalente a usar la palabra clave ON. Por ejemplo, la declaración:

SELECT FirstName
FROM Roster INNER JOIN PlayerStats
USING (LastName);

es equivalente a lo siguiente:

SELECT FirstName
FROM Roster INNER JOIN PlayerStats
ON Roster.LastName = PlayerStats.LastName;

Los resultados de las consultas con una USING difieren de las consultas que usan ON cuando usas SELECT *. A modo de ejemplo, considera la siguiente consulta:

SELECT * FROM Roster INNER JOIN PlayerStats
USING (LastName);

En esta declaración, se muestran las filas de Roster y PlayerStats en las que Roster.LastName es lo mismo que PlayerStats.LastName. En los resultados, se incluye una sola columna LastName.

Por otro lado, considera la consulta siguiente:

SELECT * FROM Roster INNER JOIN PlayerStats
ON Roster.LastName = PlayerStats.LastName;

En esta declaración, se muestran las filas de Roster y PlayerStats en las que Roster.LastName es lo mismo que PlayerStats.LastName. En los resultados, se incluyen dos columnas LastName: una de Roster y una de PlayerStats.

Secuencias de JOIN

La cláusula FROM puede contener varias cláusulas JOIN en una secuencia.

Ejemplo:

SELECT * FROM a LEFT JOIN b ON TRUE LEFT JOIN c ON TRUE;

en la que a, b y c son cualquier from_item. Las JOIN están vinculadas de izquierda a derecha, pero puedes insertar paréntesis para agruparlas en un orden diferente.

Considera las siguientes consultas: A (sin paréntesis) y B (con paréntesis) son equivalentes entre sí, pero no con C. La FULL JOIN en negrita se vincula primero.

A.

SELECT * FROM Roster FULL JOIN TeamMascot USING (SchoolID)
FULL JOIN PlayerStats USING (LastName);

B.

SELECT * FROM ( (Roster FULL JOIN TeamMascot USING (SchoolID))
FULL JOIN PlayerStats USING (LastName));

C.

SELECT * FROM (Roster FULL JOIN (TeamMascot FULL JOIN PlayerStats USING
(LastName)) USING (SchoolID)) ;

Cuando las CROSS JOIN con coma están presentes en una consulta con una secuencia de JOIN, se agrupan de izquierda a derecha como otros tipos de JOIN.

Ejemplo:

SELECT * FROM a JOIN b ON TRUE, b JOIN c ON TRUE;

La consulta anterior es equivalente a lo siguiente:

SELECT * FROM ((a JOIN b ON TRUE) CROSS JOIN b) JOIN c ON TRUE);

No puede haber una RIGHT JOIN o una FULL JOIN después de una unión de comas.

No válido: RIGHT JOIN después de una unión cruzada con comas:

SELECT * FROM Roster, TeamMascot RIGHT JOIN PlayerStats ON TRUE;  // INVALID.

Cláusula WHERE

Sintaxis

WHERE bool_expression

La cláusula WHERE filtra las filas mediante la evaluación de cada fila con la bool_expression y descarta todas las filas que no muestren TRUE (es decir, las filas que muestren FALSE o NULL).

Ejemplo:

SELECT * FROM Roster
WHERE SchoolID = 52;

La bool_expression puede contener varias subcondiciones.

Ejemplo:

SELECT * FROM Roster
WHERE STARTS_WITH(LastName, "Mc") OR STARTS_WITH(LastName, "Mac");

No puedes hacer referencia a los alias de columna de la lista SELECT en la cláusula WHERE.

Las expresiones en una INNER JOIN tienen una expresión equivalente en la cláusula WHERE. Por ejemplo, una consulta que usa INNER JOIN y ON tiene una expresión equivalente mediante CROSS JOIN y WHERE.

Por ejemplo, esta consulta:

SELECT * FROM Roster INNER JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;

es equivalente a lo siguiente:

SELECT * FROM Roster CROSS JOIN TeamMascot
WHERE Roster.SchoolID = TeamMascot.SchoolID;

Cláusula GROUP BY

Sintaxis

GROUP BY expression [, ...]

La cláusula GROUP BY agrupa las filas en una tabla con valores no distintos para la expression en la cláusula . Para varias filas en la tabla de origen con valores no distintos de la expression, la cláusula GROUP BY produce una única fila combinada. Por lo general, GROUP BY se usa cuando las funciones de agregación están presentes en la lista SELECT o para eliminar la redundancia en la salida. El tipo de datos de expression debe ser agrupable.

Ejemplo:

SELECT SUM(PointsScored), LastName
FROM PlayerStats
GROUP BY LastName;

La cláusula GROUP BY puede hacer referencia a nombres de expresiones en la lista SELECT. La cláusula GROUP BY también permite referencias ordinales a expresiones en la lista SELECT mediante valores de números enteros. 1 se refiere a la primera expresión en la lista SELECT, 2 a la segunda, y así sucesivamente. La lista de expresiones puede combinar ordinales y nombres de expresiones.

Ejemplo:

SELECT SUM(PointsScored), LastName, FirstName
FROM PlayerStats
GROUP BY LastName, FirstName;

La consulta anterior es equivalente a lo siguiente:

SELECT SUM(PointsScored), LastName, FirstName
FROM PlayerStats
GROUP BY 2, FirstName;

Las cláusulas GROUP BY pueden referirse también a los alias. Si una consulta contiene alias en la cláusula SELECT, esos alias anulan los nombres en la cláusula FROM correspondiente.

Ejemplo:

SELECT SUM(PointsScored), LastName as last_name
FROM PlayerStats
GROUP BY last_name;

Cláusula HAVING

Sintaxis

HAVING bool_expression

La cláusula HAVING es similar a la cláusula WHERE: filtra las filas que no muestran TRUE cuando se evalúan con la bool_expression.

Al igual que con la cláusula WHERE, bool_expression puede ser cualquier expresión que muestre un valor booleano y puede contener varias subcondiciones.

La cláusula HAVING se diferencia de la cláusula WHERE en cuanto a los siguientes factores:

  • La cláusula HAVING requiere una GROUP BY o agregación para formar parte de la consulta.
  • La cláusula HAVING se produce después de GROUP BY y de la agregación, y antes de ORDER BY. Esto significa que la cláusula HAVING se evalúa una vez en cada fila agregada en el conjunto de resultados. Esto difiere de la cláusula WHERE, que se evalúa antes de GROUP BY y de la agregación.

La cláusula HAVING puede hacer referencia a columnas disponibles a través de la cláusula FROM, así como los alias de la lista SELECT. Las expresiones a las que se hace referencia en la cláusula HAVING deben aparecer en la cláusula GROUP BY o deben ser el resultado de una función de agregación:

SELECT LastName
FROM Roster
GROUP BY LastName
HAVING SUM(PointsScored) > 15;

Si una consulta contiene alias en la cláusula SELECT, esos alias anulan los nombres en una cláusula FROM.

SELECT LastName, SUM(PointsScored) AS ps
FROM Roster
GROUP BY LastName
HAVING ps > 0;

Agregación obligatoria

La agregación no tiene que estar presente en la cláusula HAVING, pero debe estar en al menos una de las siguientes formas:

Función de agregación en la lista SELECT.

SELECT LastName, SUM(PointsScored) AS total
FROM PlayerStats
GROUP BY LastName
HAVING total > 15;

Función de agregación en la cláusula “HAVING”.

SELECT LastName
FROM PlayerStats
GROUP BY LastName
HAVING SUM(PointsScored) > 15;

Agregación en la lista SELECT y en la cláusula HAVING.

Cuando las funciones de agregación están presentes en la lista SELECT y en la cláusula HAVING, no es necesario que estas funciones y las columnas a las que hacen referencia sean las mismas. En el siguiente ejemplo, las dos funciones de agregación, COUNT() y SUM(), son diferentes y también usan columnas diferentes.

SELECT LastName, COUNT(*)
FROM PlayerStats
GROUP BY LastName
HAVING SUM(PointsScored) > 15;

Cláusula ORDER BY

Sintaxis

ORDER BY expression
  [{ ASC | DESC }]
  [, ...]

La cláusula ORDER BY especifica una columna o expresión como criterio de clasificación para el conjunto de resultados. Si una cláusula ORDER BY no está presente, el orden de los resultados de una consulta no se define. Se permiten los alias de columna de una cláusula FROM o una lista SELECT. Si una consulta contiene alias en la cláusula SELECT, esos alias anulan los nombres en la cláusula FROM correspondiente.

Cláusulas opcionales

  • ASC | DESC: Ordenan los resultados de los valores de expression en orden ascendente o descendente. ASC es el valor predeterminado.

Ejemplos

Para usar el orden de clasificación predeterminado (ascendente), haz lo siguiente:

SELECT x, y
FROM (SELECT 1 AS x, true AS y UNION ALL
      SELECT 9, true)
ORDER BY x;
+------+-------+
| x    | y     |
+------+-------+
| 1    | true  |
| 9    | true  |
+------+-------+

Para usar el orden de clasificación descendente, haz lo siguiente:

SELECT x, y
FROM (SELECT 1 AS x, true AS y UNION ALL
      SELECT 9, true)
ORDER BY x DESC;
+------+-------+
| x    | y     |
+------+-------+
| 9    | true  |
| 1    | true  |
+------+-------+

Es posible ordenar por varias columnas. En el siguiente ejemplo, el conjunto de resultados se ordena primero por SchoolID y, luego, por LastName:

SELECT LastName, PointsScored, OpponentID
FROM PlayerStats
ORDER BY SchoolID, LastName;

Las siguientes reglas se aplican cuando se ordenan los valores:

  • NULL: en el contexto de la cláusula ORDER BY, los NULL son el valor mínimo posible, es decir, los valores NULL aparecen primeros en los órdenes ASC y últimos en los órdenes DESC.
  • Tipos de datos de punto flotante: consulta la página sobre semántica de punto flotante en la que se explica cómo ordenar y agrupar.

Cuando se usa junto con los operadores de conjuntos, la cláusula ORDER BY se aplica al conjunto de resultados de toda la consulta, no solo a la declaración SELECT más cercana. Por esta razón, puede ser útil (aunque no es obligatorio) usar paréntesis para mostrar el alcance de ORDER BY.

Esta consulta sin paréntesis:

SELECT * FROM Roster
UNION ALL
SELECT * FROM TeamMascot
ORDER BY SchoolID;

es equivalente a esta consulta con paréntesis:

( SELECT * FROM Roster
  UNION ALL
  SELECT * FROM TeamMascot )
ORDER BY SchoolID;

pero no a esta consulta, en la que la cláusula ORDER BY se aplica solo a la segunda declaración SELECT:

SELECT * FROM Roster
UNION ALL
( SELECT * FROM TeamMascot
  ORDER BY SchoolID );

También puedes usar literales de números enteros como referencias de columna en las cláusulas ORDER BY. Un literal de número entero se convierte en un ordinal (por ejemplo, el conteo comienza en 1) en la lista SELECT.

Por ejemplo, las dos consultas siguientes son equivalentes:

SELECT SUM(PointsScored), LastName
FROM PlayerStats
ORDER BY LastName;
SELECT SUM(PointsScored), LastName
FROM PlayerStats
ORDER BY 2;

COLLATE

Puedes usar la cláusula COLLATE para definir mejor cómo se ordenan los datos de una cláusula ORDER BY. El término intercalación hace referencia a un conjunto de reglas que determinan cómo se comparan las STRING según las convenciones y estándares de un lenguaje, una región o un país en particular. Estas reglas pueden definir la secuencia de caracteres correcta y dar opciones para especificar la distinción entre mayúsculas y minúsculas.

Nota: Puedes usar COLLATE solo en las columnas de tipo STRING.

Debes agregar intercalación a tu instrucción de la siguiente manera:

SELECT ...
FROM ...
ORDER BY value COLLATE collation_string

Una collation_string contiene un collation_name y puede tener un collation_attribute opcional como sufijo, separado por dos puntos. La collation_string es un literal o un parámetro. Por lo general, este nombre consta de dos letras que representan el lenguaje seguido de forma opcional por un guion bajo y dos letras que representan la región, por ejemplo, en_US. El repositorio de datos de configuración regional común (CLDR) define estos nombres. Una instrucción también puede tener un collation_name de unicode. Este valor significa que la instrucción debe mostrar datos mediante la intercalación predeterminada de Unicode.

Además del collation_name, una collation_string puede tener un collation_attribute opcional como sufijo, separado por dos puntos. Este atributo especifica si las comparaciones de datos deben distinguir entre mayúsculas y minúsculas. Los valores permitidos son cs cuando se distingue entre mayúsculas y minúsculas y ci cuando no distingue entre mayúsculas y minúsculas. Si no se proporciona un collation_attribute, se usan los valores predeterminados de CLDR.

Ejemplos de COLLATE

Resultados de COLLATE con inglés de Canadá:

SELECT Place
FROM Locations
ORDER BY Place COLLATE "en_CA"

Resultados de COLLATE con un parámetro:

#@collate_param = "arg_EG"
SELECT Place
FROM Locations
ORDER BY Place COLLATE @collate_param

Uso de varias cláusulas COLLATE en una instrucción:

SELECT APlace, BPlace, CPlace
FROM Locations
ORDER BY APlace COLLATE "en_US" ASC,
         BPlace COLLATE "ar_EG" DESC,
         CPlace COLLATE "en" DESC

Intercalación sin distinción entre mayúsculas y minúsculas:

SELECT Place
FROM Locations
ORDER BY Place COLLATE "en_US:ci"

Intercalación predeterminada de Unicode con distinción entre mayúsculas y minúsculas:

SELECT Place
FROM Locations
ORDER BY Place COLLATE "unicode:ci"

Operadores de conjuntos

Sintaxis

UNION { ALL | DISTINCT } | INTERSECT { ALL | DISTINCT } | EXCEPT { ALL | DISTINCT }

Los operadores de conjuntos combinan los resultados de dos o más consultas de entrada en un único conjunto de resultados. Debes especificar ALL o DISTINCT; si especificas ALL, se conservan todas las filas. Si especificas DISTINCT, se descartan las filas duplicadas.

Si una determinada fila R aparece exactamente m veces en la primera consulta de entrada y n veces en la segunda consulta de entrada (m > = 0, n > = 0):

  • En UNION ALL, R aparece exactamente m + n veces en el resultado.
  • En INTERSECT ALL, R aparecerá exactamente “MIN(m, n)” en el resultado.
  • En EXCEPT ALL, R aparece exactamente “MAX(m - n, 0)” en el resultado.
  • En UNION DISTINCT, DISTINCT se calcula después de que se calcula UNION, por lo que R aparece solo una vez.
  • En INTERSECT DISTINCT, DISTINCT se calcula después de que se calcula el resultado anterior.
  • En EXCEPT DISTINCT, la fila R aparece una vez en el resultado si m > 0 y n = 0.
  • Si hay más de dos consultas de entrada, las operaciones anteriores se generalizan y el resultado es el mismo que si las entradas se combinaran de forma incremental de izquierda a derecha.

Se aplican las siguientes reglas:

  • Para las operaciones de conjuntos distintas de UNION ALL, todos los tipos de columna deben admitir la comparación de igualdad.
  • Las consultas de entrada a cada lado del operador deben mostrar la misma cantidad de columnas.
  • Los operadores sincronizan las columnas que se muestran por cada consulta de entrada de acuerdo con las posiciones de las columnas en sus respectivas listas SELECT. Es decir, la primera columna en la primera consulta de entrada se sincroniza con la primera columna en la segunda consulta de entrada.
  • El conjunto de resultados siempre usa los nombres de columna de la primera consulta de entrada.
  • El conjunto de resultados siempre usa los supertipos de tipos de entrada en las columnas correspondientes, por lo que las columnas sincronizadas también deben tener el mismo tipo de datos o un supertipo común.
  • Debes usar paréntesis si deseas separar diferentes operaciones de conjuntos. Para este fin, las operaciones de conjuntos como UNION ALL y UNION DISTINCT son diferentes. Si la declaración solo repite la misma operación de conjunto, no se necesitan los paréntesis.

Ejemplos:

query1 UNION ALL (query2 UNION DISTINCT query3)
query1 UNION ALL query2 UNION ALL query3

No válido:

query1 UNION ALL query2 UNION DISTINCT query3
query1 UNION ALL query2 INTERSECT ALL query3; // INVALID.

UNION

El operador UNION combina los conjuntos de resultados de dos o más consultas de entrada mediante la sincronización de las columnas del conjunto de resultados de cada consulta, concatenándolas de forma vertical.

INTERSECT

El operador INTERSECT muestra las filas que se encuentran en los conjuntos de resultados de las consultas de entrada izquierda y derecha. A diferencia de lo que ocurre con EXCEPT, la posición de las consultas de entrada (a la izquierda o a la derecha del operador INTERSECT) no importa.

EXCEPT

El operador EXCEPT muestra filas de la consulta de entrada izquierda que no están presentes en la consulta de entrada derecha.

Ejemplo:

SELECT * FROM UNNEST(ARRAY<int64>[1, 2, 3]) AS number
EXCEPT DISTINCT SELECT 1;

+--------+
| number |
+--------+
| 2      |
| 3      |
+--------+

Cláusula LIMIT y cláusula OFFSET

Sintaxis

LIMIT count [ OFFSET skip_rows ]

LIMIT especifica un count no negativo de tipo INT64 y no se mostrarán más que las filas count. LIMIT 0 muestra 0 filas. Si hay una operación de configuración, se aplica LIMIT después de que se evalúa esa operación.

OFFSET especifica un skip_rows no negativo de tipo INT64 y solo se considerarán las filas de ese desplazamiento en la tabla.

Estas cláusulas aceptan solo valores literales o de parámetros.

Las filas que muestran LIMIT y OFFSET no se especifican, a menos que estos operadores se usen después de ORDER BY.

Cláusula WITH

La cláusula WITH vincula los resultados de una o más subconsultas con nombre a nombres de tablas temporales. Cada nombre de tabla ingresado es visible en expresiones SELECT posteriores dentro de la misma expresión de consulta. Esto incluye los siguientes tipos de expresiones SELECT:

  • Cualquier expresión SELECT en las vinculaciones WITH posteriores
  • Expresiones SELECT de nivel superior en la expresión de consulta a ambos lados de un operador de conjunto, como UNION
  • Expresiones SELECT dentro de subconsultas en la misma expresión de consulta

Ejemplo:

WITH subQ1 AS (SELECT SchoolID FROM Roster),
     subQ2 AS (SELECT OpponentID FROM PlayerStats)
SELECT * FROM subQ1
UNION ALL
SELECT * FROM subQ2;

Si una cláusula WITH contiene varias subconsultas, los nombres de las subconsultas no pueden repetirse.

NOTA: SQL de Cloud Spanner no es compatible con WITH RECURSIVE.

NOTA: Spanner almacena las tablas temporales definidas por la cláusula WITH en la memoria. Debes lograr que el tamaño de todas las tablas temporales creadas por una consulta se ajuste al límite de memoria de consultas; de lo contrario, la consulta fallará.

NOTA: Spanner no admite la cláusula WITH en declaraciones DML.

Alias

Un alias es un nombre temporal que se le otorga a una tabla, columna o expresión presentes en una consulta. Puedes ingresar alias explícitos en la lista SELECT o en la cláusula FROM, o SQL de Cloud Spanner inferirá un alias implícito para algunas expresiones. Las expresiones sin alias explícito ni implícito son anónimas y la consulta no puede hacer referencia a ellas por nombre.

Sintaxis del alias explícito

Puedes ingresar alias explícitos en la cláusula FROM o en la lista SELECT.

En una cláusula FROM, puedes ingresar los alias explícitos para cualquier elemento, incluidas tablas, arreglos, subconsultas y cláusulas UNNEST, mediante el [AS] alias. La palabra clave AS es opcional.

Ejemplo:

SELECT s.FirstName, s2.SongName
FROM Singers AS s, (SELECT * FROM Songs) AS s2;

Puedes ingresar los alias explícitos para cualquier expresión en la lista SELECT mediante el [AS] alias. La palabra clave AS es opcional.

Ejemplo:

SELECT s.FirstName AS name, LOWER(s.FirstName) AS lname
FROM Singers s;

Visibilidad del alias explícito

Después de ingresar un alias explícito en una consulta, existen restricciones sobre en qué otra parte de la consulta puedes hacer referencia a ese alias. Estas restricciones de visibilidad de alias son el resultado de las reglas de alcance de nombres de SQL de Cloud Spanner.

Alias de cláusula FROM

SQL de Cloud Spanner procesa alias en una cláusula FROM de izquierda a derecha, y los alias solo son visibles para las expresiones de ruta de acceso posteriores en una cláusula .

Ejemplo:

Supongamos que la tabla Singers tenía una columna Concerts de tipo ARRAY.

SELECT FirstName
FROM Singers AS s, s.Concerts;

No válido:

SELECT FirstName
FROM s.Concerts, Singers AS s;  // INVALID.

Los alias de la cláusula FROM no son visibles para las subconsultas en la misma cláusula . Las subconsultas en una cláusula FROM no pueden contener referencias correlacionadas con otras tablas en la misma cláusula FROM.

No válido:

SELECT FirstName
FROM Singers AS s, (SELECT (2020 - ReleaseDate) FROM s)  // INVALID.

Puedes usar cualquier nombre de columna de una tabla en FROM como un alias en cualquier parte de la consulta, con o sin calificación con el nombre de la tabla.

Ejemplo:

SELECT FirstName, s.ReleaseDate
FROM Singers s WHERE ReleaseDate = 1975;

Si la cláusula FROM contiene un alias explícito, debes usarlo en lugar del alias implícito para el resto de la consulta (consulta Alias implícitos). Un alias de tabla es útil por cuestiones de brevedad o para eliminar la ambigüedad en casos como autocombinaciones, en que la misma tabla se analiza varias veces durante el procesamiento de consulta.

Ejemplo:

SELECT * FROM Singers as s, Songs as s2
ORDER BY s.LastName

No válido: ORDER BY no usa el alias de la tabla:

SELECT * FROM Singers as s, Songs as s2
ORDER BY Singers.LastName;  // INVALID.

Alias de la lista SELECT

Los alias en la lista SELECT son visibles solo para las siguientes cláusulas:

  • Cláusula GROUP BY
  • Cláusula ORDER BY
  • Cláusula HAVING

Ejemplo:

SELECT LastName AS last, SingerID
FROM Singers
ORDER BY last;

Alias explícitos en las cláusulas GROUP BY, ORDER BY y HAVING

Las tres cláusulas, GROUP BY, ORDER BY y HAVING, solo pueden hacer referencia a los siguientes valores:

  • Tablas en la cláusula FROM y cualquiera de sus columnas
  • Alias de la lista SELECT

GROUP BY y ORDER BY también pueden hacer referencia a un tercer grupo:

  • Literales de número entero, que se refieren a elementos de la lista SELECT El número entero 1 se refiere al primer elemento de la lista SELECT, 2 se refiere al segundo elemento, y así sucesivamente.

Ejemplo:

SELECT SingerID AS sid, COUNT(Songid) AS s2id
FROM Songs
GROUP BY 1
ORDER BY 2 DESC;

La consulta anterior es equivalente a lo siguiente:

SELECT SingerID AS sid, COUNT(Songid) AS s2id
FROM Songs
GROUP BY sid
ORDER BY s2id DESC;

Alias ambiguos

SQL de Cloud Spanner genera un error si un nombre es ambiguo, lo que significa que puede determinarse en más de un objeto único.

Ejemplos:

Esta consulta contiene nombres de columnas que entran en conflicto entre las tablas, ya que Singers y Songs tienen una columna llamada SingerID:

SELECT SingerID
FROM Singers, Songs;

Esta consulta contiene alias que son ambiguos en la cláusula GROUP BY debido a que están duplicados en la lista SELECT:

SELECT FirstName AS name, LastName AS name,
FROM Singers
GROUP BY name;

A continuación, se muestra una ambigüedad entre un nombre de columna de la cláusula FROM y un alias de la lista SELECT en GROUP BY:

SELECT UPPER(LastName) AS LastName
FROM Singers
GROUP BY LastName;

La consulta anterior es ambigua y generará un error porque LastName en la cláusula GROUP BY podría referirse a la columna original en Singers o al alias AS LastName, cuyo valor es UPPER(LastName).

Las mismas reglas de ambigüedad se aplican en las expresiones de la ruta de acceso. Considera la siguiente consulta, en la que la table tiene columnas x y y, y la columna z es de tipo STRUCT y tiene campos v, w y x.

Ejemplo:

SELECT x, z AS T
FROM table T
GROUP BY T.x;

El alias T es ambiguo y producirá un error debido a que T.x en la cláusula GROUP BY podría referirse a table.x o table.z.x.

Un nombre no es ambiguo en GROUP BY, ORDER BY o HAVING si este es un nombre de columna y un alias de la lista SELECT, siempre que el nombre se resuelva en el mismo objeto subyacente.

Ejemplo:

SELECT LastName, BirthYear AS BirthYear
FROM Singers
GROUP BY BirthYear;

El alias BirthYear no es ambiguo porque se resuelve en la misma columna subyacente, Singers.BirthYear.

Alias implícitos

En la lista SELECT, si hay una expresión que no tiene un alias explícito, SQL de Cloud Spanner asigna un alias implícito según las siguientes reglas. Puede haber varias columnas con el mismo alias en la lista SELECT.

  • Para los identificadores, el alias es el identificador. Por ejemplo, SELECT abc implica AS abc.
  • Para las expresiones de la ruta de acceso, el alias es el último identificador en la ruta de acceso. Por ejemplo, SELECT abc.def.ghi implica AS ghi.
  • Para el acceso de campo que usa el operador de acceso de campo del miembro “punto”, el alias es el nombre del campo. Por ejemplo, SELECT (struct_function()).fname implica AS fname.

En los demás casos, no hay un alias implícito, por lo que la columna es anónima y no se puede hacer referencia a ella por nombre. Los datos de esa columna aún se mostrarán y los resultados de la consulta que se muestran pueden tener una etiqueta generada para esa columna, pero la etiqueta no se puede usar como un alias.

En una cláusula FROM, los from_item no necesitan tener un alias. Se aplican las siguientes reglas:

  • Si hay una expresión que no tiene un alias explícito, SQL de Cloud Spanner asigna un alias implícito en estos casos:
    • Para los identificadores, el alias es el identificador. Por ejemplo, FROM abc implica AS abc.
    • Para las expresiones de la ruta de acceso, el alias es el último identificador en la ruta de acceso. Por ejemplo, FROM abc.def.ghi implica AS ghi
    • La columna generada con WITH OFFSET tiene el alias implícito offset.

  • Las subconsultas de tabla no tienen alias implícitos.
  • FROM UNNEST(x) no tiene un alias implícito.

Apéndice A: ejemplos con datos de muestra

Tablas de muestra

Las siguientes tres tablas contienen datos de muestra sobre atletas, sus escuelas y los puntos que obtienen durante la temporada. Estas tablas se usarán para ilustrar el comportamiento de diferentes cláusulas de consulta.

Tabla Roster:

LastName SchoolID
Adams 50
Buchanan 52
Coolidge 52
Davis 51
Eisenhower 77

En la tabla Roster, se incluye una lista de nombres de los jugadores (LastName) y el ID único asignado a su escuela (SchoolID).

Tabla PlayerStats:

LastName OpponentID PointsScored
Adams 51 3
Buchanan 77 0
Coolidge 77 1
Adams 52 4
Buchanan 50 13

En la tabla PlayerStats, se incluye una lista de nombres de jugadores (LastName) y el ID único asignado al oponente contra el que jugaron en un partido determinado (OpponentID) y la cantidad de puntos que el atleta obtuvo en ese juego (PointsScored).

Tabla TeamMascot:

SchoolId Mascot
50 Jaguars
51 Knights
52 Lakers
53 Mustangs

En la tabla TeamMascot, se incluye una lista de ID escolares únicos (SchoolID) y la mascota de esa escuela (Mascot).

Tipos de JOIN

1) [INNER] JOIN

Ejemplo:

SELECT * FROM Roster JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;

Resultados:

LastName Roster.SchoolId TeamMascot.SchoolId Mascot
Adams 50 50 Jaguars
Buchanan 52 52 Lakers
Coolidge 52 52 Lakers
Davis 51 51 Knights

2) CROSS JOIN

Ejemplo:

SELECT * FROM Roster CROSS JOIN TeamMascot;

Resultados:

LastName Roster.SchoolId TeamMascot.SchoolId Mascot
Adams 50 50 Jaguars
Adams 50 51 Knights
Adams 50 52 Lakers
Adams 50 53 Mustangs
Buchanan 52 50 Jaguars
Buchanan 52 51 Knights
Buchanan 52 52 Lakers
Buchanan 52 53 Mustangs
Coolidge 52 50 Jaguars
Coolidge 52 51 Knights
Coolidge 52 52 Lakers
Coolidge 52 53 Mustangs
Davis 51 50 Jaguars
Davis 51 51 Knights
Davis 51 52 Lakers
Davis 51 53 Mustangs
Eisenhower 77 50 Jaguars
Eisenhower 77 51 Knights
Eisenhower 77 52 Lakers
Eisenhower 77 53 Mustangs

3) FULL [OUTER] JOIN

Ejemplo:

SELECT * FROM Roster FULL JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;
LastName Roster.SchoolId TeamMascot.SchoolId Mascot
Adams 50 50 Jaguars
Buchanan 52 52 Lakers
Coolidge 52 52 Lakers
Davis 51 51 Knights
Eisenhower 77 NULL NULL
NULL NULL 53 Mustangs

4) LEFT [OUTER] JOIN

Ejemplo:

SELECT * FROM Roster LEFT JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;

Resultados:

LastName Roster.SchoolId TeamMascot.SchoolId Mascot
Adams 50 50 Jaguars
Buchanan 52 52 Lakers
Coolidge 52 52 Lakers
Davis 51 51 Knights
Eisenhower 77 NULL NULL

5) RIGHT [OUTER] JOIN

Ejemplo:

SELECT * FROM Roster RIGHT JOIN TeamMascot
ON Roster.SchoolID = TeamMascot.SchoolID;

Resultados:

LastName Roster.SchoolId TeamMascot.SchoolId Mascot
Adams 50 50 Jaguars
Davis 51 51 Knights
Coolidge 52 52 Lakers
Buchanan 52 52 Lakers
NULL NULL 53 Mustangs

Cláusula GROUP BY

Ejemplo:

SELECT LastName, SUM(PointsScored)
FROM PlayerStats
GROUP BY LastName;
LastName SUM
Adams 7
Buchanan 13
Coolidge 1

Operadores de conjuntos

UNION

El operador UNION combina los conjuntos de resultados de dos o más declaraciones SELECT mediante la sincronización de las columnas del conjunto de resultados de cada declaración SELECT y su concatenación de forma vertical.

Ejemplo:

SELECT Mascot AS X, SchoolID AS Y
FROM TeamMascot
UNION ALL
SELECT LastName, PointsScored
FROM PlayerStats;

Resultados:

X S
Jaguars 50
Knights 51
Lakers 52
Mustangs 53
Adams 3
Buchanan 0
Coolidge 1
Adams 4
Buchanan 13

INTERSECT

Esta consulta muestra los apellidos que están presentes en Roster y en PlayerStats.

SELECT LastName
FROM Roster
INTERSECT ALL
SELECT LastName
FROM PlayerStats;

Resultados:

LastName
Adams
Coolidge
Buchanan

EXCEPT

La consulta que aparece a continuación muestra los apellidos de Roster que no están presentes en PlayerStats.

SELECT LastName
FROM Roster
EXCEPT DISTINCT
SELECT LastName
FROM PlayerStats;

Resultados:

LastName
Eisenhower
Davis

Si se invierte el orden de las instrucciones SELECT, se mostrarán los apellidos de PlayerStats que no están presentes en Roster:

SELECT LastName
FROM PlayerStats
EXCEPT DISTINCT
SELECT LastName
FROM Roster;

Resultados:

(empty)