Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

86
Curiosidades que você (talvez) não sabia e se sabia Dickson S. Guedes @guediz PGBR 2015 - Porto Alegre, RS

Transcript of Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Page 1: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Curiosidades quevocê (talvez) nãosabia e se sabia …

Dickson S. Guedes@guediz

PGBR 2015 - Porto Alegre, RS

Page 2: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

O aninhador frenético

Page 3: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

ProblemaSELECT ..., CASE WHEN sobrenome IS NULL THEN nome WHEN sobrenome IS NOT NULL THEN sobrenome || ',' || nome ENDFROM ...

Page 4: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

SoluçãoSELECT ..., COALESCE(sobrenome || ',', '') || nomeFROM ...

Page 5: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 6: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

O aninhador frenético II

Page 7: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

ProblemaSELECT ..., CASE WHEN COALESCE(endereco, '') <> '' THEN CASE WHEN COALESCE( COALESCE(endereco, '') || ' ' || COALESCE(bairro, '') ) <> ' ' THEN endereco ||' '|| bairro ELSE COALESCE(cidade, '') END ELSE COALESCE(cidade,'SEM CIDADE') ENDFROM ...LEFT JOIN ...LEFT JOIN ...

Page 8: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Possível soluçãoSELECT ..., COALESCE(endereco ||' '|| bairro, cidade, 'SEM CIDADE'),FROM ...LEFT JOIN ...LEFT JOIN ...

Page 9: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Opa! Três parâmetros?SELECT ..., COALESCE(endereco ||' '|| bairro, cidade, 'SEM CIDADE'), ̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂ ̂^̂^̂ ̂ ̂^̂^̂^̂^̂^FROM ...LEFT JOIN ...LEFT JOIN ...

Page 10: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Qual é o resultado disto?SELECT ..., COALESCE(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'SEM VALOR'), COALESCE(NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'SEM VALOR'), COALESCE(NULL, NULL, NULL, NULL, NULL, NULL, 'SEM VALOR'), COALESCE(NULL, NULL, NULL, NULL, NULL, 'SEM VALOR'), COALESCE(NULL, NULL, NULL, NULL, 'SEM VALOR'), COALESCE(NULL, NULL, NULL, 'SEM VALOR'), COALESCE(NULL, NULL, 'SEM VALOR'), COALESCE(NULL, 'SEM VALOR'), ...FROM ...

Page 11: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Como isso é possível?

Page 12: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 13: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

VARIADICCREATE FUNCTION menor_de_todos(VARIADIC valores numeric[])RETURNS numeric AS$$ SELECT min($1[valor]) FROM generate_subscripts($1, 1) g(valor);$$LANGUAGE SQL;

SELECT menor_de_todos(10, 11, 12, 30, -20, -30) as menor;

menor -------- -30(1 row)

Page 14: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Parâmetros! Não é para passar um ARRAYnão!

SELECT menor_de_todos(ARRAY[10, 11, 12, 30, -20, -30]) as menor; ̂^̂^̂^ ̀-- assim da ruim

Page 15: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 16: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

O esbanjador de SELECTs

Page 17: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Tudo bunitinhoCREATE TYPE situacao_cheque AS ENUM ('compensado', 'devolvido', 'sustado', 'voador');

CREATE TABLE cheque (numero integer not null, valor integer not null, situacao situacao_cheque);

INSERT INTO cheque VALUES (1, 100.00, NULL);

INSERT INTO cheque VALUES (2, 500.00, 'compensado'), (3, 1000.00, 'devolvido'), (4, 900.00, 'devolvido'), (5, 3000.00, 'compensado'), (6, 145.00, 'sustado'), (7, 45.00, 'voador'), (8, 66.00, 'voador'), (9, 96.00, 'sustado'), (10, 45.00, 'sustado');

Page 18: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

ai você vê isso …SELECT (SELECT COUNT(*) FROM cheque WHERE situacao = 'compensado') as total_compensados, (SELECT COUNT(*) FROM cheque WHERE situacao = 'devolvido') as total_devolvidos, (SELECT COUNT(*) FROM cheque WHERE situacao = 'voador') as total_voadores;

Page 19: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

