Estrutura e sintaxe lexicais

Uma declaração SQL do Cloud Spanner compreende uma série de tokens. Eles incluem identificadores, identificadores entre aspas, literais, palavras-chave, operadores e caracteres especiais. É possível separar tokens com comentários ou um espaço em branco, por exemplo, espaço, backspace, tabulação ou nova linha.

Identificadores

São nomes associados a colunas, tabelas e outros objetos do banco de dados. Eles podem estar entre aspas ou não.

  • Os identificadores podem ser usados em expressões de caminho que retornam um STRUCT.
  • Alguns identificadores diferenciam maiúsculas de minúsculas e outros não. Para detalhes, consulte Diferença entre maiúsculas e minúsculas.
  • Identificadores sem aspas devem começar com uma letra ou um caractere sublinhado. Os caracteres seguintes podem ser letras, números ou sublinhados.
  • Os identificadores entre aspas precisam ser colocados entre caracteres de crase (`).
    • Os identificadores entre aspas podem conter qualquer caractere, como espaços ou símbolos.
    • Os identificadores entre aspas não podem estar vazios.
    • Os identificadores entre aspas têm as mesmas sequências de escape dos literais de strings.
    • Uma palavra-chave reservada precisa ser um identificador entre aspas se for uma palavra-chave independente ou o primeiro componente de uma expressão de caminho. Ela pode estar entre aspas como o segundo ou posterior componente de uma expressão de caminho.

Exemplos

Estes são identificadores válidos:

Customers5
`5Customers`
dataField
_dataField1
ADGROUP
`tableName~`
`GROUP`

Essas expressões de caminho contêm identificadores válidos:

foo.`GROUP`
foo.GROUP
foo().dataField
list[OFFSET(3)].dataField
list[ORDINAL(3)].dataField
@parameter.dataField

Estes são identificadores inválidos:

5Customers
_dataField!
GROUP

5Customers começa com um número, não uma letra ou um sublinhado. _dataField! contém o caractere especial "!" que não é uma letra, um número ou um sublinhado. GROUP é uma palavra-chave reservada e, portanto, não pode ser usada como identificador sem estar entre caracteres de crase.

Literais

Os literais representam um valor constante de um tipo de dados integrado. Alguns tipos de dados podem ser expressos como literais, mas nem todos.

Literais de strings e bytes

Os literais de string e de bytes precisam ficar entre aspas, com aspas simples (') ou duplas (") ou, ainda, aspas triplas com grupos de três aspas simples (''') ou três duplas (""").

Literais entre aspas:

Literal Exemplos Descrição
String entre aspas
  • "abc"
  • "it's"
  • 'it\'s'
  • 'Title: "Boy"'
Strings entre aspas simples (') podem conter aspas duplas sem escape ("), assim como o inverso. As
barras invertidas (\) iniciam as sequências de escape. Veja a tabela "Sequências de escape" abaixo.
As strings entre aspas não podem ter novas linhas, mesmo se precedidas de barra invertida (\).
String entre três aspas
  • """abc"""
  • '''it's'''
  • '''Title:"Boy"'''
  • '''two
    lines'''
  • '''why\?'''
As novas linhas e aspas incorporadas são permitidas sem escapes. Veja o quarto exemplo. As
barras invertidas (\) iniciam as sequências de escape. Veja a tabela "Sequências de escape" abaixo.
Não é permitida uma barra invertida (\) sem escape no final de uma linha.
Encerre a string com três aspas sem escape em uma linha que correspondam às aspas iniciais.
String bruta
  • R"abc+"
  • r'''abc+'''
  • R"""abc+"""
  • r'f\(abc,(.*),def\)'
Os literais entre aspas ou aspas triplas que têm o prefixo do literal de string bruta (r ou R) são interpretados como strings brutas/regex.
Os caracteres de barra invertida (\) não funcionam como caracteres de escape. Se uma barra invertida seguida por outro caractere for usada dentro do literal de string, os dois caracteres serão preservados.
As strings brutas não podem terminar com um número ímpar de barras invertidas.
As strings brutas são úteis para construir expressões regulares.

Os caracteres de prefixo (r, R, b, B)) são opcionais para strings entre aspas ou três aspas e indicam que a string é do tipo bruta/regex ou uma sequência de bytes, respectivamente. Por exemplo, b'abc' e b'''abc''' são interpretados como bytes de tipo. Os caracteres de prefixo diferenciam maiúsculas de minúsculas.

Literais entre aspas com prefixos:

Literal Exemplo Descrição
Bytes
  • B"abc"
  • B'''abc'''
  • b"""abc"""
Os literais entre aspas ou aspas triplas com o prefixo de literal de bytes (b ou B) são interpretados como bytes.
Bytes brutos
  • br'abc+'
  • RB"abc+"
  • RB'''abc'''
Os prefixos r e b podem ser combinados em qualquer ordem. Por exemplo, rb'abc*' equivale a br'abc*'.

Na tabela a seguir, veja todas as sequências de escape válidas para representar caracteres não alfanuméricos em literais de strings e bytes. Qualquer sequência que não esteja nesta tabela resulta em erro.

Sequência de escape Descrição
\a Aviso sonoro
\b Backspace
\f Avanço de formulário
\n Nova linha
\r Retorno de carro
\t Tabulação
\v Tabulação vertical
\\ Barra invertida (\)
\? Ponto de interrogação (?)
\" Aspas duplas (")
\' Aspas simples (')
\` Acento grave (`)
\ooo Escape octal, com exatamente três dígitos (no intervalo de 0 a 7). É decodificado como um único caractere Unicode (em literais de strings) ou byte (em literais de bytes).
\xhh ou \Xhh Escape hexadecimal, com exatamente dois dígitos hexadecimais (0–9 ou A–F ou a–f). É decodificado como um único caractere Unicode (em literais de strings) ou byte (em literais de bytes). Exemplos:
  • '\x41' == 'A'
  • '\x41B' é 'AB'
  • '\x4' é um erro
