Tarefas e soluções para o lutador PostgreSQL


Saudações a todos os amantes de SQL!

Na Internet, raramente vi artigos que cobrissem diferentes pontos de trabalho e sutilezas associados ao processamento de dados no SQL .
Gosto quando você pode aprender muitas coisas de um artigo de uma só vez, mesmo em termos gerais.
Por isso, decidi escrever meu artigo contendo várias tarefas e respostas com explicações para eles.
Adequado para quem domina bem todas as habilidades básicas e deseja se desenvolver ainda mais.

As respostas fornecidas são adequadas para o PostgreSQL (a maioria das tarefas será adequada para outros DBMSs , mas os resultados e soluções podem ser diferentes. É até interessante onde as diferenças surgem)

Tente responder a si mesmo antes de abrir o spoiler.

Vamos lá!


Vou tentar marcar com um asterisco algo puramente para o PostgreSQL * (não existem muitos momentos assim)

1. Um pouco sobre operações numéricas


1.1 Essas solicitações serão atendidas? Quais resultados eles retornarão?

-- )     SELECT 3/2; -- ) SELECT min('- '::TEXT), avg('- '::TEXT); -- )*      FALSE,     ? SELECT 7.2 = (3.8::FLOAT + 3.4) -- ) SELECT (20/25)*25.0; 


Respostas para 1.1
A) Resposta: 1
Somente a parte inteira será mostrada, porque a operação usa números inteiros. Isso geralmente é encontrado em outros idiomas.

B) Resposta: o pedido não será executado .

avg dará um erro desde aceita apenas números e intervalos de tempo *

No entanto, a função min / max pode ser executada em dados de texto (de acordo com a classificação alfabética no banco de dados).
Às vezes, isso pode ser útil quando você precisa pelo menos olhar para uma coluna que não está listada em GROUP BY
Ou quando você precisar aplicar a classificação alfabética aos números, nos quais '10' <'2'

B) Resposta: FALSO

Pode parecer estranho, mas isso é aceitável , porque este é um recurso de um computador que representa alguns números de ponto flutuante; um número pode assumir a forma 7.1 (9)
Lembro-me de como lidei com um pedido por um longo tempo sem saber.

D) Resposta: 0 . o problema é que a expressão entre parênteses será = 0

SELECT (20 / 25.0) * 25 funcionaria mais corretamente


1.2 Dada a tabela " table_2 " (com uma única coluna " value " (INTEGER)) composta pelas 5 linhas a seguir:
valor
5
5
Nulo
5
5

Qual resultado retornará a consulta:
 SELECT (avg(value)*count(*)) - sum(value) FROM table_2; 

Opções de resposta
  • -4
  • 0 0
  • Nulo
  • 5
  • Isso causará um erro porque não especificado GROUP BY
  • Nenhum dos listados


Resposta 1.2
resposta: 5

Funções agregadas aplicadas a uma coluna específica ignoram NULL , no entanto count (*) contará todas as linhas
5 * 5-20


2. Questões gerais


2.1 Em que casos uma consulta pode retornar nem todo o conteúdo de uma tabela? ( parent_id INTEGER, a tabela é preenchida com vários dados)

  SELECT * FROM any_table WHERE parent_id = parent_id; 

Como o pedido abaixo se comportará? Quais dados serão gerados? * PostgreSQL

  SELECT * FROM any_table WHERE parent_id IS NOT DISTINCT FROM parent_id; 

Respostas para 2.1
A primeira consulta mostrará todas as entradas, exceto aquelas em que parent_id é NULL

A segunda consulta mostrará todas as entradas da tabela. IS DISTINCT FROM é logicamente semelhante ao operador ! = Em que NULL é idêntico a NULL
NÃO É DISTINTO DE transforma logicamente desigualdade em igualdade

2.2 Qual será o resultado da solicitação?

 -- ) SELECT * FROM ( SELECT 1 UNION ALL SELECT 1 ) x(y) UNION ( SELECT 2 UNION ALL SELECT 2 ); 

Responder para 2,2
O resultado será 2 linhas com os valores 1 e 2 , UNION removerá todas as duplicatas na seleção resultante , e não apenas entre as duas tabelas unidas. Notei que isso não é óbvio para todos.

2.3 Escreva uma consulta que mostre a data de amanhã.

Responda a 2.3
 SELECT CAST((now()+ INTERVAL '1 DAY') AS DATE) 

Nem todo mundo costuma trabalhar com datas, mas vale a pena dominar um mínimo
* Solução Postgres, mas acho que outros DBMSs não são muito diferentes

Se trabalhar com datas é novo para você, recomendo que experimente a solicitação
Por exemplo:
- substitua DAY por (semana, mês, ano etc.)
- substitua +1 por -9000
- substitua DATE por TIME
- remover CAST
- deixe apenas AGORA ()
etc.

E, inspirado em alguns resultados, leia MANUAL , todos os tópicos descritos em detalhes