mas esperava isso …SELECT SUM(CASE WHEN situacao = 'compensado' THEN 1 ELSE 0 END) as total_compensados, SUM(CASE WHEN situacao = 'devolvido' THEN 1 ELSE 0 END) as total_devolvidos, SUM(CASE WHEN situacao = 'voador' THEN 1 ELSE 0 END) as total_voadoresFROM cheque;

Page 20: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Ei! isso também é possívelSELECT SUM( int4( situacao = 'compensado' ) ) as total_compensados, SUM( int4( situacao = 'devolvido' ) ) as total_devolvidos, SUM( int4( situacao = 'voador' ) ) as total_voadoresFROM cheque;

Page 21: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

CASTCAST('a' = 'b' AS int4) = 0int4('a' = 'b') = 0

CAST('a' = 'a' AS int4) = 1int4('a' = 'a') = 1

int4('B' = 'B') + int4('A' = 'A') = 2

Page 22: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Outros CASTs que funcionamSELECT text(1); => '1'SELECT date '2014-01-01'; => '2014-01-01'SELECT numeric '1'; => 1SELECT int4 '100000000000000'; => out of rangeSELECT int8 '100000000000000'; => 100000000000000

Page 23: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Então da para fazer algo assimSELECT SUM( int4( situacao = 'compensado' ) ) as total_compensados, SUM( int4( situacao = 'devolvido' ) ) as total_devolvidos, SUM( int4( situacao = 'voador' ) ) as total_voadores ̂^̂^̂ ̂^̂^̂^̂ ,̂̂ ^̂^̂^̂^̂^FROM cheque; ̀~~~~~~~~~~́~~~~~ transforma boolean para integer

Page 24: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Mas qual é "o" problema?todos os cheque acima de R$ 1.000,00 foram compensados?algum cheque abaixo de R$ 800,00 foi devolvido?

Page 25: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Declarativo e explicito MELHOR QUEimplícito.

SELECT BOOL_AND(situacao = 'compensado') FILTER (WHERE valor > 1000) as "todos > 1000 foram compensados?", BOOL_OR(situacao = 'devolvido') FILTER (WHERE valor < 800) as "algum < 800 foi devolvido", EVERY(situacao = 'voador') as "algum cheque voador?"FROM cheque;

SELECT bool_and(situacao = 'compensado') as "todos compensados acima de R$ 1.000"FROM cheque WHERE valor > 1000;

SELECT bool_or(situacao = 'devolvido') as "Algum cheque < 800 devolvido?"FROM chequeWHERE valor < 800;

Page 26: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 27: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

O explorador do desconhecido

Page 28: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

NULL e a aritiméticaSELECT NULL = NULL;SELECT NULL > NULL;SELECT NULL < NULL;

Page 29: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

NULL e a aritiméticaSELECT NULL = NULL; => NULLSELECT NULL > NULL; => NULLSELECT NULL < NULL; => NULL

Page 30: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

O que é NULL?SELECT NULL IS NULL; => trueSELECT NULL IS DISTINCT FROM NULL; => falseSELECT NULL IS NOT DISTINCT FROM NULL; => true

SELECT 1 IS NULL; => falseSELECT 1 IS DISTINCT FROM NULL; => trueSELECT 1 IS NOT DISTINCT FROM NULL; => false

Page 31: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

TESTE DE ATENÇÃO!

Page 32: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Lembram da função menor_de_todos?SELECT menor_de_todos(10, 11, 12, 30, -20, -30) as menor;

menor -------- -30(1 row)

Page 33: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

E se eu passar NULL?SELECT menor_de_todos(10, 11, 12, NULL, -20, -30) as menor;

menor -------- ????? (1 row)

Page 34: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

-30SELECT menor_de_todos(10, 11, 12, NULL, -20, -30) as menor;

menor -------- -30 (1 row)

Page 35: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

menor_de_todos(...) usa a funçãomin(...) que é uma função de agregação

Page 36: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

funções de agregação ignoram NULL

Page 37: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 38: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

O fabricador de registros

Page 39: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Um registro!SELECT ROW(10, 'JOAO', 1500.50);

