Bancos de dados, tabelas, normalização e um plano de backup sólido nos permitem armazenar e manter dados.
Essas melhores práticas combinadas, por sua vez, nos permitem interagir com esses dados. No mundo atual orientado por dados, os dados são valiosos. Além de valiosos, os dados muitas vezes são críticos para as soluções do usuário final fornecidas por produtos e serviços. Extrair insights, responder perguntas e métricas significativas de dados por meio de consulta e manipulação de dados é um componente integral do SQL em geral.
O PostgreSQL não é diferente.
Esse ponto crucial é fundamental para o sucesso em qualquer aspecto orientado a dados.
Abaixo, apresento uma combinação de 8 consultas diferentes ou tipos de consultas que achei interessantes e envolventes para explorar, estudar, aprender ou manipular conjuntos de dados.
Eles não estão listados em nenhuma ordem de importância.
A maioria provavelmente serão velhos amigos familiares. Talvez alguns se tornem novos conhecidos.
As tabelas de amostra e os dados usados não são tão importantes quanto a construção real das próprias consultas e o que cada consulta retorna, oferece ou fornece. Muitos deles são simulados e derivados para fins de demonstração e não devem ser tomados literalmente em seus valores.
1. Junção à esquerda, lembre-se de quaisquer nulos à direita...
Suponha que neste exemplo, temos uma venda em execução de dois meses e estamos obtendo um total de ambos combinados.
No entanto, por algum motivo, o segundo mês não puxou seu peso e queremos segmentar em quais dias o mês um pegou a folga.
Essas vendas são representadas como tabelas de pagamento e fake_month para esta demonstração.
Anotar:
- Só verificaremos totais superiores a 2.000.
- Vamos limitar a saída a apenas 10 linhas.
Para começar, temos esta expressão de tabela comum (CTE) 'gerando ' a tabela fake_month para nós e a consulta a seguir.
dvdrental=> WITH fake_month AS(
SELECT setup::date
FROM generate_series('2007-02-01', '2007-02-28', INTERVAL '1 day') AS setup
)
SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
LIMIT 10;
legit | sum | fake
-------+---------+------
1 | 2808.24 | 1
2 | 2550.05 | 2
6 | 2077.14 | 6
8 | 2227.84 | 8
9 | 2067.86 | 9
17 | 3630.33 | 17
18 | 3977.74 | 18
19 | 3908.59 | 19
20 | 3888.98 | 20
21 | 3786.14 | 21
(10 rows)
Parece que os dois meses contribuíram para isso. Então isso está resolvido?
Antes de considerarmos isso resolvido, vamos visitar a cláusula ORDER BY.
Claro, você pode ENCOMENDAR POR ASC ou DESC.
No entanto, você também pode ORDER BY NULLS primeiro ou por último e isso muda um pouco as coisas.
Vamos reescrever esta consulta e usar ORDER BY NULLS primeiro na coluna legítima.
Por brevidade, removerei o CTE da saída, apenas saiba que ele ainda está lá e sendo usado.
SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
ORDER BY legit NULLS first
LIMIT 10;
legit | sum | fake
-------+---------+------
1 | 2808.24 | 1
2 | 2550.05 | 2
6 | 2077.14 | 6
8 | 2227.84 | 8
9 | 2067.86 | 9
17 | 3630.33 | 17
18 | 3977.74 | 18
19 | 3908.59 | 19
20 | 3888.98 | 20
21 | 3786.14 | 21
(10 rows)
Não há diferença em tudo.
E se ORDER BY NULLS primeiro na coluna falsa? O da direita lado do JOIN?
Vamos ver.
SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
ORDER BY fake NULLS first
LIMIT 10;
legit | sum | fake
-------+---------+------
29 | 2717.60 |
30 | 5723.89 |
1 | 2808.24 | 1
2 | 2550.05 | 2
6 | 2077.14 | 6
8 | 2227.84 | 8
9 | 2067.86 | 9
17 | 3630.33 | 17
18 | 3977.74 | 18
19 | 3908.59 | 19
(10 rows)
Agora estamos chegando a algum lugar. Podemos ver nos dias 29 e 30, a coluna falsa foi ordenada a partir do topo do conjunto de resultados.
Devido a ORDER BY falsos nulos primeiro.
Isso resolve nossa pergunta, em quais dias a 'venda 2' diminuiu.
Você está se perguntando...
"Podemos filtrar com WHERE fake IS NULL? "
Assim:
SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
WHERE date_part('day', fk.setup) IS NULL
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
LIMIT 10;
legit | sum | fake
-------+---------+------
29 | 2717.60 |
30 | 5723.89 |
(2 rows)
Sim isso funciona. Então, por que não usar essa consulta? Por que isso importa?
Acho que usar LEFT JOIN e ORDER BY NULLS primeiro para a tabela do lado direito do JOIN é uma ótima maneira de explorar tabelas e conjuntos de dados desconhecidos.
Ao confirmar quais dados, se houver, estão 'ausentes ' nesse lado da condição de junção primeiro; aumenta a clareza e a percepção, permitindo que você filtre o conjunto de resultados com a cláusula WHERE
É claro que a familiaridade com as tabelas e conjuntos de dados pode eliminar a necessidade do LEFT JOIN apresentado aqui.
É uma consulta digna para qualquer um que utilize o PostgreSQL para pelo menos tentar, durante a exploração.
2. Concatenação de String
A concatenação, a junção ou acréscimo de duas strings, fornece uma opção de apresentação para conjuntos de resultados. Muitas 'coisas ' pode ser concatenado.
No entanto, conforme observado na documentação, o operador de concatenação de strings ('||') aceita entrada não string, desde que seja uma string.
Vejamos alguns exemplos com as consultas abaixo:
postgres=> SELECT 2||' times'||' 2 equals: '|| 2*2;
?column?
---------------------
2 times 2 equals: 4
(1 row)
Podemos ver que números e strings podem ser concatenados como mencionado acima.
O '||' operador é apenas um dos disponíveis no PostgreSQL.
A função concat() aceita vários argumentos, concatenando-os todos no retorno.
Aqui está um exemplo dessa função em ação:
postgres=> SELECT concat('Josh ','Otwell') AS first_name;
first_name
-------------
Josh Otwell
(1 row)
Podemos passar mais de dois argumentos, se desejado:
postgres=> SELECT concat('Josh',' ','Otwell') AS first_name;
first_name
-------------
Josh Otwell
(1 row)
Vamos notar algo bem rápido com estes próximos exemplos:
postgres=> SELECT CONCAT('Josh',NULL,'Otwell') AS first_name;
first_name
------------
JoshOtwell
(1 row)
postgres=> SELECT 'Josh '||NULL||'Otwell' AS first_name;
first_name
------------
(1 row)
postgres=> SELECT NULL||'Josh '||'Otwell' AS first_name;
first_name
------------
(1 row)
postgres=> SELECT CONCAT(NULL,'Josh','Otwell') AS first_name;
first_name
------------
JoshOtwell
(1 row)
Observe que a função concat() ignora NULL, não importa onde seja colocado na lista de parâmetros, enquanto o operador de concatenação de strings não.
NULL é retornado se estiver presente em qualquer lugar na string a ser concatenada.
Apenas esteja ciente disso.
Em vez de incluir manualmente dentro da string a ser concatenada, o PostgreSQL também inclui uma função concat_ws() que aceita um separador de string como primeiro parâmetro.
Vamos visitá-lo com estas perguntas:
postgres=> SELECT concat_ws('-',333,454,1919) AS cell_num;
cell_num
--------------
333-454-1919
(1 row)
postgres=> SELECT concat_ws(' ','Josh','Otwell') AS first_name;
first_name
-------------
Josh Otwell
(1 row)
concat_ws() aceita números ou strings como argumentos e, conforme indicado acima, usa o primeiro argumento como separador.
Como concat_ws() trata NULL?
postgres=> SELECT concat_ws('-',333,NULL,1919) AS cell_num;
cell_num
----------
333-1919
(1 row)
postgres=> SELECT concat_ws(NULL,333,454,1919) AS cell_num;
cell_num
----------
(1 row)
NULL é ignorado a menos que seja o argumento separador dado a concat_ws().
Em seguida, todos os argumentos são ignorados e NULL é retornado.
Concatenação é legal...
Agora que temos uma ideia de como a concatenação funciona, vejamos alguns exemplos.
Voltar para o banco de dados de aluguel de DVD simulado
Suponha que precisamos compilar uma lista de nomes e sobrenomes de clientes, juntamente com seus endereços de e-mail, para enviar um memorando para atualizar sua conta.
Vou limitar a saída a apenas 10 linhas por questões de brevidade, mas ainda demonstrando o || operador.
dvdrental=> SELECT first_name||' '||last_name||'''s email address is: '||email AS name_and_email
FROM customer
LIMIT 10;
name_and_email
--------------------------------------------------------------------------
Jared Ely's email address is: [email protected]
Mary Smith's email address is: [email protected]
Patricia Johnson's email address is: [email protected]
Linda Williams's email address is: [email protected]
Barbara Jones's email address is: [email protected]
Elizabeth Brown's email address is: [email protected]
Jennifer Davis's email address is: [email protected]
Maria Miller's email address is: [email protected]
Susan Wilson's email address is: [email protected]
Margaret Moore's email address is: [email protected]
(10 rows)
Observe que tivemos que escapar das aspas simples usadas com apóstrofos, usando aspas simples adicionais para mostrar a posse do endereço de e-mail de cada cliente.
Por que você deveria saber?
Pode haver momentos em que a concatenação de dados apresenta uma melhor percepção e compreensão do conjunto de dados com o qual você está trabalhando. Juntamente com as opções de relatório, a concatenação de conjuntos de dados compartilhados com outros poderia torná-los (os dados) mais legíveis e digeríveis.
3. Fornecendo a lista de valores IN com subconsultas
Uma Subconsulta tem vários usos poderosos. Desses, fornecer uma lista IN de valores para verificar a associação é comum.
Aqui está um uso rápido.
Suponha que temos tabelas de clientes e pagamentos em uma loja de aluguel de DVD simulada e queremos recompensar nossos cinco clientes com maiores gastos que alugaram filmes durante os dias de 10 a 13 de abril.
Imagine que é um período alvo especial. Portanto, se o cliente gastou mais de US$ 30, queremos reconhecê-lo.
Lembre-se de que existem outras opções disponíveis para resolver esse tipo de questão (ou seja, junções, captura de resultados de várias seleções, etc...), mas as subconsultas também podem lidar com isso.
Vamos começar com todo o shebang aqui. Essa consulta completa retorna tudo o que queremos para essa questão específica.
dvdrental=> SELECT first_name, last_name, email
FROM customer
WHERE customer_id IN (
SELECT customer_id FROM (
SELECT DISTINCT customer_id, SUM(amount)
FROM payment
WHERE extract(month from payment_date) = 4
AND extract(day from payment_date) BETWEEN 10 AND 13
GROUP BY customer_id
HAVING SUM(amount) > 30
ORDER BY SUM(amount) DESC
LIMIT 5) AS top_five);
Este exemplo, na verdade, contém subconsultas aninhadas, uma das quais é uma Tabela Derivada.
Vamos começar analisando a subconsulta mais interna, essa Tabela Derivada.
Essa subconsulta é uma instrução SELECT independente própria, retornando um customer_id e um SUM() na coluna de valor.
Somente os clientes que atendem aos critérios verificados pelas cláusulas WHERE e HAVING fazem o corte, sendo ainda mais diluídos com LIMIT 5;
Por que a próxima subconsulta que você pergunta?
Não podemos apenas usar a parte WHERE customer_id IN do SELECT mais externo aqui?
Vamos ver com uma abordagem prática.
Vou remover o AS top_five da subconsulta e tentar a consulta mais externa com ele agora:
dvdrental=> SELECT first_name, last_name, email
FROM customer
WHERE customer_id IN
(SELECT DISTINCT customer_id, SUM(amount)
FROM payment
WHERE extract(month from payment_date) = 4
AND extract(day from payment_date) BETWEEN 10 AND 13
GROUP BY customer_id
HAVING SUM(amount) > 30
ORDER BY SUM(amount) DESC
LIMIT 5);
ERROR: subquery has too many columns
LINE 3: WHERE customer_id IN (
Aqui, a associação IN está sendo testada apenas com a coluna customer_id, mas a Tabela Derivada retorna duas colunas e o PostgreSQL nos informa.
Uma solução é usar outra subconsulta. Selecionar apenas o customer_id do conjunto de resultados da Tabela Derivada cria a próxima subconsulta aninhada interna.
Agora, o predicado IN contém várias linhas de valores de uma coluna para verificar a associação em relação à cláusula WHERE para customer_id para fazer o conjunto de resultados finais.
Por que isso importa?
A utilização de subconsultas dessa maneira é poderosa devido ao número de valores que podem ser testados com o predicado IN().
Imagina se fosse 100? Ou mais?
'Codificação ' todos eles na lista IN() podem se tornar problemáticos e propensos a erros à medida que o volume de valores aumenta.
4. gerar_series()
Esta função de retorno de conjunto é útil e super divertida de usar e explorar. Eu usei generate_series() nos exemplos acima, mas merece uma conversa própria. Focando mais na função e capacidades.
Acho generate_series() útil para consultas comparativas em que alguns ou todos os dados estão ausentes.
Ou apenas dados parciais estão disponíveis no momento em que estou explorando. Um uso útil é preencher tabelas com 'dados fictícios '.
Para começar, vamos criar uma tabela simples:
trial=> CREATE TABLE tbl_1(
trial(> tb_id SERIAL PRIMARY KEY,
trial(> some_day DATE,
trial(> an_amt NUMERIC(4,2));
CREATE TABLE
Em seguida, use generate_series() como VALUES para nossa instrução INSERT:
trial=> INSERT INTO tbl_1(some_day, an_amt)
VALUES(
generate_series('2018-04-01','2018-04-15',INTERVAL '1 day'),
generate_series(2.43, 34.20, 1.03));
INSERT 0 31
Em seguida, crie uma segunda tabela
trial=> CREATE TABLE tbl_2(
tb2_id SERIAL PRIMARY KEY,
some_day2 DATE,
an_amt2 NUMERIC(4,2));
CREATE TABLE
Além disso, preencha-o usando generate_series() na instrução INSERT:
trial=> INSERT INTO tbl_2(some_day2, an_amt2)
VALUES(
generate_series('2018-05-16','2018-05-31',INTERVAL '1 day'),
generate_series(15.43, 31., 1.03));
INSERT 0 16
Por que isso importa?
Para reiterar, generate_series() é muito útil para criar dados simulados ou de prática.
Descobri que imitar intervalos de meses ou dias para comparação é excepcional com generate_series(). Consulte a seção 1 e o CTE lá, demonstra esse uso.
Criar um conjunto de dados completos com generate_series() e usar para comparar com os dados armazenados para determinar se algum dado está faltando também tem um grande valor.
5. Consultas com a função de agregação COUNT() .
Essa função agregada simples, mas eficaz, deve estar no arsenal de qualquer pessoa. Especialmente ao explorar tabelas ou conjuntos de dados pela primeira vez.
Quer dizer, você realmente quer 'SELECIONAR tudo ' de uma tabela com 1 milhão de linhas?
Determine com COUNT(*) quantos registros estão presentes antes de carregar.
Vamos descobrir quantas linhas a tabela de filmes tem nesta tabela de aluguel de DVD simulada:
dvdrental=> SELECT COUNT(*)
dvdrental-> FROM film;
count
-------
1000
(1 row)
Embora não seja tão extenso quanto mais de 1 milhão de linhas, tenho certeza que você vê a utilidade.
Para retornar o número de linhas específicas, COUNT(*) pode ser filtrado com uma cláusula WHERE.
Vamos ver quantos filmes têm uma classificação 'G':
dvdrental=> SELECT COUNT(*)
dvdrental-> FROM film
dvdrental-> WHERE rating = 'G';
count
-------
178
(1 row)
Há outra forma de COUNT() para estar ciente. COUNT(some_expression) .
As diferenças entre eles são:
- COUNT(*) retorna o total de todas as linhas de entrada (incluindo NULLS e duplicatas).
- COUNT(alguma_expressão ) conta o número de linhas de entrada não NULL.
Quando usado em conjunto com a palavra-chave DISTINCT, COUNT() eliminará entradas duplicadas e retornará apenas valores exclusivos.
Vamos ver isso em ação usando COUNT() com DISTINCT para determinar quantos tipos exclusivos de avaliações estão presentes:
dvdrental=> SELECT COUNT(DISTINCT rating) FROM film;
count
-------
5
(1 row)
Com esta consulta, sabemos que existem 5 tipos de classificações.
Por que isso importa?
Dependendo do que está sendo rastreado ou direcionado, saber quanto de algo existe pode ser importante. Portanto, utilizando COUNT(*) ou COUNT(some_expression ) auxilia nesses tipos de desafios.
Apenas lembre-se COUNT(*) não ignora NULL. Todas as linhas, incluindo valores duplicados e NULL, são retornadas como parte do número final.
6. UPDATE várias linhas com uma expressão CASE.
Suponha que temos esta tabela:
trial=> SELECT * FROM reward_members;
rm_id | expense_amt | member_status
-------+-------------+---------------
1 | 1245.33 | gold
2 | 1300.49 | gold
3 | 900.20 | bronze
4 | 2534.44 | platinum
5 | 600.19 | bronze
6 | 1001.55 | silver
7 | 1097.99 | silver
8 | 3033.33 | platinum
(8 rows)
Precisamos renomear a coluna member_status e adicionar 'grupo ' ao final do nome atual presente para cada registro.
Para começar, várias instruções UPDATE individuais farão isso sem problemas.
Mas, também pode uma única expressão CASE.
trial=> UPDATE reward_members
SET member_status = (
CASE member_status
WHEN 'gold' THEN 'gold_group'
WHEN 'bronze' THEN 'bronze_group'
WHEN 'platinum' THEN 'platinum_group'
WHEN 'silver' THEN 'silver_group'
END
)
WHERE member_status IN ('gold', 'bronze','platinum', 'silver');
UPDATE 8
Vamos consultar a tabela novamente para ver as alterações:
trial=> SELECT * FROM reward_members;
rm_id | expense_amt | member_status
-------+-------------+----------------
1 | 1245.33 | gold_group
2 | 1300.49 | gold_group
3 | 900.20 | bronze_group
4 | 2534.44 | platinum_group
5 | 600.19 | bronze_group
6 | 1001.55 | silver_group
7 | 1097.99 | silver_group
8 | 3033.33 | platinum_group
(8 rows)
Todas as atualizações foram bem sucedidas.
Por que isso importa?
Você pode imaginar quantas viagens de ida e volta isso levaria ao servidor se várias instruções UPDATE individuais tivessem sido executadas. Na verdade, apenas 4 para este exemplo. Mas ainda assim, o potencial para muitos está sempre lá.
No entanto, usando uma expressão UPDATE com CASE, estamos enviando apenas uma consulta.
7. COPIAR e \copiar
O PostgreSQL fornece COPY, um comando para exportar dados entre arquivos e tabelas.
Certifique-se e visite o link fornecido para ver o grande número de opções disponíveis com COPY.
Uma nota importante sobre COPY. O privilégio de função SUPERUSER é necessário para executar este comando.
O meta-comando do psql \copy é uma alternativa para os usuários que não consideram este atributo de função. Visitaremos esse comando em breve.
Primeiro, vamos executar um comando COPY para exportar determinadas colunas para um arquivo CSV na máquina local.
Suponha que temos este resultado de consulta para exportação:
trial=# SELECT expense_amt, member_status
trial-# FROM reward_members
trial-# WHERE member_status = 'gold_group';
expense_amt | member_status
-------------+---------------
1245.33 | gold_group
1300.49 | gold_group
(2 rows)
Com COPY, podemos usar essa instrução SELECT para concluir essa exportação.
trial=# COPY (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'gold_group')
TO '/home/linux_user_here/awards_to_honor.csv'
DELIMITER ','
CSV HEADER;
COPY 2
*Observação:De acordo com a documentação, a consulta deve estar entre parênteses.
Vamos agora verificar o conteúdo desse arquivo:
$ cat awards_to_honor.csv
expense_amt,member_status
1245.33,gold_group
1300.49,gold_group
Podemos ver que a primeira linha contém o HEADER (que são os nomes das colunas) e ambas as linhas têm os dados de despesa_amt e member_status para ambas as colunas retornadas do filtro da cláusula WHERE.
Outra advertência importante que descobri ao executar o comando COPY acima.
O usuário deve ter privilégios para gravar no arquivo no nível do SO.
No meu caso, corrigido com:
$ sudo chown postgres awards_to_honor.csv
Você pode evitar esse problema gravando em um arquivo de sistema ao qual o usuário atual tem acesso, como /tmp (mostrado abaixo).
trial=# COPY (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'gold_group')
TO '/tmp/awards_to_honor.csv'
DELIMITER ','
CSV HEADER;
COPY 2
No entanto, uma das minhas funções de teste sem o atributo SUPERUSER teve problemas ao gravar no arquivo /tmp.
Veja abaixo a confirmação:
trial=# SET role log_user; -- changing from postgres user to log_user
SET
Agora tentando o mesmo comando COPY, gravando na pasta /tmp
trial=> COPY (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'gold_group')
TO '/tmp/awards_to_honor2.csv'
DELIMITER ','
CSV HEADER;
ERROR: must be superuser to COPY to or from a file
HINT: Anyone can COPY to stdout or from stdin. psql's \copy command also works for anyone.
Talvez uma medida melhor, como sugerido na DICA:, para funções sem o atributo SUPERUSER, seja o meta-comando psql \copy.
Vamos executar um tipo semelhante de comando com \copy usando o mesmo papel, sem a necessidade do atributo SUPERUSER.
trial=> \copy (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'silver_group')
TO '/home/linux_user_here/more_awards.csv'
DELIMITER ','
CSV HEADER;
COPY 2
Não há problemas.
E o conteúdo dos arquivos,
$ cat more_awards.csv
expense_amt,member_status
1001.55,silver_group
1097.99,silver_group
Também funciona para a pasta /tmp:
trial=> \copy (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'silver_group')
TO '/tmp/more_awards.csv'
DELIMITER ','
CSV HEADER;
COPY 2
Mesmo conteúdo presente no arquivo escrito também:
trial=> \! cat /tmp/more_awards.csv
expense_amt,member_status
1001.55,silver_group
1097.99,silver_group
Por que isso importa?
A importação de dados para o PostgreSQL por meio de arquivos é um método infalível de upload em massa. Embora nem todos sejam abordados nesta postagem do blog, COPY e \copy oferecem várias opções para trabalhar com diferentes formatos e extensões de arquivo.
Da mesma forma, exportar dados de tabelas ou colunas específicas também é facilmente manipulado com esses dois comandos.
8. meta-comando \help do psql
Você está em uma sessão de linha de comando do psql. Curioso sobre a sintaxe do comando CREATE INDEX?
Não há necessidade e indo para um navegador ou outro documento.
Tente isso em vez disso:
trial=> \help CREATE INDEX
Command: CREATE INDEX
Description: define a new index
Syntax:
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON table_name [ USING method ]
( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
[ WITH ( storage_parameter = value [, ... ] ) ]
[ TABLESPACE tablespace_name ]
[ WHERE predicate ]
Para saber qual texto de ajuda está disponível, você pode executar \help sozinho e obter uma lista de opções disponíveis.
Não vou listá-los todos aqui, apenas sei que essa opção está disponível.
Por que isso importa?
O fato deste meta-comando ser super fácil de usar, poderoso e conveniente são profissionais suficientes para mencioná-lo aqui. Isso me economizou muito tempo pesquisando em outras documentações. E claro, sendo um novato, eu uso com bastante frequência!
Conclusão
Isto não é uma lista exaustiva. Nem o 'ser tudo termina tudo ' de consultas e manipulação de dados.
Apenas minha opinião sobre aqueles que despertam meu interesse e falam comigo à medida que continuo aprendendo e crescendo em uma função de desenvolvedor SQL. Espero que por meio desta postagem no blog, você encontre casos de uso para as consultas e comandos acima, implementando aqueles onde achar melhor.