2.4 As instruções UPDATE , DELETE , INSERT e MERGE são projetadas para manipular dados em tabelas. A execução do SELECT .. é "segura"? Qualquer consulta pode afetar os dados na tabela?
Responda a 2.4
A questão pode parecer primitiva, no entanto ...

No começo do aprendizado de SQL, eu tinha a opinião de que essa declaração só pode mostrar dados, mas:

Além do fato de que SELECT é capaz de bloquear a tabela para alteração (BEGIN; SELECT ... FOR UPDATE) *
SELECT é capaz de chamar funções que podem executar quase qualquer manipulação.

Os iniciantes precisam entender isso imediatamente, e não depois de concluir a solicitação "informativa pequena" no servidor de Produção


3. Somente PostgreSQL


3.1 Descreva o que acontece quando esta consulta é executada na caixa de diálogo SQL:

 SELECT * INTO wtf FROM pg_stat_activity; 

Responder para 3,1
Normalmente, SELECT INTO é usado nas funções plpgsql para gravar um valor em uma variável.

Fora do plpgsql, o efeito do comando será semelhante à consulta abaixo:

 CREATE TABLE wtf AS SELECT * FROM pg_stat_activity; 


3.2 o que esse pedido "simples" mostrará

 SELECT wtf_ FROM pg_stat_activity AS wtf_ ; 

Responder para 3,2
Visualização do sistema pg_stat_activity (VIEW) de processos ativos no banco de dados.

A peculiaridade da consulta é que uma coluna com linhas (ROW) com TYPE pg_stat_activity (ou outra tabela) será exibida. Você precisa saber isso mais cedo para quem escreve funções.Você pode ler mais no manual.
A pergunta foi adicionada porque um iniciante pode facilmente obter esse resultado por engano e não entende qual é o problema

4. Trabalhe com texto. Expressões regulares


Eu acho que você precisa não apenas criar consultas, mas também apresentar os resultados da maneira correta.
Expressões regulares são um tópico enorme separado, com muitos artigos de qualidade. Portanto, mostrarei apenas exemplos, sem explicações detalhadas.

4.1 Suponha que exista uma tabela " table_5 " com uma coluna de texto " X " e muitas linhas diferentes. Qual consulta pode obter os últimos 10 caracteres de cada linha?

Responder para 4,1
O SQL permite que você encontre muitas soluções para o mesmo problema, por exemplo:
a coisa mais simples que vem à mente é certa (X, 10)
regex pode ser usado: substring (X, '. {0,10} $')
você pode até nakostylyat "esquivar" (em todos os sentidos) assim: reverse (substring (reverse (X) for 10))


4.2 Existe uma tabela "table_6" com uma coluna de texto "X". A tabela contém uma linha (todo o texto apenas em inglês e russo):
 'Lorem 3 Ipsum 23 standard 7 dummy 17 text Ultimate Answer of Life ?? 777' 

A) Escreva uma consulta que retorne os caracteres 42 a 68 dessa string
B) Como extrair apenas letras maiúsculas (russo ou inglês) em uma string usando SQL?
C) Como calcular a soma dos números ( não dígitos ) em uma string usando SQL

Esboço SQL
 WITH table_6(X) AS( SELECT 'Lorem 3 Ipsum 23 standard 7 dummy 17 text Ultimate Answer of Life ?? 777'::TEXT ) SELECT X FROM table_6 

Respostas para 4.2
  --    WITH  "SQL " -- ) SELECT SUBSTRING(LEFT(X,68) FROM 42 ) FROM table_6 -- 1  SELECT SUBSTRING(X, 42, (68-42)+1) FROM table_6 -- 2  -- 3    -- )  ,        SELECT regexp_replace(X,'[^A-Z-]', '','g') FROM table_6 --  ''      - --   'g'    1  -- )        --   regexp_matches   **     ,      SELECT sum(x[1]::INT) FROM ( SELECT regexp_matches(X,'[0-9]+','g') FROM table_6 ) AS y(x) -- *        -- **   +,     (   1 ,     ) 


4.3 Como substituir todos os espaços duplos (triplos ou mais) por um único espaço no texto (célula da tabela)? (por tradição: a tabela " table_7 " com a coluna " X ") (PS, basta escrever SELECT retornando o resultado desejado, e não UPDATE table_7 ... )

Responder para 4,3
 WITH table_7(X) AS (SELECT 'Lorem 3 Ipsum 23 standard 7 dummy 11 text'::TEXT) -- 1 .    (2   ) SELECT regexp_replace(X, '( ){2,}', ' ', 'g') FROM table_7 -- 2 .     (,  ,    ..)   ,      SELECT regexp_replace(X, '\s+', ' ', 'g') FROM table_7 --  !  ,  -    ,    "" .    .. --   ,    , ,        --    ,      ,    SELECT replace(replace(replace(X, ' ', '<>'), '><', ''), '<>', ' ') FROM table_7 