Page 40: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Dois registros!SELECT ROW(10, 'JOAO', 1500.50) = ROW(10, 'JOAO', 1500.50); => true

SELECT ROW(10, 'JOAO', 1500.50) > ROW(9, 'PEDRO', 500.50); => true

SELECT ROW(1, 'MARIA', 1000.10) > ROW(1, 'MARIA', 1000.11); => false

SELECT ROW(100, 'JOANA', 10.60) < ROW(100, 'JOANA', NULL); => ?????

Page 41: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

NULL!

Page 42: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 43: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Lembra o INSERT?INSERT INTO ... VALUES (1, 'JOAO', 1500.10);

Page 44: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Pensa no VALUES!/* INSERT INTO ... */ VALUES (1, 'JOAO', 1500.10); -- FUNCIONA!

Page 45: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

VALUES é um comando sozinho!INSERT INTO ... SELECT codigo, nome, valor FROM tabela_temporaria;

INSERT INTO ... VALUES (1, 'JOAO', 1500.10);

VALUES (1, '...', 1500.10), (2, '...', 500.00), (3, '...', 100.00), (4, '...', 50.50), (5, '...', 3500.00),;

Page 46: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 47: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

O masoquista escrivinhador

Page 48: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

SIM! Isto funciona; pode testar!SELECT 1 OPERATOR(pg_catalog.+) 2 = 1 + 2; => true

Page 49: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Operadores são funções disfarçadasSELECT 1 + 1; ̂ ̂ ̂__ integer na direita | |____ operador '+' |______ integer na esquerda

SELECT oprname, oprcode, CAST(oprleft AS regtype), -- 23 é integer CAST(oprright AS regtype) -- 23 é integerFROM pg_operator WHERE oprname = '+' AND oprleft = 23 AND oprright = 23;

oprname | oprcode | oprleft | oprright ---------+---------+---------+---------- + | int4pl | integer | integer

Page 50: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Operadores são funções disfarçadasSELECT 1 + 1; ̂ ̂ ̂__ integer na direita | |____ operador '+' |______ integer na esquerda

SELECT oprname, oprcode, CAST(oprleft AS regtype), -- 23 é integer CAST(oprright AS regtype) -- 23 é integerFROM pg_operatorWHERE (oprname, oprleft, oprright) = ('+', 23, 23); ̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^̂^ ̀- este é um outro jeito de escrever o WHERE sem os AND e obter o mesmo resultado...

oprname | oprcode | oprleft | oprright ---------+---------+---------+---------- + | int4pl | integer | integer ̂^̂^̂ .̂___ o postgres chamará esta função para somar integer com integer

Page 51: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Logo …SELECT 1 + 1 = 2;

SELECT int4pl(1, 1) = 2;

Page 52: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 53: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Para o infinito, e além

Page 54: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Sim, tudo isso é possívelSELECT '+Infinity'::float > 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; => true

SELECT '-Infinity'::float < 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; => true

Page 55: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Infinito para datas, também, claro!SELECT 'Infinity'::date > current_date; => true

INSERT INTO elemento(nome, validade) VALUES ('urânio', 'Infinity'); isto é um date _.̂^̂^̂^̂^1SELECT 'today'::interval = current_date; => true

SELECT 'yesterday'::date = 'today'::date - interval '1 day'; => true

SELECT 'tomorroy'::date = 'today'::date + interval '1 day'; => true

SELECT current_date + 'allballs'::time; => '2015-09-18 00:00:00'

Page 56: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

E tudo pode ser rescrito como …SELECT date 'Infinity' > current_date; => true

INSERT INTO elemento(nome, validade) VALUES ('urânio', 'Infinity'); isto é um date _.̂^̂^̂^̂^

SELECT interval 'today' = current_date; => true

SELECT date 'yesterday' = date 'today' - interval '1 day'; => true

SELECT date 'tomorroy' = date 'today' + interval '1 day'; => true

SELECT current_date + time 'allballs'; => '2015-09-18 00:00:00'

Page 57: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

NaNaNaNaNaNaNaNSELECT 'NaN'::numeric + 1; => 'NaN'

Page 58: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 59: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Já que estamos falando dedatas

Page 60: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