\uhhhh Escape Unicode, com "u" minúsculo e exatamente quatro dígitos hexadecimais. Válido apenas em literais de string ou identificadores.
Observação: o intervalo D800-DFFF não é permitido, já que são valores unicode alternativos.
\Uhhhhhhhh Escape Unicode, com "U" maiúsculo e exatamente oito dígitos hexadecimais. Válido apenas em literais de string ou identificadores.
O intervalo D800-DFFF não é permitido, pois são valores unicode alternativos. Além disso, valores maiores que 10FFFF não são permitidos.

Literais de inteiros

Literais de inteiros são uma sequência de dígitos decimais (de 0 a 9) ou um valor hexadecimal com prefixo "0x" ou "0X". Os inteiros podem ter o prefixo "+" ou "-" para representar valores positivos e negativos, respectivamente. Exemplos:

123
0xABC
-123

Um literal de inteiro é interpretado como INT64.

Literais NUMERIC

Crie literais NUMERIC usando a palavra-chave NUMERIC seguida de um valor de ponto flutuante entre aspas.

Exemplos:

SELECT NUMERIC '0';
SELECT NUMERIC '123456';
SELECT NUMERIC '-3.14';
SELECT NUMERIC '-0.54321';
SELECT NUMERIC '1.23456e05';
SELECT NUMERIC '-9.876e-3';

Literais de ponto flutuante

Opções de sintaxe:

[+-]DIGITS.[DIGITS][e[+-]DIGITS]
[DIGITS].DIGITS[e[+-]DIGITS]
DIGITSe[+-]DIGITS

DIGITS representa um número decimal (de 0 a 9) ou mais, e e representa o rótulo expoente (e ou E).

Exemplos:

123.456e-67
.1E4
58.
4e2

Supõe-se que os literais numéricos que contêm um ponto decimal ou um rótulo expoente sejam do tipo duplo.

A coerção implícita de literais de ponto flutuante para o tipo flutuante será possível se o valor estiver dentro do intervalo flutuante válido.

Não há representação literal de NaN ou infinitude, mas é possível fazer o cast para flutuante das strings que diferenciam entre maiúsculas e minúsculas a seguir:

  • "NaN"
  • "inf" ou "+inf"
  • "-inf"

Literais de matriz