4.4 Existe uma string " X " na qual erros de digitação são permitidos. Em vez de letras russas (e, o, s, C), eram usados ​​caracteres externamente semelhantes do alfabeto inglês. Substitua esses caracteres pelo SQL.

PS A linha deve conter apenas caracteres russos e você não deve se preocupar com uma possível alteração nas palavras em inglês.

(Se estiver com dificuldades para substituir todos os caracteres, substitua pelo menos um)

Linha de exemplo:

X = 'Coeo eoc oe'

Responder para 4,4
 -- , Replace(Replace(Replace(..  ,  --        (1   1 ) SELECT TRANSLATE('Coeo  eoc oe', 'Cceo', '') 

4.5 Escreva uma consulta que converta uma string:
« Ivan Ivanov e Ivanovich» da espécie Ivan Ivanov

Responder para 4,5
 --  ,     SELECT initcap('  ') *      

Busca de bônus para quem lidou
Ótimo se houver uma função pronta
Você pode converter o contrário? (de preferência sem perder o preenchimento).
Talvez a tarefa não seja típica, mas será útil para o desenvolvimento.

'IVANOV IVAN IVANOVICH' converter em 'IVANOV IVAN IVANOVICH'
e caso invertido?

Resposta ao desafio de bônus
 SELECT string_agg(LOWER(LEFT(x,1)) || UPPER(SUBSTRING(x from 2)), '' ORDER BY rn) FROM (SELECT * FROM regexp_split_to_table('    4 TesT', '\y') WITH ORDINALITY y(x, rn) ) AS z -- *  PostgreSQL,      --    ,     --      ,      --      . -- WITH ORDINALITY      (   9.4) --      --          -- .. 

5. Um pouco sobre transações


As transações são uma coisa muito importante em um SGBD; é importante entender os pontos principais.

Vou tentar simular um exemplo:

Suponha que exista uma tabela de "mercadorias" com a qual dois usuários irão trabalhar.
Possui uma coluna de desconto inteiro igual a 10 para todas as linhas.
As configurações do banco de dados são padrão (READ COMMITTED - lendo dados confirmados).

Usuário User_1 abre uma transação, executa a seguinte solicitação:

 BEGIN; UPDATE goods SET discount = discount + 5; 

Um segundo depois, outro usuário ( Usuário_2 )
Ele executa quase a mesma solicitação sem abrir uma transação:
 UPDATE goods SET discount = discount + 10; 

O que você acha que acontecerá nas seguintes situações:

A) Qual resultado o Usuário_2 obterá se o Usuário_1 deixar a transação em aberto (ou seja, não confirmar a transação / não reverter as alterações)?
O que o usuário_1 verá a pedido:

 SELECT discount FROM goods LIMIT 1; 

B) O que acontece se o Usuário_1 fizer ROLLBACK? Quais resultados o User_2 obterá?

Q) O que acontece se o Usuário_1 se comprometer? Quais resultados o User_2 obterá?

As respostas
Até onde eu sei, READ UN COMMITTED não é suportado no PostgreSQL, e dados sujos (não confirmados) não podem ser lidos

As respostas serão as seguintes:

A) A solicitação do usuário_2 aguardará COMMIT ou ROLLBACK do usuário_1. (o pedido parece congelar)
O usuário_1 em sua transação verá sua versão do instantâneo do banco de dados, em que o descontoé igual a 15

B) Se o Usuário_1 fizer ROLLBACK, o valor do desconto permanecerá o mesmo e, em seguida, o Usuário_2 será executado, o que adicionará 10 ao desconto e o desconto será 20.

C) Se o Usuário_1 fizer COMMIT, o valor do desconto aumentará em 5 e, em seguida, o Usuário_2 será executado, o que adicionará 10 ao desconto e o desconto será 25.

Outra versão desta tarefa
Uma versão ligeiramente diferente da tarefa 13 do usuário kirill_petrov em READ COMMITTED
 --      CREATE TABLE goods (discount) AS (SELECT 10::INT UNION ALL SELECT 15); -- 1. User_1   (  ): BEGIN; UPDATE goods SET discount = discount + 5; --2. User_2  : UPDATE goods SET discount = discount + 100 WHERE discount = 15 --3. User_1  COMMIT; 
Quais dados estarão na tabela?

Conclusão


Eu acho que isso tocou em pontos bastante interessantes.

Espero que as tarefas ajudem a motivar os iniciantes, porque é chato aprender algo sem metas / objetivos / orientações específicas.

Fico feliz por aqueles que foram fáceis de responder a todas as perguntas. E aqueles que tiveram dificuldades, espero, deram um chute na direção do desenvolvimento. Para quem não entende muito, mas quer aprender SQL, convido o curso de lutador jovem do PostgreSQL para o meu último artigo.

Estou ansioso para quaisquer adições, soluções para problemas especialmente interessantes (você pode os meus) e outros comentários!

Obrigado pela atenção! Desejo-lhe sucesso em aprender SQL!

Source: https://habr.com/ru/post/pt423097/


All Articles