já viram isso?SELECT ... CAST( CAST(ano AS text) || '-' || CAST(mes AS text) || '-' || CAST(dia AS text), AS date) ), ...FROM ...;

Page 61: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

ou isso?SELECT ... FROM ...WHERE ... data_nascimento = CAST( CAST(ano AS text) || '-' || CAST(mes AS text) || '-' || CAST(dia AS text), AS date) );;

Page 62: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

que se faça a dataSELECT ..., make_date(ano, mes, dia), ...FROM ...;

Page 63: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 64: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Algumas fontes são True Type

Page 65: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 66: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

SERIAL NÃO!

Page 67: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

São equivalentesCREATE TABLE tabela ( coluna SERIAL);

OU

CREATE SEQUENCE tabela_coluna_seq;CREATE TABLE tabela ( coluna integer NOT NULL DEFAULT nextval('tabela_coluna_seq'));ALTER SEQUENCE tabela_coluna_seq OWNED BY tabela.coluna;

Page 68: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 69: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Chamando funções

Page 70: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Uma função pode ser chamada assimSELECT upper('nome');

upper ------- NOME(1 registro)

Page 71: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Uma função pode ser chamada assimtambém

SELECT * FROM upper('nome');

upper ------- NOME(1 registro)

Page 72: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

E também pode ser assimSELECT ('nome').upper;

upper ------- NOME(1 registro)

Page 73: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Uma tabela comum, uma consulta comumCREATE TABLE pessoa(nome text, data_nascimento date);

INSERT INTO pessoa VALUES('JOAO', now() - interval '35 years');

SELECT p.nome, p.data_nascimento FROM pessoa p;

Page 74: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

e uma consulta não tanto comumSELECT nome(p), data_nascimento(p) from pessoa p;

nome | data_nascimento ------+----------------- JOAO | 1980-09-18(1 registro)

Page 75: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Mas uma função também pode ter seuretorno como uma tabela

CREATE FUNCTION duplica(IN int, OUT valor_original int, OUT valor_convertido text)AS$$ SELECT $1, CAST($1 AS text) || ' eh texto'$$LANGUAGE SQL;

SELECT * FROM duplica(42);

valor_original | valor_convertido ----------------+------------------ 42 | 42 eh texto(1 registro)

Tempo: 1,684 ms

Page 76: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar
Page 77: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

PSQL

Page 78: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

isso ajuda\set v_nome 'JOAO'\set v_idade 18

\connect desenv usuario 192.168.1.1 5432

SELECT * FROM pessoa WHERE nome = :v_nome AND idade > :v_idade \g

\connect teste usuario 192.168.1.2 5432

SELECT * FROM pessoa WHERE nome = :v_nome AND idade > :v_idade ;

Page 79: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

isso também ajuda\set v_cpf 1234567890

\connect desenv usuario 192.168.1.1 5432

SELECT nome as v_nome, idade as v_idadeFROM pessoa WHERE cpf = :v_cpf \gset

\connect teste usuario 192.168.1.2 5432

SELECT * FROM pessoaWHERE nome = :v_nome AND idade > :v_idade ;

Page 80: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Talvez num futuro isso funcioneSELECT ... FROM banco.esquema.tabela;

Page 81: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Bom, não é só isso…

Page 82: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

ainda tem muito mais coisas…

Page 83: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Leia o manualhttp://www.postgresql.org/docs/manuals/

Page 84: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Visite o IRC, é divertido …

Page 85: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

Numa terça-feira monótona, AndrewGierth (a.k.a. RhodiumToad) escreveu isto

SELECT oid, lowrite(lo_open(oid,131072), a)FROM (VALUES (lo_create(0))) v(oid), generate_bytea() as x(a);

-- (note the oid returned)

\lo_export 828133392 'image.png'

SELECT lo_unlink(828133392);

Page 86: Curiosidades que você (talvez) não sabia e se sabia vale a pena lembrar

e é isso, obrigado! :)Conferencia Brasileira de PostgreSQL

18 a 20 de Novembro

email: [email protected]: twitter:

http://pgbr.postgresql.org.br/

http://github.com/guedeshttp://twitter.com/guediz