Literais de matriz são listas separadas por vírgulas de elementos entre colchetes. A palavra-chave ARRAY é opcional, assim como um tipo de elemento T explícito.

Exemplos:

[1, 2, 3]
['x', 'y', 'xy']
ARRAY[1, 2, 3]
ARRAY<string>['x', 'y', 'xy']
ARRAY<int64>[]

Literais struct

Sintaxe:

(elem[, elem...])

em que elemé um elemento no struct. elem precisa ser um tipo de dados de literal, não uma expressão ou nome de coluna.

O tipo de saída é de struct anônimo (structs são tipos não nomeados) com campos anônimos contendo tipos que correspondem aos existentes nas expressões de entrada.

Exemplo Tipo de saída
(1, 2, 3) STRUCT<int64,int64,int64>
(1, 'abc') STRUCT<int64,string>

Literais de data

Sintaxe:

DATE 'YYYY-M[M]-D[D]'

Literais de data contêm a palavra-chave DATE seguida de um literal de string em conformidade com o formato de data canônico e ficam entre aspas simples. Os literais de data, inclusive, aceitam um intervalo entre os anos 1 e 9999. As datas fora desse intervalo são inválidas.

Por exemplo, o literal de data a seguir representa 27 de setembro de 2014:

DATE '2014-09-27'

Os literais de strings no formato de data canônico também forçam, implicitamente, o tipo DATE quando usados se uma expressão do tipo DATE for esperada. Por exemplo, na consulta

SELECT * FROM foo WHERE date_col = "2014-09-27"

o literal de string "2014-09-27" será forçado para um literal de data.

Literais de carimbo de data/hora

Sintaxe:

TIMESTAMP 'YYYY-[M]M-[D]D [[H]H:[M]M:[S]S[.DDDDDD] [timezone]]'

Os literais de carimbo de data/hora contêm a palavra-chave TIMESTAMP e um literal de string em conformidade com o formato de carimbo de data/hora canônico e ficam entre aspas simples.

Os literais de carimbo de data/hora aceitam um intervalo entre os anos 1 e 9999, inclusive. Carimbos de data/hora fora desse intervalo são inválidos.

Um literal de carimbo de data/hora pode incluir um sufixo numérico para indicar o fuso horário:

TIMESTAMP '2014-09-27 12:30:00.45-08'

Se esse sufixo estiver ausente, o fuso horário padrão, "América/Los Angeles", será usado.

Por exemplo, este carimbo de data/hora representa 12h30 do dia 27 de setembro de 2014, usando o fuso horário "América/Los Angeles":

TIMESTAMP '2014-09-27 12:30:00.45'

Para ver mais informações de fusos horários, veja Fuso horário.

Literais de string com o formato de carimbo de data/hora canônico, incluindo aqueles com nomes de fusos horários, forçam implicitamente um literal de carimbo de data/hora quando usados se uma expressão de carimbo de data/hora for esperada. Por exemplo, na consulta a seguir, o literal de string "2014-09-27 12:30:00.45 America/Los_Angeles" é forçado para um literal de carimbo de data/hora.

SELECT * FROM foo
WHERE timestamp_col = "2014-09-27 12:30:00.45 America/Los_Angeles"

Um literal de carimbo de data/hora pode incluir estes caracteres opcionais:

  • T ou t: uma sinalização de tempo. Use como separador entre a data e a hora.
  • Z ou z: uma sinalização para o fuso horário padrão. Não é possível usar com [timezone].

Se você usar um desses caracteres, um espaço não poderá ser incluído antes ou depois dele. Estes são válidos:

TIMESTAMP '2017-01-18T12:34:56.123456Z'
TIMESTAMP '2017-01-18t12:34:56.123456'
TIMESTAMP '2017-01-18 12:34:56.123456z'
TIMESTAMP '2017-01-18 12:34:56.123456Z'

Fuso horário

Devido à obrigatoriedade de mapear os literais de carimbo de data/hora para um ponto específico no tempo, um fuso horário é necessário para interpretar corretamente um literal. Se um fuso horário não for especificado como parte do literal propriamente dito, o SQL do Cloud Spanner usará o valor de fuso horário padrão definido pela implementação SQL do Cloud Spanner.

