Sintaxe no PostgreSQL: ENUM
2 de Abril de 2018, 13:57 - sem comentários aindaOs tipos enumerados ou ENUM, são uma das melhores ideias que o PostgreSQL copiou do MySQL. Sério! Eles foram introduzidos na versão 8.3 do Postgres e são realmente muito úteis. Claro que a implementação no PostgreSQL é bem mais elegantes, pois utiliza o CREATE TYPE e ALTER TYPE como veremos a seguir. Isso nos dá uma implementação mais robusta e flexível para o ENUM. O ENUM é ideal para para colunas que podem receber um conjunto relativamente estável de valores possíveis. Sabe aquelas colunas que você usa com frequência como status, estado civil, sexo, etc. Você geralmente tem 3 opções quando não tem o ENUM como tipo de dado:
- Cria uma tabela auxiliar com um ID e o nome da característica em questão:
CREATE TABLE estado_civil ( id SERIAL PRIMARY KEY, nome VARCHAR(15) NOT NULL UNIQUE ); INSERT INTO estado_civil(nome) VALUES ('Solteiro'); INSERT INTO estado_civil(nome) VALUES ('Casado'); INSERT INTO estado_civil(nome) VALUES ('Divorciado'); INSERT INTO estado_civil(nome) VALUES ('Viúvo');
- Criar uma coluna com os mesmos valores possíveis:
CREATE TABLE pessoa( id SERIAL PRIMARY KEY, nome VARCHAR(50) NOT NULL UNIQUE, estado_civil VARCHAR(15), CONSTRAINT estado_civil_check CHECK (estado_civil IN ('Solteiro', 'Casado', 'Divorciado', 'Viúvo')) );
- Criar uma coluna com códigos que representem os valores possíveis:
CREATE TABLE pessoa ( id SERIAL PRIMARY KEY, nome VARCHAR(50) NOT NULL UNIQUE, estado_civil CHAR(1), CONSTRAINT estado_civil_check CHECK (estado_civil IN ('S', 'C', 'D', 'V')) ); COMMENT ON COLUMN pessoa.estado_civil IS 'S = Solteiro, C = Casado, D = Divorciado, V = Viúvo';
A primeira opção é a que apresenta a melhor modelagem. Permite que você adicione novos tipos de estado civil sem ter que mexer na tabela. Se você tiver varias tabelas com uma FK para a tabela estado_civil, alterando os seus dados, você altera para todas as tabelas relacionadas a identidade do campo estado civil. A única coisa chata é ter que criar uma tabela nova só para isso, e ter que fazer mais um JOIN toda vez que quiser resgatar os nomes dos estados civis.
A segunda opção deverá consumir muito espaço em disco desnecessariamente, uma vez que vai armazenar a palavra inteira e repeti-la varias vezes. Não é uma opção muito elegante.
A terceira opção, não tem o nome do estado civil explícito no valor do campo. Você vai ter que traduzir ‘S’ para ‘Solteiro’ no código da sua aplicação. Isso é uma operação bastante indesejada, pois algo que deveria ser dinâmico, se torna hard coded, com uma manutenção ruim para fazer.
Criando seu ENUM
Vejamos como ficaria o mesmo problema utilizando ENUM:
CREATE TYPE estado_civil AS ENUM('Solteiro', 'Casado', 'Divorciado', 'Viúvo'); CREATE TABLE pessoa ( id SERIAL PRIMARY KEY, nome VARCHAR(50) NOT NULL UNIQUE, estado_civil_pessoa estado_civil );
Veja que você criou um tipo de dados chamado estado_civil e utilizou ele na tabela pessoa. É quase como criar uma tabela auxiliar. Mas não existe um ID no meio. Quando você for fazer um INSERT na tabela pessoa, você tem que utilizar os nomes completos de cada tipo:
teste=# INSERT INTO pessoa (nome, estado_civil_pessoa) VALUES ('Paulo', 'Solteiro'); INSERT 0 1 teste=# INSERT INTO pessoa (nome, estado_civil_pessoa) VALUES ('João', 'Casado'); INSERT 0 1 teste=# INSERT INTO pessoa (nome, estado_civil_pessoa) VALUES ('Joaquim', 'Enrolado'); ERROR: invalid input value for enum estado_civil: "Enrolado" LINE 1: ...oa (nome, estado_civil_pessoa) VALUES ('Joaquim', 'Enrolado'...
Veja que você não precisa adicionar uma constraint para limitar os valores possíveis. Se você tentar inserir um valor inválido, o Postgres vai lhe avisar que aquele valor não é aceito, pois não faz parte do tipo de dados estado_civil. No entanto, você pode querer alterar o tipo de dados e incluir um novo elemento:
teste=# ALTER TYPE estado_civil ADD VALUE 'Enrolado'; ALTER TYPE teste=# INSERT INTO pessoa (nome, estado_civil_pessoa) VALUES ('Joaquim', 'Enrolado'); INSERT 0 1
Renomeando
Por fim, você ainda pode alterar o nome de um dos elementos (ou rótulos ou em inglês, labels). A sintaxe é a seguinte:
ALTER TYPE name RENAME VALUE existing_enum_value TO new_enum_value
Vejamos um exemplo para o tipo estado_civil:
teste=# SELECT * FROM pessoa WHERE nome = 'Joaquim'; id | nome | estado_civil_pessoa ----+---------+--------------------- 3 | Joaquim | Enrolado (1 row) teste=# ALTER TYPE estado_civil RENAME VALUE 'Enrolado' TO 'Amasiado'; ALTER TYPE teste=# SELECT * FROM pessoa WHERE nome = 'Joaquim'; id | nome | estado_civil_pessoa ----+---------+--------------------- 3 | Joaquim | Amasiado (1 row)
Ordenação
Se você quiser ordenar as linhas de uma tabela com base em um campo ENUM a ordenação não será feita com base nos valores do tipo estado_civil e sim pela ordem em que eles foram criados no seu tipo:
teste=# SELECT * FROM pessoa ORDER BY estado_civil_pessoa; id | nome | estado_civil_pessoa ----+---------+--------------------- 1 | Paulo | Solteiro 2 | João | Casado 3 | Joaquim | Amasiado (3 rows)
Se você quiser consultar como estão os elementos do seu tipo ENUM, você pode consultar o catálogo do Postgres com a seguinte consulta:
SELECT typname AS nome_tipo, typlen AS tamanho_elemento, enumsortorder AS ordem, enumlabel AS label FROM pg_type t JOIN pg_enum e ON t.oid = e.enumtypid WHERE typname = 'estado_civil';
nome_tipo | tamanho_elemento | ordem | label --------------+------------------+-------+------------ estado_civil | 4 | 1 | Solteiro estado_civil | 4 | 2 | Casado estado_civil | 4 | 3 | Divorciado estado_civil | 4 | 4 | Viúvo estado_civil | 4 | 5 | Amasiado (5 rows)
Veja que todos elementos são armazenados com apenas 4 bytes enquanto o rótulo em si, pode ter até 63 bytes. Na tabela pessoa, independente do tamanho do rótulo serão armazenados apenas 4 bytes, o mesmo tamanho de um campo INTEGER.
Você também pode utilizar um atalho no psql:
teste=# \dT+ estado_civil List of data types Schema | Name | Internal name | Size | Elements | Owner | Access privileges | Description --------+--------------+---------------+------+------------+----------+-------------------+------------- public | estado_civil | estado_civil | 4 | Solteiro +| postgres | | | | | | Casado +| | | | | | | Divorciado+| | | | | | | Viúvo +| | | | | | | Amasiado | | | (1 row)
Você pode ainda adicionar novos elementos em uma posição específica no seu ENUM. Vejamos a sintaxe para isso:
ALTER TYPE name ADD VALUE [ IF NOT EXISTS ] new_enum_value [ { BEFORE | AFTER } neighbor_enum_value ]
Vejamos um exemplo:
teste=# ALTER TYPE estado_civil ADD VALUE 'Namorando' AFTER 'Solteiro'; ALTER TYPE teste=# \dT+ estado_civil List of data types Schema | Name | Internal name | Size | Elements | Owner | Access privileges | Description --------+--------------+---------------+------+------------+----------+-------------------+------------- public | estado_civil | estado_civil | 4 | Solteiro +| postgres | | | | | | Namorando +| | | | | | | Casado +| | | | | | | Divorciado+| | | | | | | Viúvo +| | | | | | | Amasiado | | | (1 row)
Na verdade a sintaxe é um pouco mais elegante, você pode A sintaxe completa para alterar um tipo ENUM
Restrições
- O tamanho do rótulo ou label, é de no máximo 63 bytes, que é o valor da constante NAMEDATALEN definida no ato de compilação do PostgreSQL. Ou seja, você pode alterar este valor, mas você terá que trabalhar com uma versão compilada por você mesmo do Postgres para isso. Em geral 63 bytes costuma ser mais que suficiente;
- Você não pode apagar elementos já existentes no seu ENUM nem trocar eles de lugar depois que já foram inseridos;
- Você não pode
- Se você tentar dar um DROP no seu tipo de dados ENUM e ele já estiver sendo utilizado em outras tabelas, vai ter que utilizar um CASCADE, o que vai excluir as colunas que utilizam o ENUM nestas tabelas:
teste=# DROP TYPE estado_civil ; ERROR: cannot drop type estado_civil because other objects depend on it DETAIL: table pessoa column estado_civil_pessoa depends on type estado_civil HINT: Use DROP ... CASCADE to drop the dependent objects too. teste=# DROP TYPE estado_civil CASCADE; NOTICE: drop cascades to table pessoa column estado_civil_pessoa DROP TYPE teste=# \d pessoa Table "public.pessoa" Column | Type | Collation | Nullable | Default --------+-----------------------+-----------+----------+------------------------------------ id | integer | | not null | nextval('pessoa_id_seq'::regclass) nome | character varying(50) | | not null | Indexes: "pessoa_pkey" PRIMARY KEY, btree (id) "pessoa_nome_key" UNIQUE CONSTRAINT, btree (nome)
Conclusão
Podemos dizer que o uso do ENUM:
- Tem uma sintaxe limpa e simples de utilizar;
- Torna a sua vida mais simples, pois você declara o tipo ENUM uma vez e pode utilizar em varias tabelas;
- Torna suas consultas mais simples do que utilizar uma tabela auxiliar, pois você não precisa fazer outro JOIN;
- É eficiente em termos de armazenamento, pois ocupa pouco espaço em disco;
- Não exige a utilização de códigos que precisam ser convertidos na aplicação;
- Tem uma ordenação própria que leva em conta a ordem dos valores em que são adicionados no tipo e não a ordenação alfabética dos seus labels;
- Tem uma boa flexibilidade para adicionar novos valores em uma ordem específica;
- Não permite remover labels sem ter que destruir e recriar o ENUM. Devem ser evitados quando a lista de valores possíveis for muito dinâmica. Neste caso uma tabela auxiliar deve ser mais adequada;
Resumindo: não serve para tudo, mas no lugar certo, é uma mão na roda!
Sintaxe no PostgreSQL: booleanos
30 de Março de 2018, 11:44 - sem comentários aindaSe você não leu, recomendo que veja o artigo sobre estrutura léxica do PostgreSQL antes de começar por aqui.
Toda informática é baseada na lógica booleana. Os dados booleanos são utilizados geralmente como flags para marcar se determinado atributo de uma tabela está presente ou não. Por incrível que pareça, apesar de ser o tipo de dado mais simples que existe e fazer parte do padrão SQL, poucos SGDBs implementam este tipo de dado e armazenem ele como uma coluna de uma tabela.
Uma coluna booleana pode ter apenas 3 valores distintos, falso, verdadeiro ou nulo. O PostgreSQL possui 3 palavras reservadas para lidar com estes valores: FALSE, TRUE e NULL. Veja como exemplo a tabela verdade envolvendo valores booleanos:
teste=# CREATE TABLE bol (x boolean, y boolean); CREATE TABLE ^ teste=# INSERT INTO bol VALUES (FALSE, FALSE); INSERT 0 1 teste=# INSERT INTO bol VALUES (FALSE, TRUE); INSERT 0 1 teste=# INSERT INTO bol VALUES (FALSE, NULL); INSERT 0 1 teste=# INSERT INTO bol VALUES (TRUE, FALSE); INSERT 0 1 teste=# INSERT INTO bol VALUES (TRUE, TRUE); INSERT 0 1 teste=# INSERT INTO bol VALUES (TRUE, NULL); INSERT 0 1 teste=# INSERT INTO bol VALUES (NULL, NULL); INSERT 0 1 teste=# SELECT x, y, NOT x AS n_x, NOT y AS n_y, x OR y AS x_or_y, x AND y AS x_and_y FROM bol; x | y | n_x | n_y | x_or_y | x_and_y ---+---+-----+-----+--------+--------- f | f | t | t | f | f f | t | t | f | t | f f | | t | | | f t | f | f | t | t | f t | t | f | f | t | t t | | f | | t | | | | | | (7 rows)
Note que como resultado o PostgreSQL exibe uma representação dos valores de TRUE, FALSE e NULL como ‘f’, ‘t’ e vazio respectivamente, mas isso é apenas uma representação. Existem outras formas representar verdadeiro e falso:
teste=# INSERT INTO bol VALUES ('t', 'f'); INSERT 0 1 teste=# INSERT INTO bol VALUES ('T', 'F'); INSERT 0 1 teste=# INSERT INTO bol VALUES ('true', 'false'); INSERT 0 1 teste=# INSERT INTO bol VALUES ('TRUE', 'FALSE'); INSERT 0 1 teste=# INSERT INTO bol VALUES ('YES', 'NO'); INSERT 0 1 teste=# INSERT INTO bol VALUES ('yes', 'no'); INSERT 0 1 teste=# INSERT INTO bol VALUES ('y', 'n'); INSERT 0 1 teste=# INSERT INTO bol VALUES ('Y', 'N'); INSERT 0 1 teste=# INSERT INTO bol VALUES ('on', 'off'); INSERT 0 1 teste=# INSERT INTO bol VALUES ('ON', 'OFF'); INSERT 0 1 teste=# INSERT INTO bol VALUES ('0', '1'); INSERT 0 1 teste=# INSERT INTO bol VALUES (0, 1); ERROR: column "x" is of type boolean but expression is of type integer LINE 1: INSERT INTO bol VALUES (0, 1); HINT: You will need to rewrite or cast the expression. teste=# INSERT INTO bol VALUES ('NULL', 'null'); ERROR: invalid input syntax for type boolean: "NULL" LINE 1: INSERT INTO bol VALUES ('NULL', 'null'); teste=# INSERT INTO bol VALUES ('', ''); ERROR: invalid input syntax for type boolean: "" LINE 1: INSERT INTO bol VALUES ('', '');
Você não pode exagerar muito, se você colocar qualquer número sem aspas simples, o PostgreSQL sempre vai interpretar isso como um número. E NULL só pode ser representado com a sua palavra reservada. Não pode estar entre aspas simples e vazio é diferente de nulo. Você não pode inserir ” como sinônimo para NULL.
O PostgreSQL aceita coisas como ‘t’, ‘true’, ‘y’, ‘yes’, ‘on’, ‘1’ como sinônimos para TRUE. Mas isso funciona dentro de um INSERT. Neste contexto o PostgreSQL faz uma coerção implícita para o tipo correto de dados. Vejamos o que ocorre em outros contextos:
teste=# SELECT TRUE AND FALSE; ?column? ---------- f (1 row) teste=# SELECT 'TRUE' AND 'FALSE'; ?column? ---------- f (1 row) teste=# SELECT 't' AND 'f'; ?column? ---------- f (1 row) teste=# UPDATE bol SET x = 'on' WHERE y = 'off'; UPDATE 12
So far, so good. Mas existe um contexto que é mais sensível: a chamada de uma função. Suponhamos que você tenha uma função como esta:
CREATE FUNCTION not_and (boolean, boolean) RETURNS boolean AS $func$ BEGIN RETURN NOT ($1 AND $2); END; $func$ LANGUAGE plpgsql;
Agora vamos chamar esta função:
teste=# SELECT not_and('true', 'false'); not_and --------- t (1 row)
Perfeito. Tudo tranquilo. Parece que o PostgreSQL está se comportando exatamente como você esperava. Então onde está o problema? Bom, acontece que no PostgreSQL você pode ter sobrecarga de funções. Ou seja, varias funções com o mesmo nome, recebendo parâmetros diferentes. Vejamos um exemplo:
CREATE FUNCTION not_and (text, text) RETURNS text AS $func$ BEGIN RETURN $1 || $2; END; $func$ LANGUAGE plpgsql;
A função tem o mesmo nome, mas recebe parâmetros do tipo TEXT. Vejamos o que acontece quando fazemos exatamente a mesma chamada que antes:
teste=# SELECT not_and('true', 'false'); not_and ----------- truefalse (1 row)
Aqui o comportamento foi diferente. E veja que utilizamos exatamente a mesma chamada que antes! O PostgreSQL utilizou a função com parâmetros do tipo TEXT e não do tipo BOOLEAN. Para corrigir isso você tem duas opções:
teste=# SELECT not_and(boolean 'true', boolean 'false'); not_and --------- t (1 row) teste=# SELECT not_and(TRUE, FALSE); not_and --------- t (1 row)
OU seja: ou você utiliza uma coerção explícita (que você vai utilizar muito com outros tipos de dados em chamadas de funções) ou utiliza as palavras reservadas. Particularmente eu acho que utilizar sempre as palavras reservadas TRUE e FALSE muito mais elegante e evita possíveis dores de cabeça no futuro. Você pode perder um bom tempo até descobrir que existe outra função com o mesmo nome mas parâmetros diferentes…
Existe ainda um contexto peculiar em que valores booleanos podem ser utilizados de forma peculiar. Quando você quer fazer um teste do tipo verdadeiro ou falso, como num IF ou num WHERE, você pode utilizar uma sintaxe mais direta. Veja o UPDATE abaixo com o WHERE escrito de duas formas diferentes:
teste=# UPDATE bol SET x = 'on' WHERE y = TRUE; UPDATE 3 teste=# UPDATE bol SET x = 'on' WHERE y; UPDATE 3
Observação importante
Por último um pequeno comentário sobre o uso de booleanos como tipo de dados em suas tabelas. O PostgreSQL aloca um byte e não um bit para armazenar uma coluna do tipo booleano. Em muitos casos você pode utilizar outros tipos de dados no lugar do BOOLEAN, como um TIMESTAMP (que ocupa 8 bytes) por exemplo. Diferente de tempos passados, economizar demais em tipos de dados não é uma grande vantagem. Mas imagine o caso em que você quer um flag para saber se um cliente está inativo ou não. Se você utilizar um TIMESTAMP, você pode deixar a coluna como NULL se o cliente não estiver inativo e inserir a data de inativação caso o cliente tenha sido inativado. Se uma minoria dos clientes forem inativados, o consumo de espaço em disco a mais será mínimo e você está armazenando mais informação neste caso. Saber a data de inativação pode ser importante para você no futuro. Existem outros casos em que ativo e inativo pode não ser suficientes, você pode querer ter mais valores possíveis para a sua coluna. Neste caso você poderia utilizar o tipo ENUM.
Sintaxe no PostgreSQL: estrutura lexica
28 de Março de 2018, 19:44 - sem comentários aindaEste post inicia uma série de artigos sobre a linguagem SQL no PostgreSQL. Na documentação oficial, o capítulo 4 possui uma longa explicação sobre sintaxe SQL no PostgreSQL. Confesso que quando eu li sobre isso há mais de 15 anos, tive vontade de pular essa parte. Bastante burocrática e pouco interessante. Mas… o mal mora nos detalhes! Entre as minhas abas abertas do meu navegador (quase sempre com uma ou duas abas da documentação do Postgres), me vejo revisitando este capítulo mais e mais vezes. Gostaria de começar pelo começo… e de fato, temos muitos detalhes importantes que vão influenciar na forma como você deve escrever seus comandos SQL no PostgreSQL.
Dando nomes às partes
Trazendo diretamente da documentação temos:
“SQL input consists of a sequence of commands. A command is composed of a sequence of tokens, terminated by a semicolon (“;”).”
A tradução de alguns termos é meio estranha aos ouvidos, por isso trouxe a expressão original do inglês, mas vamos lá: “Uma entrada SQL consiste numa sequência de comandos. Cada comando é composto por uma sequência de tokens terminadas por um ponto e vírgula (“;”). ”
A tradução da palavra token é meio complicada, mas você pode chamar de símbolo, sinal, palavra ou outras possibilidades que o Google me sugeriu, mas isto iria confundir a definição a seguir:
“Um token pode ser uma palavra chave, um identificador, um identificador entre aspas*, uma constante, ou um símbolo de caractere especial. As fichas são normalmente separadas por espaços em branco(espaços, tabulações ou nova linha), mas isso não é obrigatório se não houver ambiguidade (que é geralmente o caso se um caractere especial estiver entre fichas de outros tipos)”
Uma definição relativamente simples, que já dá algumas dicas importantes, mas vamos por partes. Agora vamos ver isso em detalhes:
Palavras chave
São fichas que possuem um significado especial na linguagem SQL como UPDATE, SELECT, WHERE, FROM, etc. As palavras chave vão mudando com o passar do tempo como você pode ver na lista da documentação. Isso significa que conforme novas versões do padrão SQL vão surgindo, novas palavras chave vão sendo adicionadas. Da mesma forma, conforme novas versões do PostgreSQL vão sendo lançadas, novas implementações do padrão SQL e fora do padrão SQL vão sendo incorporadas a lista de palavras chave. Existem funcionalidades que o PostgreSQL lança antes de se tornarem padrão SQL e funcionalidades do padrão SQL que o PostgreSQL não implementa. Para complicar um pouco mais, existem palavras chaves reservadas e não reservadas. A diferença é que as palavras chave reservadas nunca podem ser utilizadas como identificadores e as palavras chaves não reservadas podem ser utilizadas em alguns tipos de identificadores. E tem mais uma questão importante… nada impede que no futuro, novas palavras chaves sejam criadas para novas funcionalidades que venham a ser implementadas no futuro.
Então o mais importantes sobre palavras chaves que você deve entender é: não use uma palavra chave como identificador. Seja esse identificador o nome de uma tabela, coluna de tabela ou nome de uma função. Não use e pronto. Independente se ela é reservada no padrão SQL:92, SQL:2011 ou SQL:2016 ou apenas no PostgreSQL. Evite ao máximo. Sua vida vai ficar bem mais fácil assim.
Uma excessão à regra é o uso de apelidos (alias em inglês) em nomes de colunas como em
SELECT resultado AS table FROM foo;
Palavras chave não fazem distinção de letras maiúsculas e minúsculas (ou em inglês case insensitive) no PostgreSQL. Isso significa que você pode escrever UPDATE, update, ou UPdate e o Postgres vai interpretar exatamente da mesma forma. Mas é um costume antigo e considerado desejável, que você escreva suas palavras reservadas sempre em letras maiúsculas. Algumas vezes as pessoas também tem o hábito de escrever nomes de funções em letras maiúsculas. No entanto, nomes de funções não são palavras reservadas, são identificadores, o que pode gerar alguns problemas em situações bastante específicas. o que não é necessário, mas também não gera muitos
Identificadores
Identificadores são nomes que você dá para os objetos que você cria no seu banco de dados, bem como variáveis em linguagens de programação como o PL/pgSQL. Como dissemos antes, não utilize nunca palavras reservadas como identificadores. Identificadores são sensíveis a diferenças entre maiúsculas e minúsculas (case sensitive em inglês) de uma forma particular. Se o seu identificador não estiver entre aspas duplas, o Postgres vai considerar todas as letras como minúsculas independente de como você escrever. Desta forma: ID, id e Id para o PostgreSQL sempre serão equivalentes a id. Por outro lado, se você utilizar aspas duplas, como em “ID”, “id” e “Id”, cada um deles se referem a um objeto diferente. Isso pode causar uma bela confusão, maior do que você possa imaginar. Então, por uma questão de sanidade mental e maior chance de não ser colocado de castigo na chuva num domingo de carnaval amarrado no meio da jaula dos leões, é melhor você criar identificadores com letras minúsculas e apenas letras minúsculas. Você não vai precisar nunca das aspas e nunca vai se confundir. Para separar várias palavras num identificador, você utiliza o sublinhado ( _ ), como em nome_produto_nota. Simples e fácil de ler. Você pode criar identificadores com até 63 caracteres, o que é mais do que suficiente para você criar um monstro se necessário.
Então vamos às regras de ouro dos identificadores:
- Use letras minúsculas, sempre;
- Não utilize acentos ou melhor, utilize apenas letras do alfabeto latino sem acentos. Nada de cirílico, letras gregas, runas, ideogramas etc;
- Se seu identificador possui varias palavras, separe elas por um sublinhado;
- Todo identificador deve começar com uma letra;
- Você pode utilizar alem de letras (eu te avisei para só utilizar as minúsculas, né?), algarismos de 0 a 9 e sublinhado. Também é possível usar o $, mas como isso não é padrão SQL, isso não é uma boa ideia;
Por fim, uma recomendação importante: siga um padrão de nomenclatura para os seus identificadores. Não importa qual seja. A discussão sobre qual é o melhor padrão é interminável. Apenas escolha um que fizer mais sentido para a sua equipe siga ele até a morte. Se você mudar de padrão no meio de um projeto, vai instalar o caos. Mas adote um padrão. Qualquer um.
Constantes
Constantes são os dados atribuídos aos seus identificadores. Eles podem ter diversos tipos e cada um deles tem suas peculiaridades. O SQL é uma linguagem fortemente tipada. Isso significa que o tipo da constante faz muita diferença para ele e você deve se importar com isso. E muito. Você será uma pessoa muito mais feliz, se souber utilizar isso de forma correta. Pode não ficar milionário, mas as pessoas vão te respeitar mais, você terá mais sucesso no amor e terá menos doenças relacionadas ao stress.
Dependendo de como você escrever uma determinada constante, ela vai ser automaticamente enquadrada em um tipo específico. Isso ocorre particularmente com texto (sempre entre aspas simples) e números. Em algumas situações, como durante um INSERT, UPDATE ou numa cláusula WHERE, o PostgreSQL vai interpretar o tipo da constante segundo o campo relacionado.
Números
Números possuem uma sintaxe específica. Sempre que você escrevem algarismos sem aspas simples ou duplas, o PostgreSQL vai tentar interpretar como um número. O detalhe importante é como lidar com o separador de casas decimais e com a notação científica:
-
- Sem separador decimal, o PostgreSQL interpreta sempre a constante como um INTEGER. Se o número for muito grande, ele vai utilizar o BIGINT. Note que a vírgula é utilizada para separar duas constantes inteiras distintas. Ex:
teste=# SELECT 42,8; ?column? | ?column? ----------+---------- 42 | 8
- Com o separador decimal (que é sempre um ponto, não uma vírgula), o PostgreSQL interpresa como um NUMERIC. Ex:
teste=# SELECT 4.2, .4, 4.; ?column? | ?column? | ?column? ----------+----------+---------- 4.2 | 0.4 | 4
- Podemos usar a notação científica também usando a letra ‘e’ ou ‘E’. Então quando queremos um número como 42×10³ que é a mesma coisa que 42000, usamos 42e3. Ex:
teste=# SELECT 42e5, 42e-5, 4.2e5, 4.2e-5; ?column? | ?column? | ?column? | ?column? ----------+----------+----------+---------- 4200000 | 0.00042 | 420000 | 0.000042 (1 row) teste=# SELECT 42E5, 42E-5, 4.2E5, 4.2E-5; ?column? | ?column? | ?column? | ?column? ----------+----------+----------+---------- 4200000 | 0.00042 | 420000 | 0.000042 (1 row)
Cadeias de Caracteres
Caracteres devem vir sempre entre aspas simples. Não confundir com aspas duplas que são utilizados para identificadores, como vimos acima e não para constantes. Existem 3 tipos de constantes relacionadas com caracteres no PostgreSQL: CHARACTER ou CHAR, CHARACTER VARYNG ou VARCHAR e TEXT. Se você não especificar nada, o PostgreSQL vai sempre assumir como TEXT, que é semelhante ao VARCHAR sem limitação de tamanho (até o limite do PostgreSQL de 1GB). Trabalhar com cadeias de caracteres (ou strings em inglês) tem suas peculiaridades.
Concatenação
Juntar duas strings é fácil:
teste=# SELECT 'foo','bar'; ?column? | ?column? ----------+---------- foo | bar (1 row) teste=# SELECT 'foo' 'bar'; ERROR: syntax error at or near "'bar'" LINE 1: SELECT 'foo' 'bar'; ^ teste=# SELECT 'foo' || 'bar'; ?column? ---------- foobar (1 row) teste=# SELECT 'foo' teste-# 'bar'; ?column? ---------- foobar (1 row)
- No primeiro caso, a vírgula separa duas constantes distintas, assim como ocorreu com números.
- No segundo caso tivemos um erro de sintaxe.
- Para concatenar as duas cadeias de caracteres, nós usamos o operador ||, como mostrado no terceiro exemplo.
- O último exemplo é um pouco bizarro (mas é o que o padrão SQL define): se duas cadeias de caracteres são separadas por uma ou mais linhas em branco, elas são consideradas como se estivessem concatenadas. Vai por mim, evite esse tipo de coisa e use o operador || quando precisar.
Citação tipo dólar (dollar quoting)
Um dos problemas que temos ao lidar com texto é que eles são delimitados por aspas simples, mas em varias situações você pode querer incluir uma aspa simples no seu texto. A forma tradicional de lidar com isso é duplicar a aspa simples. Vejamos o caso clássico da Joana d’Arc:
teste=# SELECT 'Joana d''Arc'; ?column? ------------- Joana d'Arc
O PostgreSQL possui uma alternativa para isso que não faz parte do padrão SQL mas que é bastante útil. Você pode ao invés de iniciar e terminar a sua cadeia de caracteres com uma aspa simples, você pode usar dois sinais de dólar, desta forma:
teste=# SELECT $$Joana d'Arc$$; ?column? ------------- Joana d'Arc
Na verdade você pode ainda utilizar um identificador qualquer entre os dois sinais de dólar (mas precisa ser o mesmo identificador no início e no final), se preferir:
teste=# SELECT $txt$Joana d'Arc$txt$; ?column? ------------- Joana d'Arc
Aqui, nós temos Joana d’Arc envolvidos por $txt$. De fato, isso ajuda muito em situações mais complexas. Quando você vai escrever uma função por exemplo, todo o código é considerado como texto. Para iniciar e terminar este texto, delimitamos ele com $function$ ou $BODY$.
Um detalhe curioso é que a maioria dos editores de texto que utilizam o realce de sintaxe (Syntax highlighting) se perdem quando utilizamos este tipo de notação. Aqui no texto eu deliguei o realce no segundo exemplo para ajudar um pouco, no primeiro, veja que ele considera o início da constante no lugar errado.
Escape no estilo C
O PostgreSQL foi todo escrito na linguagem C e como tal traz algumas práticas desta linguagem. Antigamente, qualquer cadeia de caractere poderia ser recheada de escapes no estilo C, utilizando as famosas barras invertidas ( \ ). Isso é muito útil para incluir caracteres não imprimíveis como uma tabulação ou uma quebra de linha. Antigamente o PostgreSQL aceitava isso nativamente. Existe uma tabela na documentação com todas as possibilidades, mas as mais comuns são:
- \n (quebra de linha)
- \t (tabulação)
- \r (equivalente ao “enter“)
- \\ (o caractere \)
- \’ (uma aspa simples)
A partir da versão 9.1 do PostgreSQL o parâmetro standard_conforming_strings passou a vir ligado por padrão. Isso significa que o comportamento histórico de aceitar escapes no estilo C dentro de uma cadeia de caracteres. Para contornar isso, o Postgres (e outros SGDBs também) criaram uma sintaxe alternativa para aceita-los. Basta preceder a aspa simples que abre a cadeia de caracteres por um E maiúsculo ou não:
teste=# SELECT E' foo \n bar'; ?column? ---------- foo + bar (1 row) teste=# SELECT E'Joana d\'Arc'; ?column? ------------- Joana d'Arc (1 row)
No primeiro exemplo, utilizamos o \n para para quebrar a linha. No segundo utilizamos para escapar a aspa simples. Veja que o escape no estilo C é mantido dessa forma mais não é padrão SQL. Não estimulamos o seu uso. Se você realmente precisa inserir caracteres não imprimíveis como uma tabulação ou uma quebra de linha, você pode fazer isso usando o padrão SQL com uma função desta forma:
teste=# SELECT ' foo ' || CHR(10) || ' bar'; ?column? ---------- foo + bar (1 row)
Caracteres unicode
Aqui as coisas começam a complicar um pouco mais. Você pode querer inserir caracteres que não estão na tabela ASCII padrão, mas caracteres em outros alfabetos. Se você utiliza UTF8 como codificação de caracteres (você deveria fazer isso sempre, sério), então você pode utilizar esta notação para inserir caracteres específicos que seu teclado ABNT não possui. Você deve preceder a aspa simples com um sinal de U&:
teste=# SELECT U&'\0441\043B\043E\043D'; ?column? ---------- слон (1 row)
Existe um operador que utiliza o caractere & no PostgreSQL. Por este motivo, quando quiser trabalhar com caracteres UTF8 utilize o U&’ sem espaços, quando quiser utilizar o operador & utilize sempre com espaços antes de depois dele, de forma evitar qualquer ambiguidade.
Cadeias de caracteres binárias
Existem 2 tipos de cadeias de caracteres binárias no PostgreSQL: BIT (com tamanho fixo, assim como em CHAR) e BIT VARYING. Como se pode imaginar, eles só aceitam os caracteres 0 e 1. Este tipo é muito utilizado em mapas de bits, uma técnica muito comum em programação em C. Para utilizar cadeias binárias, você pode também utilizar caracteres hexadecimais, onde cada caractere hexadecimal equivale exatamente a 4 caracteres binários. Para isso você utiliza o B como prefixo quando for utilizar números binários e o X quando for utilizar números hexadecimais:
teste=# SELECT B'1010', X'A'; ?column? | ?column? ----------+---------- 1010 | 1010 (1 row)
Coerção de tipos de dados
Todos os outros tipos de dados trabalham em geral com constantes entre aspas simples, em diferentes formatos. Se você estiver realizando uma operação de INSERT por exemplo, pode ser que o PostgreSQL consiga converter implicitamente para o tipo correto durante a operação. Mas em outras situações isso nem sempre acontece. Existem muitos detalhes dependendo de cada tipo de dado envolvido. Vamos deixar estes detalhes para outro artigo!
Existem 3 formas de definir com qual tipo de dado estamos trabalhando:
type ‘string’
‘string’::type
CAST ( ‘string’ AS type )
- O primeiro é estilo é o mais utilizado e deve ser preferido no dia-a-dia;
- O segundo estilo só existe no PostgreSQL e é mantido por razões históricas, portanto você deveria evitar o mesmo;
- O último utiliza a função CAST. Funciona bem e é padrão SQL, mas é um pouco mais verborrágico. Acredito que a primeira opção é mais enxuta.
Vejamos alguns exemplos utilizando os 3:
teste=# SELECT NUMERIC(4,2) '42'; numeric --------- 42.00 (1 row) teste=# SELECT '42'::NUMERIC(4,2); numeric --------- 42.00 (1 row) teste=# SELECT CAST('42' AS NUMERIC(4,2)); numeric --------- 42.00
Note que quando utilizamos o 42 no primeiro exemplo, ele foi considerado um INTEGER e não um NUMERIC. Outro detalhe é que aqui utilizamos sim um número entre aspas simples. Esta regra vai valer para praticamente qualquer tipo de dado. Mas claro, sempre existem exceções…
Operadores
operadores são funções que utilizam símbolos especiais e tem significados específicos dependendo do tipo de dado envolvidos junto aos operadores. Em geral estamos acostumados com operadores que utilizam um caractere só, como +, -, * e /. Mas o PostgreSQL possui uma gama enorme de operadores que podem utilizar um ou mais dos seguintes caracteres:
+ – * / < > = ~ ! @ # % ^ & | ` ?
- Observação: Existem algumas regras para evitar confusão como comentários como — e /*
Os operadores são uma parte muito importante do PostgreSQL e um dos seus grandes trunfos. Isso porque estes operadores são indexáveis. Então você pode utilizar um tipo de dados geométrico e fazer uma consulta onde na cláusula WHERE você utiliza o operador ?-| para saber se outra figura geométrica é perpendicular ao seu polígono. E utilizar um índice para acelerar esta consulta!
Caracteres especiais
Existe por fim uma lista de caracteres especiais utilizados em situações específicas:
- $ – O dólar é utilizado para numerar parâmetros de uma função de acordo com a ordem que aparece na chamada da função e na notação de cadeia de caracteres com o $$ como explicamos há pouco;
- () – Os parenteses são utilizados para agrupar parâmetros de uma função, agrupar expressões e para reforçar a precedência de operadores;
- [] – Os colchetes são utilizados em matrizes (arrays);
- , – As vírgulas servem para separar elementos sintáticos como variáveis, identificadores e constantes;
- ; – O ponto e vírgula fecha comandos SQL;
- : – Os dois pontos são utilizados em matrizes (arrays) para separar pedaços do mesmo. Também podem ser utilizados em substituição de variáveis como prefixo antes do nome da variável;
- * – O Asterisco pode substituir um conjunto de identificadores ou utilizado em funções de agregação;
- . – O ponto separa a parte inteira da decimal em números e também separa nome de esquemas de tabelas e colunas.
Próximos passos
Nos próximos artigos vamos brincar um pouco com vários tipos de dados e funções e ver como utilizar de maneira correta. Prepare-se!
Lançada a grade do PGConf Brasil 2018
17 de Março de 2018, 9:42 - sem comentários aindaEm novembro eu postei aqui e aqui sobre o PGConf Brasil 2018. Eu prometi para mim mesmo que não ficaria postando trocentas vezes sobre o evento. Mas é um momento muito especial e eu estou orgulhoso em divulgar uma grade realmente excepcional.
Sobre seleção das palestras
Foi uma maratona… recebemos um número recorde de propostas de palestras na nossa chamada de trabalhos: mais de 80! Algo que eu havia notado no PGBR2017 se confirmou logo de cara: o nível do pessoal subiu. Em 2007 quando começamos, o nível ainda era mais iniciante. Agora vemos mais palestras com nível elevado e um público mais experiente também. Em 2018 continuaremos tendo boas palestras de nível básico, mas a maioria tem nível intermediário.
Tivemos 5 pessoas na banca avaliadora. Apenas uma pessoa da Timbira, que não fui eu. E mais, a decisão da banca avaliadora foi soberana. Parece que não, mas isso faz toda a diferença quando pensamos na qualidade do evento que estamos organizando. A ideia é que mesmo o evento sendo organizado pela Timbira, nós seguimos as recomendações da comunidade internacional e fomos reconhecidos como “evento da comunidade“. Isso significa que a Timbira (como sempre) não vai ganhar um tostão com a organização do evento e não teremos um evento comercial para vender a Timbira. Nosso compromisso é com os profissionais que utilizam (ou estão pensando em utilizar) o PostgreSQL no Brasil. Simples assim.
Sobre as salas
Tivemos que abrir mais uma sala para acomodar as palestras. Decidimos trazer o maior número de palestras relevantes possível, mesmo sem saber quantos inscritos teremos. A foto deste post foi tirada em 2011 no mesmo hotel em que o evento vai acontecer e deu nisso: salas lotadas. Achamos que em 2018 não vai ser muito diferente e reservamos TODAS as salas do hotel. Então vai ficar assim:
- Sala de exposições “Josh Berkus” para o credenciamento, patrocinadores, coffee breack e happy hour;
- Sala “Marc G. Fournier” com capacidade para 230 lugares;
- Sala “Thomas G. Lockhart” com capacidade para 120 lugares;
- Sala “Vadim B. Mikheev” com capacidade para 120 lugares;
- Sala “Jan Wieck” para os Hacker Talks, Hackathon e Couch Clinic com capacidade para 20 lugares;
- Sala VIP para palestrantes com capacidade de 20 lugares.
O nome das salas é uma homenagem aos nossos “Hackers Emeritus“: desenvolvedores que tiveram contribuições excepcionais no PostgreSQL e que não estão mais ativos.
Sobre os palestrantes
Temos ao todo 44 palestrantes confirmados. Temas bastante variados, mas com muito mais foco em DevOps, nuvem e desenvolvimento.
- 36 palestrantes nacionais
- SP
- Arlindo do Carmo e Silva Neto
- Carlos Smaniotto
- Danielle Monteiro
- Everaldo Canuto
- Fabiano Menegidio
- Fábio Telles Rodriguez
- Felipe Oliveira
- Fernando Ike
- Juliano Atanazio
- Leonardo Ferreira Leite
- Matheus Oliveira
- Renan Ranelli
- Waldir Pimentel
- Yago Nobre dos Santos
- SC
- Dickson S. Guedes
- Erivelton Vichroski
- Gustavo Sperandio
- Lucas Eduardo Viecelli
- Marcelo Kruger
- Brasília
- Davy Alvarenga Machado
- Gerdan dos Santos
- Glauco Torres
- Marcone Viana Peres
- Raul Diego de Queiroz Oliveira
- RS
- Álvaro Melo
- Fabrízio de Royes Mello
- Rodrigo Crespi
- Sebastian Webber
- TO
- Euler Taveira
- Raphael Araújo e Silva
- PR
- Rafael Thofehrn Castro
- William Ivanski
- RJ
- Lucio Chiessi
- RO
- Luis Fernando Bueno
- CE
- Narcelio de Sá Pereira Filho
- AM
- Roberto Mello
- SP
- 8 Palestrantes internacionais
- EUA
- Ivan Novick
- Joe Conway
- Stephen Frost
- Argentina
- Martín Marqués
- Chile
- Alvaro Herrera
- Cuba
- Gilberto Castillo
- Equador
- Jaime Casanova
- Itália
- Rubens Souza
- EUA
Agora, se você quer ver a grade e conhecer todas as palestras, só tem um jeito, vai lá no site do evento!
Muito mais que palestras
Teremos palestras de 30, 60 e 120 minutos. Mas teremos algumas coisas que nem todos estão acostumados a ver:
- Hacker Talks: Palestras com foco em apoiar pessoas que queiram desenvolver novas funcionalidades no PostgreSQL;
- Hackathon: Pessoas desenvolvendo novas funcionalidades relacionadas ao PostgreSQL ao vivo;
- Couch Clinic: Nossos palestrantes estarão dando consultoria de graça para quem quiser, bastará se inscrever;
- Lightning Talks: Uma sessão com 12 palestras de 5 minutos. Qualquer um pode palestrar e se inscrever durante o evento, só não pode estourar os 5 minutos;
- Happy Hour: Preparamos na noite do primeiro dia do evento um Happy Hour com todos participantes do evento. Uma ótima oportunidade para melhorar o seu networking.
E agora???
Bom, agora não tem muito jeito, só fazendo a sua inscrição mesmo. Lembrando que o valor atual das inscrições só vão até junho. As opções de compra antecipada de camisetas e canecas também acabam em junho. Então vai lá e faça sua inscrição agora!
Extreme Go Horse DBA
24 de Fevereiro de 2018, 22:38 - sem comentários aindaTodos já conhecem o DBA Chuck Norris, aquele mega phoda que tudo pode no CPD. Aquele que está acima de Deus. Mas os tempos mudaram, estamos na era DevOps e migrando tudo para as nuvens. Então a moda agora é DBA XGH. Veja aqui uma compilação das melhores técnicas XGH para PostgrSQL:
- Se você é um ninja do Linux, SEMPRE compile o PostgreSQL e explore todas as opções possíveis de compilação. Se possível utilize também o –whithout-readline e –without-zlib, assim você consegue tirar até a última gota de desempenho do seu banco de dados;
- Para não ter problemas na hora de compilar, instale todos os pacotes da sua distribuição Linux, você garante uma instalação limpa, sem problemas com dependências e pronta para rodar qualquer parada;
- Compre o maior disco possí
- Na hora de particionar os discos, adote a filosofia KISS (Keep It Simple, Stupid): Deixe o particionador automático ocupar o disco inteiro com apenas uma partição. Você elimina assim as complexidades desnecessárias, aumenta o desempenho e não desperdiça espaço em disco;
- Se você tiver bases grandes com alguns TB, aí é melhor você comprar um único disco grande como 8TB e dividir o disco em várias partições menores de 100GB colocando um tablespace em cada um, distribuindo assim o I/O no disco;
- Se você tem vários discos e quer obter a melhor performance, utilize sempre um único RAID 0 e continue dividindo tudo em partições de 100GB;
- Ao criar seu banco de dados sempre utilize como codificação de caractere padrão o SQL_ASCII. Você elimina a necessidade de conversões, ganha espaço em disco e desempenho, além de trabalhar com um padrão que qualquer linguagem de programação entende;
- Use e abuse da flexibilidade do VARCHAR. Com ele você tem uma compatibilidade direta com a web que entende apenas texto. Com o VARCHAR você consegue armazenar texto, RG, CPF, CEP, telefones, Json, XML, o que você quiser.
- Se precisar de campos flexíveis, você também pode utilizar o VARCHAR marcando as posições para distribuir vários campos de tamanho fixo dentro de uma cadeia de caracteres. Essa é uma técnica campeã utilizada já no tempo do Cobol e funciona até hoje;
- Evite erros na sua aplicação removendo qualquer tipo de restrição do tipo PRIMARY KEY, FOREIGN KEY, UNIQUE e NOT NULL. Suas consultas vão rodar mais rápido e não vão mais dar erro na execução;
- DevOps exige agilidade, utilize o esquema padrão e o usuário padrão para tudo. Assim você não tem que armazenar varias senhas ou se preocupar com vários esquemas.
- Você ainda pode criar um acesso universal colocando a seguinte linha no seu pg_hba.conf: “host all all 0.0.0.0/0 trust”;
- Uma ideia para facilitar o suporte remoto é colocar um IP público no servidor de banco de dados. Você vai conseguir acessar seu servidor sem rodeios, de forma muito mais ágil;
- Não mexa no postgresql.conf, deixe os valores padrão que são otimizados para funcionar no seu hardware e na sua aplicação já na instalação;
- Em nenhuma hipótese ative a gravação dos logs do banco de dados, isso vai ocupar mais espaço em disco e gerar mais I/O deixando seu banco de dados mais lento;
- A melhor ferramenta de backup é sempre o PGAdmin. Em poucos clicks você resolve tudo, ponto final;
- O jeito mais prático de matar uma sessão no banco de dados é com o comando kill -9, não falha nunca;
- O melhor jeito de não ter dor de cabeça com os desenvolvedores é criar um super usuário próprio para eles na produção. Esta metodologia ágil é conhecida como OLD: On Line Development;
- Se você tem uma tabela crítica para o seu sistema, crie um índice para cada campo da sua tabela e garanta que seu sistema sempre fará consultas indexadas;
- Se você tem muitas tabelas, você deve criar uma view juntando a maioria das tabelas mais utilizadas e a partir dela criar todas as outras consultas do seu sistema;
- A melhor forma de evitar problemas com o autovacuum é desligar ele para todas as tabelas. Assim você garante que não vai ter processos pesados de vacuum rodando no seu horário de pico;
- Se você tem uma aplicação que é “database centric” e trabalha com um único banco monolítico, migre para a nuvem o quanto antes. Quanto maior o seu banco de dados, maior será a economia que você terá migrando diretamente para a nuvem. Sucesso garantido;
- A melhor versão do PostgreSQL que já fizeram é a 8.2. Tudo que veio depois é besteira. Está funcionando, não é mesmo? Não mexa!
- Repita comigo: SQL simples roda rápido, SQL com subconsultas é lento. Se você tem que atualizar 10 milhões de registros, a melhor forma é fazer 10 milhões de UPDATEs simples no banco de dados, claro;
- Se você tem uma consulta complexa para fazer, crie uma função e divida a operação em diversas etapas e loops, simplificando a lógica e a execução da mesma;
- A documentação do PostgreSQL é longa, prolixa e complexa. Já ouviu falar no Google?
Você utiliza XGH na sua empresa também? Ajude os demais colegas e conte nos comentários as técnicas de alto rendimento que você desenvolveu e recomenda para todos!
OBS: Eu sei…. o Go Horse Process não chega a ser algo novo. Mas sabe como é DBA: tá sempre atrasado no hype.