Bases de Dados T03 - Introdução ao SQL Prof. Daniel Faria Prof. Flávio Martins Prof. Pedro Sousa Prof. Alessandro Gianola Sumário ● Recapitulação Breve ● Introdução ao SQL ○ Criação de Bases de Dados ○ População de Bases de Dados ○ Interrogação de Bases de Dados 2 Recapitulação Breve Definições ● Sistema de Informação (SI): sistema de coleta, processamento, armazenamento, distribuição e uso da informação que abarca não apenas a tecnologia, mas também a maneira como a organização interage com a tecnologia ● Sistema de Gestão de Bases de Dados (SGBD): pacote de software desenhado para guardar e gerir bases de dados; a base de muitos sistemas de informação ● Base de Dados (BD): conjunto de dados interligados e estruturados 4 Definições ● Modelo de dados: conjunto de conceitos e métodos para descrever dados, a sua semântica (e.g. relações) e restrições ● Esquema: aplicação de um modelo de dados para descrever uma colecção de dados específica ● Modelo Relacional: modelo de dados mais popular em SGBD ● Modelo Entidade-Associação: utilizado como primeiro passo no desenho de uma BD (modelação conceptual) 5 Concepção de Base de Dados Especificação de Requisitos ● requisito funcional 1: Modelo Conceptual Esquema Relacional (E-A, UML) ● requisito funcional 2: ● … ● restrição de integridade 1: ● restrição de integridade 2: ● … 6 Modelo Relacional ● Relação: conjunto de tuplos que obedecem a uma especificação de nome e domínio de dados definida num cabeçalho ○ Essencialmente uma tabela ● ● 7 Introdução ao SQL Structured Query Language (SQL) ● Materializa (aproximadamente) o modelo relacional ● Inclui: ○ Data Definition Language (DDL): usada para especificação do esquema da base de dados ○ Data Manipulation Language (DML): usada para manipulação dos dados (inserção, alteração e acesso) 9 Data Definition Language Comando Descrição CREATE DATABASE / TABLE / TYPE / SEQUENCE Cria uma nova base de dados, tabela, tipo de dados ou sequência. DROP DATABASE / TABLE / TYPE / SEQUENCE Remove uma base de dados, tabela, tipo de dados, ou sequência. ALTER DATABASE / TABLE / TYPE / SEQUENCE Edita uma base de dados, tabela, tipo de dados, ou sequência. TRUNCATE Esvazia uma ou mais tabelas. 10 Data Manipulation Language Comando Descrição INSERT Popula uma tabela com valores passados como argumentos COPY Copia dados de um ficheiro para uma tabela ou vice-versa UPDATE Atualiza valores de uma ou mais colunas numa tabela (de linhas que cumprem critérios especificados) DELETE Apaga valores de uma tabela segundo critérios especificados. SELECT Lista valores de tabelas segundo critérios especificados. 11 Criação de Bases de Dados Criar e Apagar Bases de Dados CREATE DATABASE database_name; https://www.postgresql.org/docs/current/sql-createdatabase.html DROP DATABASE database_name; https://www.postgresql.org/docs/current/sql-dropdatabase.html 13 Criar Tabelas CREATE TABLE table_name ( column_name data_type [column_constraint], … [table_constraint], … ); 14 Restrições de Coluna e Tabela ● ● Coluna: ○ NOT NULL ○ PRIMARY KEY ○ UNIQUE ○ REFERENCES reftable [ ( refcolumn ) ] ○ CHECK expression Tabela: ○ PRIMARY KEY ( column_name [, ... ] ) ○ UNIQUE ( column_name [, ... ] ) ○ FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn ) ] ○ CHECK expression 15 Tipos de Dados: Numéricos https://www.postgresql.org/docs/14/datatype-numeric.html Números inteiros com 3 capacidades diferentes Números “reais” com aritmética exata mas lenta; bons para valores monetários Números “reais” com aritmética inexata mas rápida; usar com cautela Séries de números inteiros com 3 capacidades diferentes (uso frequente como chave primária) 16 Exemplo de Problemas com Float CREATE TABLE test( x FLOAT, y FLOAT); INSERT INTO test VALUES (1.2,1.2); SELECT x+y FROM test; x+y -----------------2.4000000953674316 17 Tipos de Dados: Textuais https://www.postgresql.org/docs/14/datatype-character.html ● Considerações: ○ char ocupa mais espaço de disco ○ Limites de tamanho levam a inserção de valores mais lenta, a evitar quando não necessários para restrições de integridade ○ varchar sem limite é igual a text e um dos dois deve ser escolhido na maioria dos casos 18 Tipos de Dados: Temporais https://www.postgresql.org/docs/14/datatype-datetime.html 19 Tipos de Dados ● O PostgreSQL suporta várias funções para tipos textuais e temporais ● É ainda possível criar tipos de dados usando CREATE TYPE ○ Tipos enumerados (e.g. ‘male’, ‘female’) ○ Combinando atributos de tipos existentes CREATE TYPE name AS ENUM (['label' [,…]]); CREATE TYPE name AS ([attribute_name data_type [COLLATE collation] [,…]]); 20 Exemplos de Criação de Tabelas CREATE TABLE department( did INTEGER, name VARCHAR(80), budget NUMERIC(12,4) ); INSERT INTO department VALUES(1, 'Finance', 1000.0); INSERT INTO department VALUES(2, 'Marketing', 2000.0); INSERT INTO department VALUES(1, 'Engineering', 5000.0); INSERT INTO department VALUES(3, 'Marketing', 3000.0); 21 Exemplos de Criação de Tabelas SELECT * FROM department; did | name | budget ----+-------------+----------1 | Finance | 1000.0000 2 | Marketing | 2000.0000 1 | Engineering | 5000.0000 3 | Marketing | 3000.0000 Temos um did e um nome duplicados! 22 Exemplos de Criação de Tabelas CREATE TABLE department( did INTEGER PRIMARY KEY, name VARCHAR(80) UNIQUE NOT NULL, budget NUMERIC(12,4) ); Já não é possível ter did ou nome duplicados! 23 Exemplos de Criação de Tabelas CREATE TABLE employee( eid INTEGER PRIMARY KEY, name VARCHAR(80) UNIQUE NOT NULL ); CREATE TABLE works_in( eid INTEGER, did INTEGER, role VARCHAR(80) NOT NULL, PRIMARY KEY (eid, did) ); Como garantir integridade referencial? 24 Exemplos de Criação de Tabelas CREATE TABLE employee( eid INTEGER PRIMARY KEY, name VARCHAR(80) UNIQUE NOT NULL ); CREATE TABLE works_in( eid INTEGER REFERENCES employee, did INTEGER REFERENCES department, role VARCHAR(80) NOT NULL, PRIMARY KEY (eid, did) ); Foreign keys como restrições de coluna/tabela! 25 Outras Restrições ● NOT NULL: Necessário para obrigar a inserção de um valor ○ Por omissão todas as colunas que não fazem parte da chave primária podem ter NULL (mesmo colunas UNIQUE, dado que NULL != NULL) ● DEFAULT: Usar quando há um valor assumido no caso de não-inserção ● CHECK: Permite verificações de domínio de dados mais avançadas, e.g.: CHECK (LENGTH(name) > 3) CHECK (birthdate > '1920-01-01') CHECK (EXTRACT(YEAR FROM AGE(birthdate)) > 18) CHECK (gender in ('Female','Male','Other')) 26 Edição de Tabelas ALTER TABLE table_name RENAME column_name TO new_column_name, ADD column_name data_type, DROP column_name, ALTER column_name TYPE data_type; ● ALTER TABLE permite: ○ Renomear a tabela, uma coluna, ou uma restrição ○ Adicionar/remover colunas ou restrições ○ Editar colunas (mudar data_type, adicionar/remover restrições) 27 Remoção de Tabelas DROP TABLE [IF EXISTS] table_name; ● IF EXISTS: produz uma notificação em vez de um erro caso a tabela não exista (importante para não abortar código que consiste de múltiplos comandos) 28 População de Bases de Dados Inserção Atómica de Dados INSERT INTO table_name [(column_name, …)] VALUES (value_list_1), (value_list_2), … (value_list_n); Exemplo: INSERT INTO department VALUES(1, 'Finance', 1000.0),(2, 'Marketing', 2000.0); 30 Inserção de Dados de Outras Tabelas INSERT INTO table_name [(column_name, …)] SELECT [*|expression1, …] FROM table1_name, … WHERE condition1, …; Popula uma tabela com o resultado de uma query! 31 Importação/Exportação de Dados Importação: COPY … FROM COPY table_name [(column_name [, ...])] FROM {'filename' | PROGRAM 'command' | STDIN} [[WITH] (option [, ...])] [WHERE condition] Exportação: COPY … TO COPY {table_name [(column_name [, ...])] | (query) } TO { 'filename' | PROGRAM 'command' | STDOUT} [[WITH] (option [, ...])] 32 Atualização de Dados UPDATE table_name SET column_name = expression, … ; Exemplos: UPDATE department SET budget = 3000 WHERE name = 'Marketing'; ALTER TABLE department ADD share FLOAT; UPDATE department SET share = budget / (SELECT SUM(budget)) FROM department; 33 Remoção de Dados DELETE FROM table_name WHERE condition; Exemplos: DELETE FROM department WHERE name = 'Marketing'; DELETE FROM department WHERE share < 0.1; 34 Interrogação de Bases de Dados Interrogação de Bases de Dados [WITH with_query [, ...]] SELECT [ALL | DISTINCT [ON (expression [, ...])]] [* | expression [[AS] output_name] [, ...]] [FROM from_item [, ...]] [WHERE condition] [GROUP BY [ALL | DISTINCT] grouping_element [, ...]] [HAVING condition] [{UNION | INTERSECT | EXCEPT} [ALL | DISTINCT] select] [ORDER BY expression [ASC | DESC | USING operator] [NULLS { FIRST | LAST}] [, ...]] [LIMIT {count | ALL}] 36 Caso Mais Simples SELECT * FROM account; +----------------+-------------+---------+ | account_number | branch_name | balance | +----------------+-------------+---------+ | A-101 | Downtown | 500.00 | | A-102 | Perryridge | 400.00 | | A-201 | Brighton | 900.00 | | A-215 | Mianus | 700.00 | | A-217 | Brighton | 750.00 | | A-222 | Redwood | 700.00 | | A-305 | Round Hill | 350.00 | +----------------+-------------+---------+ ● SELECT *: Devolve todo o conteúdo da tabela ● O resultado de um SELECT é sempre uma tabela ○ Mesmo “SELECT 2;” 37 Ordenar SELECT * FROM account ORDER BY balance DESC; +----------------+-------------+---------+ | account_number | branch_name | balance | +----------------+-------------+---------+ | A-201 | Brighton | 900.00 | | A-217 | Brighton | 750.00 | | A-215 | Mianus | 700.00 | | A-222 | Redwood | 700.00 | | A-101 | Downtown | 500.00 | | A-102 | Perryridge | 400.00 | | A-305 | Round Hill | 350.00 | +----------------+-------------+---------+ ● ORDER BY: ordena os resultados ○ Default por ordem crescente (ASC) ○ Especificar ordem decrescente (DESC) ● Sem ORDER BY, resultados vêm por ordem “arbitrária” 38 Filtrar Colunas SELECT account_number AS acc_no FROM account a; +--------+ | acc_no | +--------+ | A-101 | | A-102 | | A-201 | | A-215 | | A-217 | | A-222 | | A-305 | +--------+ ● As colunas a obter são listadas logo a seguir ao SELECT ● Podemos dar aliases às colunas devolvidas e às tabelas consultadas 39 Filtrar Linhas SELECT * FROM account WHERE balance > 500; +----------------+-------------+---------+ | account_number | branch_name | balance | +----------------+-------------+---------+ | A-201 | Brighton | 900.00 | | A-215 | Mianus | 700.00 | | A-217 | Brighton | 750.00 | | A-222 | Redwood | 700.00 | +----------------+-------------+---------+ ● WHERE statement permite filtrar valores ○ Podemos combinar várias cláusulas com operadores lógicos (AND ou OR) ○ Cláusulas booleanas (usando operadores ou funções de comparação) 40 Operadores e Funções de Comparação ● Operadores: =, >, <, >=, <=, != ou <> ● Predicados: ○ [NOT] BETWEEN x AND y ○ IS [NOT] NULL/TRUE/FALSE/UNKNOWN ↦ lidar com NULLs ● Comparação de Arrays: ○ expression [NOT] IN (value [, value...]) ↦ lista manual ou SELECT ○ expression operator ANY/SOME/ALL (array expression) ● Comparação de Strings: ○ string [NOT] LIKE pattern https://www.postgresql.org/docs/current/functions-comparison.html https://www.postgresql.org/docs/current/functions-comparisons.html https://www.postgresql.org/docs/15/functions-matching.html 41 Filtrar Linhas e Colunas SELECT DISTINCT branch_name FROM account WHERE branch_name LIKE ‘%n’; +-------------+ | branch_name | +-------------+ | Downtown | | Brighton | +-------------+ ● DISTINCT remove duplicados (Brighton aparece duas vezes em account) ● Sem DISTINCT teremos um resultado por linha da tabela original 42 Combinar Tudo SELECT account_number AS acc_no, balance FROM account WHERE SQRT(balance) > 22 OR branch_name LIKE ‘%n’; +--------+---------+ | acc_no | balance | +--------+---------+ | A-101 | 500.00 | | A-201 | 900.00 | | A-215 | 700.00 | | A-217 | 750.00 | | A-222 | 700.00 | +--------+---------+ ● As cláusulas podem incluir funções ○ Matemáticas ○ Para Strings ○ Para Datas/Horas 43 Produto Cartesiano SELECT * FROM account, depositor; +----------------+-------------+---------+---------------+----------------+ | account_number | branch_name | balance | customer_name | account_number | +----------------+-------------+---------+---------------+----------------+ | A-101 | Downtown | 500.00 | Hayes | A-102 | | A-102 | Perryridge | 400.00 | Hayes | A-102 | | A-201 | Brighton | 900.00 | Hayes | A-102 | | A-215 | Mianus | 700.00 | Hayes | A-102 | | A-217 | Brighton | 750.00 | Hayes | A-102 | | ... | ... | ... | ... | ... | | A-305 | Round Hill | 350.00 | Turner | A-305 | +----------------+-------------+---------+---------------+----------------+ 49 rows in set (0.00 sec) 44 Produto Cartesiano ● account tem 7 linhas ● depositor tem 7 linhas ○ account × depositor tem 7×7 = 49 linhas! ● account tem 3 colunas ● customer tem 2 colunas ○ account × depositor tem 3+2 = 5 colunas! ● Produto cartesiano permite cruzar dados entre tabelas, mas requer filtros que interligam as tabelas 45 Produto Cartesiano SELECT * FROM account a, depositor d WHERE a.account_number = d.account_number; +----------------+-------------+---------+---------------+----------------+ | account_number | branch_name | balance | customer_name | account_number | +----------------+-------------+---------+---------------+----------------+ | A-101 | Downtown | 500.00 | Johnson | A-101 | | A-102 | Perryridge | 400.00 | Hayes | A-102 | | A-201 | Brighton | 900.00 | Johnson | A-201 | | A-215 | Mianus | 700.00 | Smith | A-215 | | A-217 | Brighton | 750.00 | Jones | A-217 | | A-222 | Redwood | 700.00 | Lindsay | A-222 | | A-305 | Round Hill | 350.00 | Turner | A-305 | +----------------+-------------+---------+---------------+----------------+ 46 Junção Interna SELECT * FROM account a [INNER] JOIN depositor d USING (account_number); +----------------+-------------+---------+---------------+ | account_number | branch_name | balance | customer_name | +----------------+-------------+---------+---------------+ | A-101 | Downtown | 500.00 | Johnson | | A-102 | Perryridge | 400.00 | Hayes | | A-201 | Brighton | 900.00 | Johnson | | A-215 | Mianus | 700.00 | Smith | | A-217 | Brighton | 750.00 | Jones | | A-222 | Redwood | 700.00 | Lindsay | | A-305 | Round Hill | 350.00 | Turner | +----------------+-------------+---------+---------------+ Idêntico ao Produto cartesiano com filtro mas sem a coluna duplicada! 47 Junção Natural SELECT * FROM account NATURAL JOIN depositor; +----------------+-------------+---------+---------------+ | account_number | branch_name | balance | customer_name | +----------------+-------------+---------+---------------+ | A-101 | Downtown | 500.00 | Johnson | | A-102 | Perryridge | 400.00 | Hayes | | A-201 | Brighton | 900.00 | Johnson | | A-215 | Mianus | 700.00 | Smith | | A-217 | Brighton | 750.00 | Jones | | A-222 | Redwood | 700.00 | Lindsay | | A-305 | Round Hill | 350.00 | Turner | +----------------+-------------+---------+---------------+ Junta TODAS as colunas com nome igual. Evitar usar! 48 Junção Externa SELECT * FROM borrower LEFT [OUTER] JOIN depositor USING (customer_name); customer_name | loan_number | account_number ---------------+-------------+---------------Iacocca | L-17 | A-217 2 loans e 1 account Iacocca | L-16 | A-217 Cook | L-15 | A-101 1 loan e 2 account Cook | L-15 | A-102 Brown | L-23 | A-444 Brown | L-23 | A-215 2 loans e 2 accounts Brown | L-21 | A-444 Brown | L-21 | A-215 Nguyen | L-14 | Davis | L-93 | 1 loans mas 0 accounts Gonzalez | L-17 | Parker | L-20 | 49 Operações de Conjuntos ● União SELECT account_number FROM account WHERE branch_name = ‘Brighton’ UNION SELECT account_number FROM depositor WHERE customer_name = ‘Johnson’; +----------------+ | account_number | +----------------+ | A-201 | | A-217 | | A-101 | +----------------+ A-201, A-217 A-101, A-201 50 Operações de Conjuntos ● Intersecção SELECT account_number FROM account WHERE branch_name = ‘Brighton’ INTERSECT SELECT account_number FROM depositor WHERE customer_name = ‘Johnson’; +----------------+ | account_number | +----------------+ | A-201 | +----------------+ A-201, A-217 A-101, A-201 51 Operações de Conjuntos ● Diferença SELECT account_number FROM account WHERE branch_name = ‘Brighton’ EXCEPT SELECT account_number FROM depositor WHERE customer_name = ‘Johnson’; +----------------+ | account_number | +----------------+ | A-217 | +----------------+ A-201, A-217 A-101, A-201 52 Agregação SELECT COUNT(*) FROM account; +-------+ | COUNT | +-------+ | 7 | +-------+ SELECT SUM(balance), AVG(balance) FROM account; +---------+---------+ | SUM | AVG | +---------+---------+ | 4300.00 | 614.29 | +---------+---------+ ● Funções que agregam valores para toda a tabela output https://www.postgresql.org/docs/current/functions-aggregate.html 53 Agregação SELECT branch_name, SUM(balance) AS total FROM account GROUP BY branch_name HAVING total > 500; +-------------+---------+ | branch_name | total | +-------------+---------+ | Brighton | 1650.00 | | Mianus | 700.00 | | Redwood | 700.00 | +-------------+---------+ ● É necessário um GROUP BY sempre que se combina colunas agregadas com não agregadas ● HAVING statement é semelhante à WHERE mas verificada após a agregação 54