O SQL do Cloud Spanner representa os fusos horários usando strings no seguinte formato canônico, que representa o deslocamento do tempo universal coordenado (UTC).

Formato:

(+|-)H[H][:M[M]]

Exemplos:

'-08:00'
'-8:15'
'+3:00'
'+07:30'
'-7'

Os fusos horários também podem ser expressos com strings de nomes de fusos horários do tz database. Para ter uma referência menos explicativa, porém mais simples, veja a Lista de fusos horários do tz database (em inglês) na Wikipédia. Os nomes de fusos horários canônicos têm o formato <continent/[region/]city>, como America/Los_Angeles.

Exemplo:

TIMESTAMP '2014-09-27 12:30:00 America/Los_Angeles'
TIMESTAMP '2014-09-27 12:30:00 America/Argentina/Buenos_Aires'

Diferenciação entre maiúsculas e minúsculas

O Cloud Spanner SQL segue estas regras para diferenciar maiúsculas de minúsculas:

Categoria Diferenciação entre maiúsculas e minúsculas? Observações
Palavras-chave Não  
Nomes de funções Não  
Nomes de tabela Consulte as observações Os nomes de tabela geralmente não diferenciam maiúsculas de minúsculas, mas podem diferenciar quando se consulta um banco de dados que usa nomes de tabela com essa diferenciação.
Nomes de coluna Não  
Valores de strings Sim
Comparações de strings Sim  
Aliases dentro de uma consulta Não  
Correspondência com expressões regulares Consulte as observações A expressão regular correspondente diferencia maiúsculas de minúsculas por padrão, a menos que a própria expressão especifique que ela não pode fazer essa diferenciação.
Correspondência com LIKE Sim  

Palavras-chave reservadas

