33
ICE-B ICE-B ICE-B ICE-B ICE-B ICE-B ICE-B ICE-B ICE-B 17 - Sqlite e Python 17 - Sqlite e Python 17 - Sqlite e Python 17 - Sqlite e Python 17 - Sqlite e Python 17 - Sqlite e Python 17 - Sqlite e Python 17 - Sqlite e Python 17 - Sqlite e Python Ludwig Krippahl

17 - Sqlite e Python17 - Sqlite e Python17 - Sqlite e Python17 - …iceb.ssdi.di.fct.unl.pt/1920/files/ICE-B-17.pdf · 2020. 5. 26. · 17 - Sqlite e Python17 - Sqlite e Python17

  • Upload
    others

  • View
    62

  • Download
    1

Embed Size (px)

Citation preview

  • ICE-BICE-BICE-BICE-BICE-BICE-BICE-BICE-BICE-B

    17 - Sqlite e Python17 - Sqlite e Python17 - Sqlite e Python17 - Sqlite e Python17 - Sqlite e Python17 - Sqlite e Python17 - Sqlite e Python17 - Sqlite e Python17 - Sqlite e Python

    Ludwig Krippahl

  • 1

    Sqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + Python

    Resumo■ Usar Sqlite a partir de Python■ Módulo sqlite3■ Ligação à base de dados■ Cursor para executar comandos SQL■ Exemplo prático: criar uma tabela e consultar os dados

  • 2

    Sqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + Python

    Usar Sqlite em PythonUsar Sqlite em PythonUsar Sqlite em PythonUsar Sqlite em PythonUsar Sqlite em PythonUsar Sqlite em PythonUsar Sqlite em PythonUsar Sqlite em PythonUsar Sqlite em Python

  • 3

    Sqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + Python

    Porquê usar um motor de bases de dados?■ A linguagem SQL facilita muito algumas operações• Criar tabelas, inserir registos, consultar dados

    ■ O motor de bases de dados está optimizado para gerir os dados• Garante integridade da informação, mesmo em caso de falhas

    • Está preparado para gerir grandes volumes de dados• Oferece uma interface standard (SQL) acessível a outros sistemas

  • 4

    Sqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + Python

    Como usar o Sqlite em Python com o módulo sqlite3■ Criar uma ligação à base de dados: conn = connect(db_name)■ Obter um cursor, que executa SQL: cursor = conn.cursor()■ Dar o comando ou commandos SQL: cursor.execute(sql)■ Actualizar a base de dados: conn.commit()• Isto garante atomicidade das transacções

    • Até ao commit() a BD não é alterada.

    • Apenas parece alterada da perspectiva desta ligação

    • No commit() são feitas todas as alterações.

    • Se houver erro não é feita nenhuma alteração

    • Se nos arrependemos, em vez do commit() podemos fazer rollback()

    ■ Fechar a ligação: conn.close()

  • 5

    Sqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + Python

    Exemplo: Renovação de praiasExemplo: Renovação de praiasExemplo: Renovação de praiasExemplo: Renovação de praiasExemplo: Renovação de praiasExemplo: Renovação de praiasExemplo: Renovação de praiasExemplo: Renovação de praiasExemplo: Renovação de praias

  • 6

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Temos um ficheiro de texto com dados de projectos■ Ficheiro praias.txt• Concelho, nome, custo e prioridade.

    Marinha Grande;Esporao da Praia da Vieira;720000.00;Media

    Lourinha;Arribas junto ao forte do Paimogo;591000.00;Media

    Lourinha;Arribas em Porto das Barcas;691000.00;Media

    Lourinha;Arribas em Porto Dinheiro;606500.00;Media

    Sintra;Arribas da praia Grande do Rodizio;39951.63;Media

    Sintra;Arribas da praia das Azenhas do Mar;326560.08;Media

    Sintra;Arribas da praia Pequena;428015.58;Media

    Santiago do Cacem;Arriba da Praia Fonte do Cortico;23000.00;Media

    Sines;Relocalizacao de acessos das praias de Morgavel, Franquia ...

    Setubal;Arribas da praia de Galapos;100000.00;Baixa

    Vila do Bispo;Alimentacao artificial da praia da Mareta;2500000.00;Elevada

    Portimao;Saneamento da arriba na praia do Vau;30000.00;Elevada

    ■ Queremos organizar isto numa tabela para poder consultar• Por exemplo, todos os projectos com uma certa prioridade

  • 7

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Plano do programa:■ Criar a tabela Projectos com os campos necessários:• concelho, nome, custo, prioridade

    ■ Carregar os dados do ficheiro para a tabela Projectos■ Criar uma função que liste os projectos com a prioridade

    especificada• Consultando a tabela na BD

    import sqlite3 def create_table(db_name): """create the Projects table in the database""" def load_projects(file_name, db_name): """load projects from file into projects table""" def with_priority(db_name,priority): "return dictionary with projects of given priority"

  • 8

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Criar a tabeladef create_table(db_name): """create the projects table in the database""" conn = sqlite3.connect(db_name) cursor = conn.cursor() cursor.execute('CREATE TABLE Projects ( Concelho TEXT, Nome TEXT,'+ 'Custo FLOAT, Prioridade TEXT, PRIMARY KEY(Nome));') conn.commit() conn.close()

    ■ Ligar à base de dados (connect)■ Obter o cursor para essa ligação■ Executar o código SQL para criar a tabela e fazer commit■ Fechar a ligação.

  • 9

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Criar a tabeladef create_table(db_name): """create the projects table in the database""" conn = sqlite3.connect(db_name) cursor = conn.cursor() cursor.execute('CREATE TABLE Projects ( Concelho TEXT, Nome TEXT,'+ 'Custo FLOAT, Prioridade TEXT, PRIMARY KEY(Nome));') conn.commit() conn.close()

    In : create_table('teste.db') In :

    ■ Como sabemos se funcionou?

  • 10

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Como verificar o resultado■ Opção 1: usar o sqlite3 directamente:

    SQLite version 3.20.1 2017-08-24 16:21:36 Enter ".help" for usage hints. Connected to a transient in-memory database. Use ".open FILENAME" to reopen on a persistent database. sqlite> .open teste.db sqlite> .tables Projects sqlite> .schema CREATE TABLE Projects ( Concelho TEXT, Nome TEXT,Custo FLOAT, Prioridade TEXT, PRIMARY KEY(Nome)); sqlite> .quit

  • 11

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Como verificar o resultado■ Opção 2: usar um gestor para Sqlite.• Sqliteman (http://sqliteman.yarpen.cz/), Sqlitebrowser (https://sqlitebrowser.org/)

    ■ Não é necessário; usem isto apenas se acharem que dá jeito

  • 12

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    ■ Problema: se a tabela já existe ocorre uma exception

    In : create_table('teste.db') ... OperationalError: table Projects already exists

    ■ Isto é inconveniente porque bloqueia a execução■ Para evitar que pare vamos usar um bloco try ... except

    try: ... except ...: ...

    ■ Se ocorrer um erro no bloco try a execução passa ao ramoexcept que corresponde ao erro

    ■ Nota: pode ser todos se não especificarmos qual, mas isso é máideia.

  • 13

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Criar a tabeladef create_table(db_name): """create the projects table in the database""" conn = sqlite3.connect(db_name) cursor = conn.cursor() try: cursor.execute('CREATE TABLE Projects ( Concelho TEXT, Nome TEXT,'+ 'Custo FLOAT, Prioridade TEXT, PRIMARY KEY(nome));') conn.commit() except sqlite3.Error: print('Error: could not create table.') conn.close()

    In : create_table('teste.db') In : create_table('teste.db') Error: could not create table. In :

  • 14

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Inserir os dados do ficheiroMarinha Grande;Esporao da Praia da Vieira;720000.00;Media

    Lourinha;Arribas junto ao forte do Paimogo;591000.00;Media

    Lourinha;Arribas em Porto das Barcas;691000.00;Media

    Lourinha;Arribas em Porto Dinheiro;606500.00;Media

    Sintra;Arribas da praia Grande do Rodizio;39951.63;Media

    Sintra;Arribas da praia das Azenhas do Mar;326560.08;Media

    Sintra;Arribas da praia Pequena;428015.58;Media

    Santiago do Cacem;Arriba da Praia Fonte do Cortico;23000.00;Media

    Sines;Relocalizacao de acessos das praias de Morgavel, Franquia ...

    Setubal;Arribas da praia de Galapos;100000.00;Baixa

    Vila do Bispo;Alimentacao artificial da praia da Mareta;2500000.00;Elevada

    Portimao;Saneamento da arriba na praia do Vau;30000.00;Elevada

  • 15

    Strings e SQLStrings e SQLStrings e SQLStrings e SQLStrings e SQLStrings e SQLStrings e SQLStrings e SQLStrings e SQL

    Criação de strings com outros argumentos■ Para criar comandos SQL será preciso combinar strings e

    parâmetros■ Uma opção é usar format:

    In : 'INSERT INTO Table VALUES( {}, "{}", {});'.format(1,'abc','NULL') Out: 'INSERT INTO Table VALUES( 1, "abc", NULL);' In : 'INSERT INTO Table VALUES( {0}, "{1}", {2});'.format(1,'abc','NULL') Out: 'INSERT INTO Table VALUES( 1, "abc", NULL);' In : 'INSERT INTO Table VALUES( {num}, "{tex}", {nul});'\ ...: .format(num=1,tex='abc',nul='NULL') Out: 'INSERT INTO Table VALUES( 1, "abc", NULL);'

    ■ Nota: na string com o comando SQL as strings têm de estardelimitadas

  • 16

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Inserir os dados do ficheirodef load_projects(file_name, db_name): """load projects from file into projects table""" lines = open(file_name).readlines() conn = sqlite3.connect(db_name) cursor = conn.cursor() template = 'INSERT INTO Projects VALUES ( "{0}", "{1}", {2}, "{3}");' for line in lines: try: cells = line.strip().split(';') sql = template.format(cells[0],cells[1],cells[2],cells[3]) cursor.execute(sql) conn.commit() except sqlite3.Error: print('Error on ',line) conn.close()

    ■ Tentamos inserir cada registo e fazer logo o commit• Se alguma coisa correr mal, avisamos que houve um erro naquela linha

    ■ Alernativa: fazer todos os execute e depois um só commit

  • 17

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Inserir os dados do ficheiro■ Testar:

    In : load_projects('praias.txt','teste.db')

    ■ Verificar com a consola do sqlite3

    SQLite version 3.20.1 2017-08-24 16:21:36 Enter ".help" for usage hints. Connected to a transient in-memory database. Use ".open FILENAME" to reopen on a persistent database. sqlite> .open teste.db sqlite> select * from projects; Marinha Grande|Esporao da Praia da Vieira|720000.0|Media Lourinha|Arribas junto ao forte do Paimogo|591000.0|Media Lourinha|Arribas em Porto das Barcas|691000.0|Media Lourinha|Arribas em Porto Dinheiro|606500.0|Media Sintra|Arribas da praia Grande do Rodizio|39951.63|Media sqlite>.quit

  • 18

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    ■ Testar:

    In : load_projects('praias.txt','teste.db')

    ■ Verificar com o sqliteman• (Opcional, e é mais importante familiarizarem-se com a consola)

  • 19

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Com a tabela no sqlite3 podemos:■ Ver os custos dos projectos de nome começado por Arriba:

    sqlite> SELECT Nome, Custo FROM Projects WHERE Nome LIKE "Arriba%"; Arribas junto ao forte do Paimogo|591000.0 Arribas em Porto das Barcas|691000.0 Arribas em Porto Dinheiro|606500.0 Arribas da praia Grande do Rodizio|39951.63 Arribas da praia das Azenhas do Mar|326560.08 Arribas da praia Pequena|428015.58 Arriba da Praia Fonte do Cortico|23000.0 Arribas da praia de Galapos|100000.0 sqlite>

    ■ O operador LIKE compara strings admitindo wildcards• O sinal % na string do LIKE substitui qualquer substring

  • 20

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Com a tabela no sqlite3 podemos:■ Ver os custos dos projectos com praia no nome:

    sqlite> SELECT Nome, Custo FROM Projects WHERE Nome LIKE "%praia%"; Esporao da Praia da Vieira|720000.0 Arribas da praia Grande do Rodizio|39951.63 Arribas da praia das Azenhas do Mar|326560.08 Arribas da praia Pequena|428015.58 Arriba da Praia Fonte do Cortico|23000.0 Relocalizacao de acessos das praias de Morgavel, Franquia e Farol|100100.0 Arribas da praia de Galapos|100000.0 Alimentacao artificial da praia da Mareta|2500000.0 Saneamento da arriba na praia do Vau|30000.0 sqlite>

    ■ O operador LIKE compara strings admitindo wildcards• O sinal % na string do LIKE substitui qualquer substring

    ■ O operador LIKE não distingue maiúsculas e minúsculas

  • 21

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Com a tabela no sqlite3 podemos:■ Ver os concelhos diferentes onde há projectos (DISTINCT)

    sqlite> SELECT DISTINCT Concelho FROM Projects; Marinha Grande Lourinha Sintra Santiago do Cacem Sines Setubal Vila do Bispo Portimao

    ■ Ou prioridade:

    sqlite> SELECT DISTINCT Prioridade FROM Projects; Media Baixa Elevada sqlite>

  • 22

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Consultas usando Python■ Com o objecto cursor podemos executar o SELECT• Neste caso não há commit porque não alteramos a base de dados

    ■ Depois de executar o SELECT, podemos obter todos os resultadoscom cursor.fetchall()

    • Uma lista de tuplos com os valores dos campos

    In : conn = sqlite3.connect('teste.db') In : cursor = conn.cursor() In : cursor.execute('SELECT * FROM Projects WHERE Nome LIKE "%praia%";') In : cursor.fetchall() Out: [('Marinha Grande', 'Esporao da Praia da Vieira', 720000.0, 'Media'), ('Sintra', 'Arribas da praia Grande do Rodizio', 39951.63, 'Media'), ('Sintra', 'Arribas da praia das Azenhas do Mar', 326560.08, 'Media'), ('Sintra', 'Arribas da praia Pequena', 428015.58, 'Media'), ... ('Portimao', 'Saneamento da arriba na praia do Vau', 30000.0, 'Elevada')] In : conn.close()

  • 23

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Consultas usando Python■ Vamos criar uma função auxiliar para simplificar isto• E organizar os dados como uma lista de dicionários, usandocursor.description

    • Tem um tuplo de tuplos com o nome da coluna como primeiro elemento

    • O resto não interessa, é só para compatibilidade com a API de BD

    • Podemos usar isto para criar uma lista de dicionários

    In : conn = sqlite3.connect('teste.db') In : cursor = conn.cursor() In : cursor.execute('SELECT * FROM Projects WHERE Nome LIKE "%praia%";') In : cursor.description Out: (('Concelho', None, None, None, None, None, None), ('Nome', None, None, None, None, None, None), ('Custo', None, None, None, None, None, None), ('Prioridade', None, None, None, None, None, None)) In : conn.close()

  • 24

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Consultas usando Python■ Função auxiliar para simplificar consultas

    def query_db(db_name,query): "return dictionary with result of SELECT" conn = sqlite3.connect(db_name) cursor = conn.cursor() cursor.execute(query) records = cursor.fetchall() conn.close() result = [] for record in records: current = {} for ix in range(len(record)): current[cursor.description[ix][0]] = record[ix] result.append(current) return result

  • 25

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Consultas usando Python■ Função auxiliar para simplificar consultas

    In : query_db('teste.db','SELECT * FROM Projects;') Out[36]: [{'Concelho': 'Marinha Grande', 'Custo': 720000.0, 'Nome': 'Esporao da Praia da Vieira', 'Prioridade': 'Media'}, {'Concelho': 'Lourinha', 'Custo': 591000.0, 'Nome': 'Arribas junto ao forte do Paimogo', 'Prioridade': 'Media'}, {'Concelho': 'Lourinha', 'Custo': 691000.0, 'Nome': 'Arribas em Porto das Barcas', 'Prioridade': 'Media'}, ... {'Concelho': 'Portimao', 'Custo': 30000.0, 'Nome': 'Saneamento da arriba na praia do Vau', 'Prioridade': 'Elevada'}]

  • 26

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Consultas usando Python■ Função auxiliar para simplificar consultas

    In : query_db('teste.db','SELECT * FROM Projects WHERE Prioridade="Baixa"') Out: [{'Concelho': 'Setubal', 'Custo': 100000.0, 'Nome': 'Arribas da praia de Galapos', 'Prioridade': 'Baixa'}] In : query_db('teste.db','SELECT * FROM Projects WHERE Prioridade="Elevada"') Out: [{'Concelho': 'Vila do Bispo', 'Custo': 2500000.0, 'Nome': 'Alimentacao artificial da praia da Mareta', 'Prioridade': 'Elevada'}, {'Concelho': 'Portimao', 'Custo': 30000.0, 'Nome': 'Saneamento da arriba na praia do Vau', 'Prioridade': 'Elevada'}]

  • 27

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Função para obter projectos dada a prioridade■ Esta agora é fácil:

    def with_priority(db_name,priority): "return dictionary with projects of given priority" query = 'SELECT * FROM Projects WHERE Prioridade = "{0}";' query = query.format(priority) return query_db(db_name,query)

    In : with_priority('teste.db','Baixa') Out: [{'Concelho': 'Setubal', 'Custo': 100000.0, 'Nome': 'Arribas da praia de Galapos', 'Prioridade': 'Baixa'}]

  • 28

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Função para organizar projectos por prioridade■ Devolve um dicionário com todas as prioridades na tabela■ Cada entrada desse dicionário tem a lista de dicionários com os

    projectos correspondentes

    def projects_by_priority(db_name): "return dictionary with priorities and all projects in list" projects = {} priorities = query_db(db_name,'SELECT DISTINCT Prioridade from Projects;') for entry in priorities: priority = entry['Prioridade'] projects[priority] = with_priority(db_name,priority) return projects

    ■ Usamos SELECT DISTINCT Prioridade para listar prioridades■ Para cada uma criamos a entrada no dicionário projects

  • 29

    ExemploExemploExemploExemploExemploExemploExemploExemploExemplo

    Função para organizar projectos por prioridadeIn : projects = projects_by_priority('teste.db') In : projects.keys() Out: dict_keys(['Media', 'Baixa', 'Elevada']) In : projects['Elevada'] Out: [{'Concelho': 'Vila do Bispo', 'Custo': 2500000.0, 'Nome': 'Alimentacao artificial da praia da Mareta', 'Prioridade': 'Elevada'}, {'Concelho': 'Portimao', 'Custo': 30000.0, 'Nome': 'Saneamento da arriba na praia do Vau', 'Prioridade': 'Elevada'}] In : projects['Baixa'] Out: [{'Concelho': 'Setubal', 'Custo': 100000.0, 'Nome': 'Arribas da praia de Galapos', 'Prioridade': 'Baixa'}]

  • 30

    Sqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + PythonSqlite + Python

    ResumoResumoResumoResumoResumoResumoResumoResumoResumo

  • 31

    ResumoResumoResumoResumoResumoResumoResumoResumoResumo

    Sqlite e Python■ Python permite-nos processar os dados de muitas formas• Gráficos, ajuste de modelos, processar ficheiros, etc

    ■ Mas um SGBD permite gerir os dados de forma independente• Mais fácil de trocar informação com outros programas (e.g. sqliteman)• Optimizado para gerir dados (atomicidade, grande volume, etc)

    ■ Combinar os dois pode ser uma boa solução• Módulo sqlite3: ligar, criar cursor, executar e fechar

    Leitura adicional:■ Recomendada: Capítulo 17 dos apontamentos■ Opcional: sqlite3: https://docs.python.org/3.6/library/sqlite3.html