Palavras-chave são um grupo de tokens que têm um significado especial na linguagem Cloud Spanner SQL e as seguintes características:

  • Não é possível usar palavras-chave como identificadores a menos que estejam entre caracteres de acento grave (`).
  • As palavras-chave não diferenciam maiúsculas de minúsculas.

O Cloud Spanner SQL tem as seguintes palavras-chave reservadas.

ALL
AND
ANY
ARRAY
AS
ASC
ASSERT_ROWS_MODIFIED
AT
BETWEEN
BY
CASE
CAST
COLLATE
CONTAINS
CREATE
CROSS
CUBE
CURRENT
DEFAULT
DEFINE
DESC
DISTINCT
ELSE
END
ENUM
ESCAPE
EXCEPT
EXCLUDE
EXISTS
EXTRACT
FALSE
FETCH
FOLLOWING
FOR
FROM
FULL
GROUP
GROUPING
GROUPS
HASH
HAVING
IF
IGNORE
IN
INNER
INTERSECT
INTERVAL
INTO
IS
JOIN
LATERAL
LEFT
LIKE
LIMIT
LOOKUP
MERGE
NATURAL
NEW
NO
NOT
NULL
NULLS
OF
ON
OR
ORDER
OUTER
OVER
PARTITION
PRECEDING
PROTO
RANGE
RECURSIVE
RESPECT
RIGHT
ROLLUP
ROWS
SELECT
SET
SOME
STRUCT
TABLESAMPLE
THEN
TO
TREAT
TRUE
UNBOUNDED
UNION
UNNEST
USING
WHEN
WHERE
WINDOW
WITH
WITHIN

Ponto e vírgula de terminação

Como opção, as instruções de string de consulta podem terminar com ponto e vírgula (;) quando enviadas por meio da Interface de Programação do Aplicativo (API).

Em solicitações com várias instruções, elas precisam ser separadas por ponto e vírgula, que costuma ser opcional após a instrução final. Em algumas ferramentas interativas, é necessário que as instruções terminem com ponto e vírgula.

Vírgulas à direita

É possível usar uma vírgula à direita (,) no final de uma lista em uma instrução SELECT.

Exemplo

SELECT name, release_date, FROM Books

Parâmetros de consulta

Use parâmetros de consulta para substituir expressões arbitrárias. No entanto, parâmetros de consulta não podem ser usados para substituir identificadores, nomes de colunas, nomes de tabelas ou outras partes da própria consulta. Parâmetros de consulta são definidos fora da instrução de consulta.

As APIs do cliente permitem a vinculação de nomes de parâmetros a valores; o mecanismo de consulta substitui um valor vinculado por um parâmetro no momento da execução.

Parâmetros de consulta nomeados

Sintaxe:

@parameter_name

Um parâmetro de consulta nomeado é indicado com o uso de um identificador precedido pelo caractere @.

Exemplo:

Este exemplo retorna todas as linhas em que LastName é igual ao valor do parâmetro de consulta nomeado myparam.

SELECT * FROM Roster WHERE LastName = @myparam

Dicas

@{ hint [, ...] }

hint:
  [engine_name.]hint_name = value

O objetivo de uma dica é modificar a estratégia de execução de uma consulta sem alterar o resultado da consulta. As dicas geralmente não afetam a semântica de consulta, mas podem ter implicações no desempenho. Estes tipos de dica estão disponíveis:

A sintaxe de dica requer o caractere @ seguido de chaves. Você pode criar uma dica ou um grupo de dicas. O prefixo engine_name. opcional permite que vários mecanismos definam dicas com o mesmo hint_name. Isso é importante se você precisar sugerir diferentes estratégias de execução específicas do mecanismo ou diferentes mecanismos compatíveis com diferentes dicas.

Você pode atribuir identificadores e literais a dicas.

  • Os identificadores são úteis para dicas que funcionam como enumerações. Você pode usar um identificador para evitar o uso de uma string entre aspas. No AST resolvido, as dicas de identificador são representadas como literais de string. Portanto, @{hint="abc"} é o mesmo que @{hint=abc}. Dicas de identificador também podem ser usadas para dicas que usam um nome de tabela ou nome de coluna como um único identificador.
  • Os literais NULL são permitidos e são inferidos como números inteiros.

As dicas devem ser aplicadas apenas ao nó ao qual estão anexadas, e não a um escopo maior. Por exemplo, uma dica em um JOIN no meio da cláusula FROM deve ser aplicada somente a esse JOIN, e não a outros JOIN s na cláusula FROM. As dicas no nível da instrução podem ser usadas para dicas que modificam a execução de uma instrução inteira, por exemplo, um orçamento de memória geral ou um prazo.

Exemplos

Neste exemplo, um literal é atribuído a uma dica. Essa dica é usada apenas com dois mecanismos de banco de dados chamados database_engine_a e database_engine_b. O valor da dica é diferente para cada mecanismo de banco de dados.

@{ database_engine_a.file_count=23, database_engine_b.file_count=10 }

Neste exemplo, um identificador é atribuído a uma dica. Há identificadores exclusivos para cada tipo de dica. Você pode ver uma lista de tipos de dica no início deste tópico.

@{ JOIN_METHOD=HASH_JOIN }

Comentários

Comentários são sequências de caracteres ignoradas pelo analisador. O SQL do Cloud Spanner é compatível com os seguintes tipos de comentários.

Comentários de linha única

Use um comentário de linha única se quiser que o comentário apareça apenas em uma linha.

Exemplos

# this is a single-line comment
SELECT book FROM library;
-- this is a single-line comment
SELECT book FROM library;
/* this is a single-line comment */
SELECT book FROM library;
SELECT book FROM library
/* this is a single-line comment */
WHERE book = "Ulysses";

Comentários in-line

Use um comentário in-line se quiser que ele apareça na mesma linha da instrução. Comentários precedidos por # ou -- têm que aparecer à direita das instruções.

Exemplos

SELECT book FROM library; # this is an inline comment
SELECT book FROM library; -- this is an inline comment
SELECT book FROM library; /* this is an inline comment */
SELECT book FROM library /* this is an inline comment */ WHERE book = "Ulysses";

Comentários de várias linhas

Use um comentário de várias linhas se precisar que o comentário inclua várias linhas. Comentários de várias linhas aninhados não são compatíveis.

Exemplos

SELECT book FROM library
/*
  This is a multiline comment
  on multiple lines
*/
WHERE book = "Ulysses";
SELECT book FROM library
/* this is a multiline comment
on two lines */
WHERE book = "Ulysses";