Jump to content
Sign in to follow this  
Belini

Criar e ler um banco de dados SQlite

Recommended Posts

Nunca trabalhei com banco de dados por isto preciso de dicas para criar um banco de dados de aproximadamente 2 milhões de linhas e depois fazer a leitura dele linha por linha para comparar com outra informação que será passada pelo programa, vou dar um exemplo da linha que preciso gravar no banco de dados e posteriormente fazer a leitura dela.

1=01 03 05 11 15 17 19 25 26 28 33 36 40 42 45 47 48 54 57 60 64 66 67 70 75 PG-Q01 10
2=03 05 07 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PG-Q02 10
3=02 07 10 12 14 16 17 23 26 28 32 34 35 39 41 48 49 52 54 58 61 62 63 70 72 PG-Q03 10
4=05 06 11 14 15 16 17 24 25 30 33 36 42 43 44 46 49 50 51 60 63 64 66 74 75 PG-Q04 10
5=02 01 05 08 17 19 23 24 27 28 31 39 40 44 45 47 49 51 55 59 61 63 66 74 75 PG-Q05 10
6=01 03 10 14 15 18 19 23 24 28 31 35 36 39 40 47 48 54 56 59 61 62 63 64 65 PG-Q06 10
7=02 07 09 15 18 20 21 23 25 30 31 36 41 42 43 46 50 51 56 59 63 64 70 74 75 PG-Q07 10
8=04 06 08 11 12 19 21 24 27 29 33 34 39 44 45 46 48 51 55 57 65 67 72 73 74 PG-Q08 10
9=04 05 08 14 15 17 20 25 28 30 36 39 41 42 44 46 51 55 57 60 63 64 72 74 75 PG-Q09 10

Estas são as linhas que preciso gravar e ler posterirmente e para isto penso em usar o For $i = 1 to 2000000

Share this post


Link to post
Share on other sites

Encontrei um exemplo no forum americano e estou fazendo testes nele mas ainda não sei como fazer a procura no banco de dados como faço usando o iniread por exemplo como seria para mim pegar os dados da linha 7 sem ter que ler linha por linha?

#include <GUIConstants.au3>
#include <EditConstants.au3>

;~ #include <SQLite.au3>
;~ #include <SQLite.dll.au3>

#include "SQLite.au3"
#include "SQLite.dll.au3"

$form_num = 1

#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Sqlite GUI test", 223, 359, 267, 119)
$count = GUICtrlCreateInput($form_num, 144, 10, 33, 21, BitOR($ES_AUTOHSCROLL,$ES_READONLY))
$b_right = GUICtrlCreateButton(">", 176, 8, 27, 25, 0)
$b_left = GUICtrlCreateButton("<", 120, 8, 27, 25, 0)
$lname = GUICtrlCreateLabel("Name:", 8, 48, 48, 17)
$iname = GUICtrlCreateInput("", 64, 48, 145, 21)
$ladress = GUICtrlCreateLabel("Adress:", 8, 88, 45, 17)
$iadress = GUICtrlCreateInput("", 64, 88, 145, 21)
$iemail = GUICtrlCreateInput("", 64, 128, 145, 21)
$lemail = GUICtrlCreateLabel("E-mail:", 8, 128, 46, 17)
$lother = GUICtrlCreateLabel("Other:", 8, 168, 46, 17)
$eother = GUICtrlCreateEdit("", 64, 168, 145, 121)
$badd = GUICtrlCreateButton("Add", 48, 312, 75, 25, 0)
$bdel = GUICtrlCreateButton("Delete", 128, 312, 75, 25, 0)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

_SQLite_Startup()
If NOT FileExists("database.db") Then
    $dbn=_SQLite_Open("database.db")
    _SQLite_Exec($dbn,"CREATE TABLE datas (id,name,adress,email,other);")
Else
    $dbn=_SQLite_Open("database.db")
EndIf


MsgBox(4096, '', $dbn)

dataquery($form_num)

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            progend()
        Case $b_right
            $form_num = $form_num + 1
            GUICtrlSetData($count,$form_num)
            dataquery($form_num)
        Case $b_left
            If $form_num == 1 Then
                $form_num = 1
                GUICtrlSetData($count,$form_num)
            Else
                $form_num = $form_num - 1
                GUICtrlSetData($count,$form_num)
                dataquery($form_num)
            EndIf
        Case $badd
            IF GUICtrlRead($iname) == "" Then
                MsgBox(0,"ERORR","Empty name!")
            Else
                dataadd($form_num)
            EndIf
        Case $bdel
            datadel($form_num)
    EndSwitch
WEnd

Func progend()
    _SQLite_Close()
    _SQLite_Shutdown()
    Exit
EndFunc

Func dataadd($id)
    Local $retarr
    $str1 = GUICtrlRead($iname)
    $str2 = GUICtrlRead($iadress)
    $str3 = GUICtrlRead($iemail)
    $str4 = GUICtrlRead($eother)
    _SQLite_QuerySingleRow($dbn,"SELECT id FROM datas WHERE id='"&$id&"'",$retarr)
    If $retarr[0] <> "" Then
        _SQLite_Exec($dbn,"UPDATE datas SET name='"&$str1&"', adress='"&$str2&"',email='"&$str3&"',other='"&$str4&"' WHERE id='"&$id&"'")
    Else
        _SQLite_Exec($dbn,"INSERT INTO datas (id,name,adress,email,other) VALUES ('"&$form_num&"','"&$str1&"','"&$str2&"','"&$str3&"','"&$str4&"');")
    EndIf
EndFunc


Func dataquery($id)
    GUICtrlSetData($iname,"")
    GUICtrlSetData($iadress,"")
    GUICtrlSetData($iemail,"")
    GUICtrlSetData($eother,"")
    Local $retarr
    If _SQLite_QuerySingleRow($dbn,"SELECT * FROM datas WHERE id='"&$id&"'",$retarr) == $SQLITE_OK Then
        If $retarr[0] == "" Then
            ;MsgBox(0,"ERROR","Query error!")
        Else
            GUICtrlSetData($iname,$retarr[1])
            GUICtrlSetData($iadress,$retarr[2])
            GUICtrlSetData($iemail,$retarr[3])
            GUICtrlSetData($eother,$retarr[4])
        EndIf
    EndIf
EndFunc

Func datadel($id)
    Local $retarr
    GUICtrlSetData($iname,"")
    GUICtrlSetData($iadress,"")
    GUICtrlSetData($iemail,"")
    GUICtrlSetData($eother,"")
    _SQLite_QuerySingleRow($dbn,"SELECT id FROM datas WHERE id='"&$id&"'",$retarr)
    If $retarr[0] <> "" Then
        _SQLite_Exec($dbn,"DELETE FROM datas WHERE id='"&$id&"'")
    EndIf
EndFunc

 

Share this post


Link to post
Share on other sites

Como dizia o famoso assassino Jack Estripador (ou seu homônimo brasileiro Chico Picadinho), vamos por partes!

Quanto ao problema aqui, as linhas são gravadas como se fossem uma linha inteira ou como números isolados?

Quote

1=01 03 05 11 15 17 19 25 26 28 33 36 40 42 45 47 48 54 57 60 64 66 67 70 75 PG-Q01 10

Isso tudo é uma linha só? Ou são vários campo separados (um para cada nro)?

E se for uma linha só, vc vai ter 2 milhões de linhas, isso?

PS.: Veja minha resposta lá nos exemplos para resolver o problema da abertura do banco de dados.

Share this post


Link to post
Share on other sites

Depois, para fins de pesquisa, vc vai usar o comando _SQLite_Query para pesquisar o que vc quer, independente de qual linha está.

Em teoria, vc usa o IniRead para puxar o que vc precisa e depois compara com o resultado dentro do banco.

Tenha em mente que o SQLite (ou qualquer outro banco), ao fazer uma pesquisa ele sempre "cria" um subconjunto de dados que fecham com as condições estabelecidas pelo comando QUERY. Então vc sempre vai precisar "varrer" este subconjunto para pegar a informação que vc precisa.

#include <Sqlite.au3>

; inicializa o SQLite. Não esquecer das DLL com os nomes certos e na pasta do script
$SQLite_DLL = _SQLite_Startup()
If @error Then
   ConsoleWrite("Erro de inicialização da SQLite" & @CRLF)
   Exit
EndIf

; aqui está abrindo um banco em memória, ou seja, não fica nada gravado em disco
Local $Handle_DB = _SQLite_Open()
If @error Then
   ConsoleWrite("Erro na abertura do banco de dados" & @CRLF)
   Exit
EndIf

; cria a tabela NUMEROS com apenas um campo chamado LINHA que contém texto genérico
_SQLite_Exec($Handle_DB, "CREATE TABLE Numeros (Linha TEXT);")

; insere os dados na tabela
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('1=01 03 05 11 15 17 19 25 26 28 33 36 40 42 45 47 48 54 57 60 64 66 67 70 75 PG-Q01 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('2=03 05 07 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PG-Q02 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('3=02 07 10 12 14 16 17 23 26 28 32 34 35 39 41 48 49 52 54 58 61 62 63 70 72 PG-Q03 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('4=05 06 11 14 15 16 17 24 25 30 33 36 42 43 44 46 49 50 51 60 63 64 66 74 75 PG-Q04 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('5=02 01 05 08 17 19 23 24 27 28 31 39 40 44 45 47 49 51 55 59 61 63 66 74 75 PG-Q05 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('6=01 03 10 14 15 18 19 23 24 28 31 35 36 39 40 47 48 54 56 59 61 62 63 64 65 PG-Q06 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('7=02 07 09 15 18 20 21 23 25 30 31 36 41 42 43 46 50 51 56 59 63 64 70 74 75 PG-Q07 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('8=04 06 08 11 12 19 21 24 27 29 33 34 39 44 45 46 48 51 55 57 65 67 72 73 74 PG-Q08 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('9=04 05 08 14 15 17 20 25 28 30 36 39 41 42 44 46 51 55 57 60 63 64 72 74 75 PG-Q09 10');")

; lê o que vc precisa no arquivo INI
Local $sTexto = IniRead(@ScriptDir & "\Arquivo.Ini", "Numeros", "Chave", "")
If not $sTexto Then
   ConsoleWrite("Erro na leitura do arquivo INI" & @CRLF)
   Exit
EndIf

; faz a pesquisa no banco
Local Enum $DB_LINHA
Local $Consulta, $Informacao
_SQLite_Query($Handle_DB, "SELECT Linha FROM Numeros WHERE Linha = '" & $sTexto & "';", $Consulta)
While _SQLite_FetchData($Consulta, $Informacao) == $SQLITE_OK
   If $Informacao[$DB_LINHA] = $sTexto Then ConsoleWrite("Achei" & @CRLF)
WEnd

; fecha tudo
_SQLite_Close($Handle_DB)
_SQLite_Shutdown()

 

   Se vc precisa apenas verificar se a informação está dentro do banco há outro comando que pode facilitar.

   O objetivo dele, se funcionar, é trazer um subconjunto de APENAS 1 registro!

#include <Sqlite.au3>

; inicializa o SQLite. Não esquecer das DLL com os nomes certos e na pasta do script
$SQLite_DLL = _SQLite_Startup()
If @error Then
   ConsoleWrite("Erro de inicialização da SQLite" & @CRLF)
   Exit
EndIf

; aqui está abrindo um banco em memória, ou seja, não fica nada gravado em disco
Local $Handle_DB = _SQLite_Open()
If @error Then
   ConsoleWrite("Erro na abertura do banco de dados" & @CRLF)
   Exit
EndIf

; cria a tabela NUMEROS com apenas um campo chamado LINHA que contém texto genérico
_SQLite_Exec($Handle_DB, "CREATE TABLE Numeros (Linha TEXT);")

; insere os dados na tabela
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('1=01 03 05 11 15 17 19 25 26 28 33 36 40 42 45 47 48 54 57 60 64 66 67 70 75 PG-Q01 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('2=03 05 07 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PG-Q02 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('3=02 07 10 12 14 16 17 23 26 28 32 34 35 39 41 48 49 52 54 58 61 62 63 70 72 PG-Q03 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('4=05 06 11 14 15 16 17 24 25 30 33 36 42 43 44 46 49 50 51 60 63 64 66 74 75 PG-Q04 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('5=02 01 05 08 17 19 23 24 27 28 31 39 40 44 45 47 49 51 55 59 61 63 66 74 75 PG-Q05 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('6=01 03 10 14 15 18 19 23 24 28 31 35 36 39 40 47 48 54 56 59 61 62 63 64 65 PG-Q06 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('7=02 07 09 15 18 20 21 23 25 30 31 36 41 42 43 46 50 51 56 59 63 64 70 74 75 PG-Q07 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('8=04 06 08 11 12 19 21 24 27 29 33 34 39 44 45 46 48 51 55 57 65 67 72 73 74 PG-Q08 10');")
_SQLite_Exec($Handle_DB, "INSERT INTO Numeros VALUES ('9=04 05 08 14 15 17 20 25 28 30 36 39 41 42 44 46 51 55 57 60 63 64 72 74 75 PG-Q09 10');")

; lê o que vc precisa no arquivo INI
Local $sTexto = IniRead(@ScriptDir & "\Arquivo.Ini", "Numeros", "Chave", "")
If not $sTexto Then
   ConsoleWrite("Erro na leitura do arquivo INI" & @CRLF)
   Exit
EndIf

; faz a pesquisa no banco
If _SQLite_QuerySingleRow($Handle_DB, "SELECT Linha FROM Numeros WHERE Linha = '" & $sTexto & "';", $Consulta) = $SQLITE_OK Then
   ConsoleWrite("Achei" & @CRLF)
EndIf

; fecha tudo
_SQLite_Close($Handle_DB)
_SQLite_Shutdown()

 

   Veja se isso resolve!

Share this post


Link to post
Share on other sites

@manimal as informações são apenas uma linha mesmo como vc postou no exemplo, meu programa já está pronto e usa 3 arquivos ini para armazenar dados, fazer leitura, comparação e atualização de dados, até umas 30.000 linhas funciona bem mas como devo precisar de ums 2 milhões de linhas pensei em fazer testes com banco de dados prá ver se consigo melhorar a velocidade de pesquisa e comparação, vou expplicar o que já faço usando arquivos ini aí vc me fala se é possível fazer o mesmo usando banco de dados e se terei melhora na velocidade de pesquisa, comparação e atualização de dados.

1º arquivo ini: Cadastro.ini

Quote

[DADOS]
PG-Q01=01 03 05 11 15 17 19 25 26 28 33 36 40 42 45 47 48 54 57 60 64 66 67 70 75 PG-Q01 10
PG-Q02=01 02 06 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PG-Q02 10
PG-Q03=03 04 10 12 14 16 17 23 26 28 32 34 35 39 41 48 49 52 54 58 61 62 63 70 72 PG-Q03 10
PG-Q04=02 06 10 11 13 16 17 24 25 30 33 36 42 43 44 46 49 50 51 60 63 64 66 74 75 PG-Q04 10
PG-Q05=02 03 05 08 13 16 23 24 27 28 31 39 40 44 45 47 49 51 55 59 61 63 66 74 75 PG-Q05 10
PG-Q06=01 03 10 14 15 18 19 23 24 28 31 35 36 39 40 47 48 54 56 59 61 62 63 64 65 PG-Q06 10

2º arquivo ini: Dados_01.ini

Quote

[DADOS]
1=01 02 06 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PG-Q02 10
2=02 06 10 11 13 16 17 24 25 30 33 36 42 43 44 46 49 50 51 60 63 64 66 74 75 PG-Q04 10
3=01 03 10 14 15 18 19 23 24 28 31 35 36 39 40 47 48 54 56 59 61 62 63 64 65 PG-Q06 10

3º arquivo ini: Dados_01.ini

Quote

[DADOS]
PG-Q02=01 02 06 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PG-Q02 10
PG-Q04=02 06 10 11 13 16 17 24 25 30 33 36 42 43 44 46 49 50 51 60 63 64 66 74 75 PG-Q04 10
PG-Q06=01 03 10 14 15 18 19 23 24 28 31 35 36 39 40 47 48 54 56 59 61 62 63 64 65 PG-Q06 10

No primeiro arquivo eu tenho todos cadastros e os dados que preciso ler estão identificados pelo que está nas chaves da seção com o nome DADOS aí funciona assim se eu entrar com o código PG-Q02 ele vai ler no primeiro ini e gravar nos arquivos ini 2 e 3 sendo que no arquivo 2 ele vai retirar a identificação PG-Q02 e vai gravar numerando sempre colocando prá ser a chave um número a mais do que o último gravado exemplo no arquivo 2 já tenho 8 dados gravados então o último garavado está na chave 8 aí este que vou gravar vai ter o número 9 como chave e depois dele os dados que pegou do arquivo 1 o arquivo 3 repete a mesma linha que pegou no arquivo ini 1 e feito isto apaga da arquivo 1 a linha que foi lida de onde pegou os dados para gravar nos arquivos 2 e 3, no exemplo que dei acima o arquivo 1 ficara sem as linhas 2, 4 e 6 depois que eu fiz a leitura dos dados destas linhas e gravei nos arquivos 2 e 3

Arquivo 1 depois de gravados os dados no inis 2 e 3

Quote

[DADOS]
PG-Q01=01 03 05 11 15 17 19 25 26 28 33 36 40 42 45 47 48 54 57 60 64 66 67 70 75 PG-Q01 10
PG-Q03=03 04 10 12 14 16 17 23 26 28 32 34 35 39 41 48 49 52 54 58 61 62 63 70 72 PG-Q03 10
PG-Q05=02 03 05 08 13 16 23 24 27 28 31 39 40 44 45 47 49 51 55 59 61 63 66 74 75 PG-Q05 10

ou seja os dados que tem nos arquivos 2 e 3 não tem mais no arquivo 1 e o que tem no arquivo 1 ainda não foi transportado para os arquivos 2 e 3

Usando arquivo ini se eu precisar os dados que tem na chave PG-Q05 por exemplo eu já vou direto nestes dados e sem ter que digitar todos os dados que tem naquela linha apenas coloco para procurar PG-Q05 na seção DADOS aí gravo estes dados nos arquivos ini 2 e 3 depois apago a linha que tem a chave PG-Q05  usando o IniDelete, o meu problema é conseguir fazer o mesmo usando banco de dados e nem sei ainda se seria melhor criar 3 banco de dados como fiz usando arquivos ini ou criar apenas 1 e salvar os dados dos 3 nele mesmo.

Share this post


Link to post
Share on other sites

@Belini,

Nunca trabalhei com banco de dados por isto preciso de dicas para criar um banco de dados de aproximadamente 2 milhões de linhas
Segundo página do desenvolvedor, SQLite manipula arquivos de até 140 terabytes...
Então acho que você tem que colocar mais alguns milhões de linhas para começar a esbarrar no limite técnico.

Veja: https://www.sqlite.org/whentouse.html @ Very large datasets

e depois fazer a leitura dele linha por linha
Beleza, é possível!
Mas oriento a não fazer um for...next de 1 até o fim da lista...
Vai ficar lento demais!

Sugiro fazer por blocos, tipo, de 300 em 300 linhas por vez

 
A mesma coisa vale para inserção de dados...
Ler um arquivo inteiro, de não sei quantos mbytes ou gbytes e inserir e um for...next, vai ficar muito lento...
Vai por blocos, monta uma query só... que insere um bloco de linhas, exemplo:

Local $aInsert[1]
_ArrayAdd($aInsert, "INSERT INTO matematica(numeros)VALUES(" & Random(0, 9, 1) & ");")
_ArrayAdd($aInsert, "INSERT INTO matematica(numeros)VALUES(" & Random(0, 9, 1) & ");")
_ArrayAdd($aInsert, "INSERT INTO matematica(numeros)VALUES(" & Random(0, 9, 1) & ");")
_ArrayAdd($aInsert, "INSERT INTO matematica(numeros)VALUES(" & Random(0, 9, 1) & ");")
_ArrayAdd($aInsert, "INSERT INTO matematica(numeros)VALUES(" & Random(0, 9, 1) & ");")
Repete isso 20x...

E no final...

Local $sql= _ArrayToString($aInsert, "", 1)

_Base_Execute($sql)

Faz a execução de um concatenado de SQLs!

Qual é a quantidade ideal? Não sei... depende do trabalho do seu insert, tem que testar...

AutoIt parece que não se dá bem com loops muito grandes... Mas se for por blocos, parece melhora muito.

 

O ideal é sempre inserir texto, utilizando antes _SQLite_FastEncode().
Ele faz o scape correto dos caracteres, assim não dá erro de insert.

Local $frase = "Viva a matemática, que eu tanto amo e não lembro mais nada!"
Local $sql =  "INSERT INTO livro(frases)VALUES(" & _SQLite_FastEncode($frase) & ");"

_Base_Execute($sql)

  • Like 1

Share this post


Link to post
Share on other sites

Obrigado @manimal e @Luigi pelas aulas vou fazer testes aqui com tudo que vc passaram e gostaria que me dessem uma sugestão de como fazer o banco de dados destes 3 arquivos que uso se devo colocar os dados dos 3 em um banco de dados só ou se devo criar 3 banco de dados sendo um para cada arquivo deste, pergunto isto porque se for colocar tudo em um só serão aproximandamente 4.000.000 de linhas em um único banco de dados pois inicialmente só o primeio bd terá dados e quando pegar informação de alguma das linhas irá apagar dele e gravar nos outros dois db.

Share this post


Link to post
Share on other sites

@Luigi tentei inserir algumas  linhas para testar o exemplo que vc postou mas sempre dá por causa de ter espaço nas linhas que preciso inserir, como fazer para poder inserir letras e números separados por espaço?

Func Etapa_1()
    Local $sql
    ConsoleWrite("Etapa 1: Inserindo um número" & @LF)
    For $i = 1 To 10
        $dados = "PG-Q" & $i & "=01 02 06 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PG-Q" & $i & " 10"
        $sql = "INSERT INTO matematica(numeros)VALUES(" & $dados & ");"
        _Base_Execute($sql)
    Next
EndFunc   ;==>Etapa_1

Coloquei numerando de 1 a10 prá depois tentar pegar os dados de alguma das linhas tipo a linha que houver PG-Q5 no início dela, quando for prá valer vou precisar pegar entre ums 2.000.000 de linhas

Share this post


Link to post
Share on other sites

Olá.

   O erro está na sintaxe do comando de INSERT, pois o AutoIt converte para string a tua variável $dados, mas a forma final está errada.

   Só mude a linha

$sql = "INSERT INTO matematica(numeros)VALUES(" & $dados & ");"

   para

$sql = "INSERT INTO matematica(numeros) VALUES('" & $dados & "');"

 

   Quanto à quantidade de banco de dados, vc pode ter apenas 1 arquivo físico e dentro dele vc pode ter quantas tabelas quiser.

   Basta dar um CREATE TABLE para cada arquivo que vc quer dentro do banco.

Share this post


Link to post
Share on other sites

A quantidade de linhas não faz diferença. Ter 1 linha ou 1 milhão de linhas não muda nada para o gerenciamento do banco.

Ter 3 tabelas dentro do banco ou 1 tabela apenas, depende de vc.

Na verdade, acredito que manter tudo em uma mesma tabela será melhor, pois a manutenção e a consulta dos dados será unificada.

Mas você pode explicar melhor o que vc está fazendo? Talvez o teu foco no banco pode estar errado, se vc estiver olhando ele como uma extensão dos arquivos INI.

Share this post


Link to post
Share on other sites

É um programa de bingo que fiz no primeiro arquivo ini tem os dados de todas cartelas que foram geradas, a medida que vai vendendo faço o cadastro que é consultado neste primeiro arquivo e se nele tiver os dados daquela cartela o programa grava nos outros dois arquivos e apaga do primeiro para que a mesma cartela não seja usada mais de uma vez, o arquivo 2 que é numerado em sequência ao invés do código da cartela será usado para conferir as cartelas cada vez que um número for sorteado e prá isto estou usando o for next de 1 até quantas linhas tiver no arquivo ini, o terceiro arquivo é usado apenas para conferir cartela separadamente tipo quero ver quantos acertos teve na cartela PG-Q232 aí entro com o código dela e ela verifica se tem os dados no arquivo 3 se tem carrega os dados e o programa faz a conferência.

O que eu preciso fazer usando o banco de dados é isto:

1 - Criar um banco de dados que contenha aproximadamente 2.000.000 e neste banco de dados depois preciso fazer a consulta usando o código que é o número da cartela ex: PG-Q45=, caso encontre os dados guarda eles e apaga aquela linha.

2 - Criar um banco de dados com as informações que pegou do primeiro banco de dados e gravar em sequência numerando as linhas sem gravar o número da cartela no início tipo 1= linha, 2= linha... este banco de dados será lido por completo toda vez que um número for sorteado e na linha que encontar aquele número vai apagar ele de lá e manter o resto da linha

3 - Criar um banco de dados com informações idênticas as que pegou do primeiro banco de dados e será usado apenas para consulta quando entrar com o número de alguma cartela que foi cadastrada, neste não será feita nenhuma alteração quando for acesado.

 

Share this post


Link to post
Share on other sites

Oi Belini.

   Foi o que pensei. Acredito que vc esteja tentando usar o BD como substituto mais rápido dos arquivos INI, mas há a possibilidade de um melhoramento considerável aqui.

   Tu já considerastes que basta apenas um campo a mais no 1a arquivo INI, marcando a cartela como já vendida? Daí não precisaria "apagar:  do 1a INI e gravar no 2o.

   E a pesquisa, devido ao modelo TXT não ter nenhum tipo de pesquisa (afinal é apenas um monte de informação), é necessário fazer manualmente, como vc fez, através de For..Next, mas no BD vc manda ele pesquisar e pergunta se achou, simples assim!

   E a questão da estatística, também um campo incrementado pode fazer isso.

   Mas eu acho que ainda é possível que haja uma possibilidade de pesquisa das cartelas de modo diferente. Vou pensar a respeito.

   Entendeu a idéia?

Share this post


Link to post
Share on other sites

Entendi sim só que usando arquivo ini quanto maior o arquivo mais lento ele fica para ler e para gravar, esta parte da consulta ao primeiro arquivo e apagar a linha é tranquilo pois é feito um a um a medida que vai vendendo aí a melhor opção é apagar mesmo para torná-lo menor e assim mais rápido nas próximas consultas e gravações também, preciso mesmo de velocidade é no arquivo 2 que precisa conferir todas linhas contidas nele cada vez que um novo número é sorteado, para poder ir testando aqui teria como vc postar um exemplo de como encontar uma linha no banco de dados digitando apenas o código inicial e depois apagar ou modificar esta linha?

No primeiro bd preciso achar uma linha digitando um código tipo este PG-25000 ai pegar as informações desta linha depois apagar

No segundo bd preciso ler todas as linhas contidas nele identificar a linha que contem o número que foi sorteado e substituir este número por "| "

Ex: o número sorteado foi 25 e a linha contém "25 " nela ai preciso trocar por "| ", veja que procuro por 25 com espaço na frente pois na identificação pode conter 25 também ( PG-25000 ) só que nela não tem espaço aí vai trocar apenas o 25 com espaço na frente que encontrar naquela linha.

5=02 01 05 08 17 19 23 25 27 28 31 39 40 44 45 47 49 51 55 59 61 63 66 74 75 PG-Q05 10
5=02 01 05 08 17 19 23 | 27 28 31 39 40 44 45 47 49 51 55 59 61 63 66 74 75 PG-Q05 10

Quando a linha toda ficar assim  5=| | | | | | | | | | | | | | | | | | | | | | | | | PG-Q05 10 é porque os 25 números sairam então aquela cartela é a ganhadoras ou uma delas.

 

Share this post


Link to post
Share on other sites

Alterei um código que encontrei no forum americano e já consegui mostrar a linha que tem o código da cartela que preciso e também consegui pegar a linha que tem o número sorteado, agora preciso deletar esta linha quando for encontrado o código da cartela e alterar o número para "| " quando o número encontrado na linha for o número que foi sorteado, vou postar o código para ver se está correta da forma que fiz ou se tem uma maneira melhor e mais rápida para encontrar estas informações que eu preciso.

#include <SQLite.au3>
#include <array.au3>

Global $hQuery, $aRow, $sMsg, $sSql
Global $BASE_DB, $cod_cartela, $sorteado

_SQLite_Startup(@ScriptDir & "\sqlite3.dll")

If Not FileExists("database.db") Then
    $dbn = _SQLite_Open("database.db")
    _SQLite_Exec($dbn, "CREATE TABLE Dados (Numeros);")
    For $i = 1 To 10
        $dados = "PG-Q" & $i & "=02 05 06 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PG-Q" & $i & " 10"
        $sql = "INSERT INTO Dados VALUES('" & $dados & "');"
        ;_Base_Execute($sql)
        _SQLite_Exec($dbn, $sql)
    Next
Else
    $dbn = _SQLite_Open("database.db")
EndIf

$cod_cartela = 'PG-Q5'
$aResult = _SearchDatabase($cod_cartela); Procurando linha que tem o código da cartela (mostra apenas a linha que tem o código da cartela)
_ArrayDisplay($aResult)

$sorteado = '71 '
$aResult = _SearchDatabase($sorteado); Procurando linha que tem o número que foi sorteado (mostra as 10 linhas pois nas 10 tem o número "71 "
_ArrayDisplay($aResult)

_SQLite_Close()
_SQLite_Shutdown()

Func _SearchDatabase($sString)
    Local $Sql, $sSql, $aTables, $aResult, $iState
    Local $tmp1, $tmp2
    $Sql = "SELECT Numeros, ""Dados"" AS ""table"", rowid FROM  ""Dados"""
    $sSql = "SELECT * FROM (" & $Sql & ") WHERE Numeros LIKE '%" & $sString & "%';"
    $iState = _SQLite_GetTable2d(Default, $sSql, $aResult, $tmp1, $tmp2)
    If $iState <> $SQLITE_OK Then
        Return SetError(@error, 0, $iState)
    Else
        If $sString = $cod_cartela Then
            MsgBox(4096, "CÓDIGO", "Guardar a linha para gravar nos outros 2 banco de dados e apagar a linha")
        Else
            MsgBox(4096, "SORTEADO", 'Trocar a string encontrada por "| " em todas as linhas')
        EndIf
        Return $aResult
    EndIf
    Return SetError(1, 0, 0)
EndFunc   ;==>_SearchDatabase

EDITADO: Uma coisa que já ví aqui nos testes é que gravar no banco dados é muitas vezes mais lento do que gravar num arquivo .ini gastei umas 6 horas para gravar 2 milhoes de linhas em arquivos .ini e para gravar a mesma quantidade em arquivo .db gastarei dias mas isto até que não vem muito ao caso pois as cartelas serão geradas aos poucos e não tantas de uma só vez, o que me interesa mesmo é depois do banco de dados criado é ter velocidade de resposta para fazer a conferência e alteração da linha cada vez que um número for sorteado pois o tempo de sorteio entre uma pedra e outra é muito curto e neste intervalo que canta a pedra seria preciso fazer a conferência dos 2 milhões de linhas e alteração das linhas que contiverem os número sorteado, vou gravar um banco de dados com umas 50.000 linhas  apenas para testes aqui e se eu ver que dará certo gero as outras 1.000.950 linhas que faltam para fazer o teste completo.

Share this post


Link to post
Share on other sites

Consegui encontrar e apagar a linha que tem o código da cartela mas ainda não consegui substituir o número sorteado em todo banco de dados, ex: se saiu o número 21 preciso trocar "21 " por "| " em todo banco de dados, alguém sabe como fazer isto?

#include <SQLite.au3>
#include <array.au3>

Global $hQuery, $aRow, $sMsg, $sSql, $dados_linha
Global $BASE_DB, $cod_cartela, $sorteado, $retarr

_SQLite_Startup(@ScriptDir & "\sqlite3.dll")

If Not FileExists("database.db") Then
    $dbn = _SQLite_Open("database.db")
    _SQLite_Exec($dbn, "CREATE TABLE Dados (Numeros);")
    For $i = 1 To 10
        $dados = "PM-S" & $i & "=02 05 06 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PM-Q" & $i & " 10"
        $sql = "INSERT INTO Dados VALUES('" & $dados & "');"
        ;_Base_Execute($sql)
        _SQLite_Exec($dbn, $sql)
    Next
Else
    $dbn = _SQLite_Open("database.db")
EndIf

$cod_cartela = 'PM-S325 '
$aResult = _SearchDatabase($cod_cartela); Procurando linha que tem o código da cartela (mostra apenas a linha que tem o código da cartela)
If UBound($aResult) > 1 Then
    $dados_linha = $aResult[1][0]; guardar para gravar nas outras duas
    _SQLite_Exec($dbn, "DELETE FROM Dados WHERE Numeros= " & "'" & $aResult[1][0] & "'" & ";"); FUNCIONOU
    _ArrayDisplay($aResult); ESTA LINHA FOI APAGADA
Else
    MsgBox(4096, 'Sem informações', "Nenhuma informação foi encontrada!")
EndIf

$sorteado = "60 "
$trocar = "| "

_SQLite_Exec($dbn, "UPDATE Dados set Numeros= " & _SQLite_FastEscape($sorteado) & " where Numeros= " & _SQLite_FastEscape($trocar)); troca todos números por "| " ==> (!ª tentativa)
_SQLite_Exec($dbn, "UPDATE Dados set Numeros= " & "'" & $sorteado & "'" & " where Numeros= " & "'" & $trocar & "'"); troca todos números por "| "==> (2ª tentativa)
_SQLite_Exec($dbn, "UPDATE Dados SET Numeros= " & "'" & $sorteado & "'" & " where Numeros= " & "'" &  $trocar & "'" &  ";"); troca todos números por "| "==> (3ª tentativa)

$aResult = _SearchDatabase($trocar); Procurando linha que tem "| " (mostra todas as linha que tiveram os dados trocados)
If UBound($aResult) > 1 Then
    _ArrayDisplay($aResult)
Else
    MsgBox(4096, 'Sem informações', "Nenhuma informação foi encontrada!")
EndIf

_SQLite_Close()
_SQLite_Shutdown()

Func _SearchDatabase($sString)
    Local $sql, $sSql, $aTables, $aResult, $iState
    Local $tmp1, $tmp2
    $sql = "SELECT Numeros, ""Dados"" AS ""table"", rowid FROM  ""Dados"""
    $sSql = "SELECT * FROM (" & $sql & ") WHERE Numeros LIKE '%" & $sString & "%';"
    $iState = _SQLite_GetTable2d($dbn, $sSql, $aResult, $tmp1, $tmp2)
    If $iState <> $SQLITE_OK Then
        Return SetError(@error, 0, $iState)
    Else
        Return $aResult
    EndIf
EndFunc   ;==>_SearchDatabase

Banco de dados para testes com 187.240 linhas:  https://mega.nz/#!oBVGTS6C!qnsL0_lJvQCIc4dcC9L3bi0-O0YR8m43K7IADbh4oH8

Share this post


Link to post
Share on other sites

Como seria para carregar na memória um arquivo .bd do disco e depois fazer todas alterações necessárias durante o tempo que estiver usando sem salvar no disco.

#include <SQLite.au3>
#include <array.au3>

Global $hQuery, $aRow, $sMsg, $sSql, $dados_linha
Global $BASE_DB, $cod_cartela, $sorteado, $retarr

_SQLite_Startup(@ScriptDir & "\sqlite3.dll")

If Not FileExists("database.db") Then
    $dbn = _SQLite_Open("database.db")
    _SQLite_Exec($dbn, "CREATE TABLE Dados (Numeros);")
    For $i = 1 To 10
        $dados = "PM-S" & $i & "=02 05 06 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PM-Q" & $i & " 10"
        $sql = "INSERT INTO Dados VALUES('" & $dados & "');"
        ;_Base_Execute($sql)
        _SQLite_Exec($dbn, $sql)
    Next
Else
    $dbn = _SQLite_Open("database.db")
EndIf

$cod_cartela = ' PM-S2002 '
$aResult = _SearchDatabase($cod_cartela); Procurando linha que tem o código da cartela (mostra apenas a linha que tem o código da cartela)
If UBound($aResult) > 1 Then
    $dados_linha = $aResult[1][0]; guardar para gravar nas outras duas
    _SQLite_Exec($dbn, "DELETE FROM Dados WHERE Numeros= " & "'" & $aResult[1][2] & "'" & ";"); apaga a linha que tem o código da cartela
    _ArrayDisplay($aResult)
Else
    MsgBox(4096, 'Sem informações', "Nenhuma informação foi encontrada!")
EndIf

$sorteado = Random(1, 75, 1)
If $sorteado <= 9 Then
    $sorteado = " 0" & $sorteado & " "
Else
    $sorteado = " " & $sorteado & " "
EndIf
_SQLite_Exec($dbn, "UPDATE Dados set Numeros= replace(numeros, '" & $sorteado & "', ' | ') where Numeros like '%" & $sorteado & "%'"); troca todos números por " | "
$aResult = _SearchDatabase(" | "); Procurando linha que tem " | " (mostra todas as linha que tiveram os dados trocados)
If UBound($aResult) > 1 Then _ArrayDisplay($aResult)

_SQLite_Close()
_SQLite_Shutdown()

Func _SearchDatabase($sString)
    Local $sql, $sSql, $aTables, $aResult, $iState
    Local $tmp1, $tmp2
    $sql = "SELECT Numeros, ""Dados"" AS ""table"", rowid FROM  ""Dados"""
    $sSql = "SELECT * FROM (" & $sql & ") WHERE Numeros LIKE '%" & $sString & "%';"
    $iState = _SQLite_GetTable2d($dbn, $sSql, $aResult, $tmp1, $tmp2)
    If $iState <> $SQLITE_OK Then
        Return SetError(@error, 0, $iState)
    Else
        Return $aResult
    EndIf
EndFunc   ;==>_SearchDatabase

 

Share this post


Link to post
Share on other sites

Queria entender um pouco mais sobre esta questão de "gerar os cartões" que totalizariam 2 milhões de linhas.

Estes cartões já estão gerados? Estão em um arquivo INI, isso? E vc quer importar para um BD?

Se for assim, o procedimento de leitura do INI e gravação no BD vc já tem. Será demorado? Provavelmente, mas como vc mesmo disse, é uma operação que pode ser feita "off-line", ou seja, o cliente nunca vai saber que aconteceu. Vc já vai chegar com o BD pronto para ele.

Mas a minha pergunta é exatamente essa! É necessário gravar todos estes cartões antecipadamente?

Como funciona um bingo na prática? Faça de conta que vc não tem nenhum cartão gerado. Primeira vez que vc entrou num bingo.

São gerados quantos cartões? Ficam gravados porque?

 

PS. Quanto à dúvida técnica do BD em memória, basta não utilizar nenhum parâmetro no comando _SQLite_Open, daí o BD é gerado em memória.

Share this post


Link to post
Share on other sites

Outra coisa. Quem fez o post americano tbm não entendia muito de BD ou estava começando.

Em teoria, os passos são:

  1. vc abre o BD
  2. cria as tabelas internas e os relacionamentos
  3. inclue, altera, exclue ou consulta dos dados

Os passos 1 e 2 ocorrem apenas uma vez, já o 3o passo ocorre gradativamente. Por isto que eu me arrepio quando vejo o código postado.

If Not FileExists("database.db") Then
    $dbn = _SQLite_Open("database.db")
    _SQLite_Exec($dbn, "CREATE TABLE Dados (Numeros);")
    For $i = 1 To 10
        $dados = "PM-S" & $i & "=02 05 06 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PM-Q" & $i & " 10"
        $sql = "INSERT INTO Dados VALUES('" & $dados & "');"
        ;_Base_Execute($sql)
        _SQLite_Exec($dbn, $sql)
    Next
Else
    $dbn = _SQLite_Open("database.db")
EndIf

Para começo de conversa, qual a diferença entre as linhas de abertura do BD com o _SQLite_Open?

Se não existe o arquivo físico, abre o banco! E se existe, abre o banco?

Não se deve confundir a abertura e criação do BD com sua manutenção.

Eu faria assim:

; seção de abertura do BD
$dbn = _SQLite_Open("database.db")
_SQLite_Exec($dbn, "CREATE TABLE IF NOT EXIST Dados (Numeros TEXT);")
    
; seção de inclusão de dados
For $i = 1 To 10
    $dados = "PM-S" & $i & "=02 05 06 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PM-Q" & $i & " 10"
    $sql = "INSERT INTO Dados VALUES('" & $dados & "');"
    _SQLite_Exec($dbn, $sql)
Next

 

Observe:

  • a clásula IF NOT EXIST no comando CREATE TABLE (assim cria somente se a tabela não existir, evitando que a tabela seja zerada toda vez)
  • o tipo TEXT para definição do campo Numeros. Apesar de opcional, é sempre importante colocar.

Neste caso, o BD seria aberto, criado se necessário o arquivo físico e a(s) tabela(s) internas.

Em um segundo momento, os dados seriam incluídos. Claro que olhando para o script, os dados seriam inclusos sempre, por isso que a inclusão só poderia acontecer em um script separado para alimentar o BD inicialmente (recomendado) ou uma condição que permitisse a inserção dos dados na tabela apenas uma única vez.

; seção de abertura do BD
$dbn = _SQLite_Open("database.db")
_SQLite_Exec($dbn, "CREATE TABLE IF NOT EXIST Dados (Numeros TEXT);")

Local $aRegistro
; verifica se tem alguma coisa no BD
_SQLite_QuerySingleRow($dbn, "SELECT COUNT(Numeros) FROM Dados;", $aRegistro)
If $SQLITE_OK and not $aRegistro[0] Then ; se não existir NENHUM cartão, insere os dados
   ; seção de inclusão de dados
   For $i = 1 To 10
       $dados = "PM-S" & $i & "=02 05 06 08 15 20 23 26 28 30 35 36 38 43 45 47 52 54 55 56 66 68 71 74 75 PM-Q" & $i & " 10"
       $sql = "INSERT INTO Dados VALUES('" & $dados & "');"
       _SQLite_Exec($dbn, $sql)
   Next
EndIf

 

Ok, agora temos um procedimento adequado para criar e inserir os dados (se necessário).

Para criar um BD em memória basta mudar a linha

$dbn = _SQLite_Open("database.db")

para

$dbn = _SQLite_Open()

Porém, daí todos os dados colocados no BD desaparecerão quando e se o programa fechar ou a máquina desligar/reiniciar, etc

Em compensação, as operações são super rápidas.

 

Mas eu acho que a sua cartela pode ser desdobrada em campos menores. Seguindo o post anterior, me explique tbm o que são os nros?

  • PM-S 1,2,3, etc - o que é?
  • = 02 05 06 08 etc - imagino que são os nros sorteados na cartela
  • PM-Q 1,2,3, etc - o que é?

Pensei numa ideia maluca aqui, vamos ver se vinga ;)

Share this post


Link to post
Share on other sites

@manimal eu gero as cartelas para serem vendidas antecipadamente e uso os dados que gravei em arquivo ini ou no caso agora no banco de dados para fazer a conferência de todas que foram vendidas e desta forma ninguém passa batido e nem precisa estar presente para concorrer por isto preciso já ter o banco de dados pronto sendo que no primeiro estarão as que não formam vendidas pois apaga a linha dele toda vez que uma cartela é cadastrada e nos outros dois tem todas que estão concorrendo sendoa número 2 usada para conferir os números que sairam e a 3 apenas para consulta, eu sei que se eu não indicar um banco de dados ele será criado na memória só que não quero criar e sim carregar um que já tenho salvo no disco e depois usar ele na memória sem salavar nada no disco.

EDITADO:  PM-S  e PM-Q é a identificação da cartela "S" é quando tem 6 sorteios na mesma cartela e Q" é quando tem apenas 4 sorteios o que vem depois é número daquela cartela e usando este código tenho aceso a todos números contidos naquela cartela para poder fazer a conferência dela.

Share this post


Link to post
Share on other sites

Entendi a questão da memória, mas daí não tem jeito de fazer isso diretamente.

Vc trá que criar um "clone" do banco em memória e importar o conteúdo do BD em disco e a partir daí trabalhar só com o da memória.

E se necessário, fazer as alterações em disco a medida que acontecem. Eu tenho um script assim.

Ao iniciar, carrego todo o banco em memória, daí todas as consultas são no BD em memória e faço as gravações (eventuais) em disco simultaneamente.

 

E os cartões? Como são divididos?

Share this post


Link to post
Share on other sites

@manimal o que eu preciso é clonar o banco de dados para memória e fazer alterações nele apenas na memória também, não preciso gravar mais nada fisicamente depois que ele estiver carregado na memória porém preciso substituir os números sorteados em todo banco de dados que estiver na memória o outro bd será aberto físicamente quando precisar fazer alterações e o que fizer será salvo nos 2 fisicamente mas isto é fora da hora do sorteio, quando inicia o sorteio os 2 serão fechados com todas alterações que foram feitas e será carregada uma cópia do banco 2 apenas para conferencia dos números sorteados, ou seja terei 2 banco de dados sendo que um contém os dados das cartelas que não vendeu e o outro dados das vendidas aí quando vou cadastrar cartelas abro os dois fisicamente e faço alterações neles, quando inicia o sorteio os dois são fechados e preciso carregar as informações do banco 2 na memória para conferir os números que forem sendo sorteados sendo que preciso substituir o número sorteado por " | "  de todo banco de dados mas apenas na memória, vc pode postar um exemplo de como usa o seu banco de dados na memória?

 

Share this post


Link to post
Share on other sites

Para clonar o banco de dados em memória, tem várias opções. Todas dá no mesmo, mas vc escolhe a melhor.

Opção 1 (a mais rápida):

#include <Sqlite.au3>

; inicializa SQLite
_SQLite_Startup()
Local $hBD_Mem = _SQLite_Open()

; importa os dados
_SQLite_Exec($hBD_Mem, "ATTACH DATABASE '" & @ScriptDir & "\BancoDeDados.db' as Original;")
_SQLite_Exec($hBD_Mem, "CREATE TABLE Dados AS SELECT * FROM Original.Dados;")
_SQLite_Exec($hBD_Mem, "DETACH DATABASE Original;")

; fecha tudo
_SQLite_Close($hBD_Mem)
_SQLite_Shutdown()

 

Opção 2 (a intermediária), precisa saber a estrutura do banco. É útil quando vc precisa mudar a estrutura ou precisa pegar apenas alguns campos:

#include <Sqlite.au3>

; inicializa SQLite
_SQLite_Startup()
Local $hBD_Mem = _SQLite_Open()

; importa os dados
_SQLite_Exec($hBD_Mem, "ATTACH DATABASE '" & @ScriptDir & "\BancoDeDados.db' as Original;")
_SQLite_Exec($hBD_Mem, "CREATE TABLE IF NOT EXISTS Dados (Numeros TEXT);")
_SQLite_Exec($hBD_Mem, "INSERT INTO Dados SELECT * FROM Original.Dados;")
_SQLite_Exec($hBD_Mem, "DETACH DATABASE Original;")

; fecha tudo
_SQLite_Close($hBD_Mem)
_SQLite_Shutdown()

 

Opção 3 (a mais lenta), mas é a que permite mostrar alguma coisa tipo uma barra de progresso. Útil quando a tabela é muito grande.

#include <Sqlite.au3>

; inicializa SQLite
_SQLite_Startup()
Local $hBD_Mem = _SQLite_Open()
Local $hBD_Disco = _SQLite_Open(@ScriptDir & "\BancoDeDados.db")
If @error Then
   ConsoleWrite("Erro na abertura do banco de dados" & @CRLF)
   Exit
EndIf

; seção que carrega a tabela em memória (array)
Local $aConsulta, $nLinhas, $nColunas
SplashTextOn("", "Inicializando banco de dados...", 600, 100, -1, -1, 1 + 32, "", 24)
Local $nResultado = _SQLite_GetTable2d($hBD_Disco, "SELECT * FROM Dados;", $aConsulta, $nLinhas, $nColunas)
Sleep(1000)
SplashOff()

; importa os dados
If $nResultado = $SQLITE_OK Then
   Local Enum $DB_NUMEROS
   ProgressOn("Atenção!", "Carregando banco de dados...", "0%")
   _SQLite_Exec($hBD_Mem, "CREATE TABLE IF NOT EXISTS Dados (Numeros TEXT);")
   For $nIndice = 1 to $nLinhas
      ProgressSet($nIndice / $nLinhas * 100, Round($nIndice / $nLinhas * 100, 2) & '%')
      _SQLite_Exec($hBD_Mem, 'INSERT INTO Dados (Numeros) VALUES ("' & $aConsulta[$nIndice][$DB_NUMEROS] & '");')
   Next
   ProgressSet(100, '100%')
   Sleep(250)
   ProgressOff()
EndIf

; fecha tudo
_SQLite_Close($hBD_Mem)
_SQLite_Close($hBD_Disco)
_SQLite_Shutdown()

 

Share this post


Link to post
Share on other sites

Fiz testes usando a primeira opção e foi super rápido depois abri o banco de dados original no DB Browser for SQLite.exe e realmente ele permaneceu inalterado ou seja funcionou usando a cópia na memória e muitas vezes mais rápido que antes, agora preciso apenas melhorar a velocidade de criação do banco de dados quando os números são sorteados, estou gravando linha por linha vc tem alguma sugestão de como armazenar e gravar várias de uma vez só ou outra solução para diminuir o tempo de criação do banco de dados?

Share this post


Link to post
Share on other sites

Buenas!

   Sempre que falamos em clonar um banco em memória, nosso objetivo é melhorar o tempo de resposta para funções de massa, como grandes e complexas consultas por exemplo, que talvez ao serem efetuadas a partir do disco (BD original) possam resultar bem mais lentas para apresentar os resultados. Grandes alterações no banco como inserção em massa de dados, alterações ou exclusões também podem ocorrer.

   Então, ao clonarmos o BD para a memória, temos que ter em mente que eventuais alterações feitas na memória podem ter 2 (dois) destinos:

  1. são ignoradas, ou seja o BD serve apenas para SELECTs e o que vale é o BD em disco;
  2. precisam ser salvas, ou seja, em algum momento, precisam ser descarregadas/efetivadas/replicadas em disco.

   Na opção 1, o problema está resolvido. Ignora-se o BD em memória e tudo bem!

   Na opção 2 o buraco é bem mais embaixo. Aqui temos novamente 2 (duas) possibilidades:

  • efetivamos as alterações à medida que acontecem! Pessoalmente é a que eu utilizo por algumas razões:
  1. mantenho o BD em memória igual ao BD no disco (sincronização);
  2. caso ocorra alguma falha no equipamento (reset, falta de luz, travamento, etc) as alterações estão seguras;
  3. ao iniciar o script, carrego novamente o BD em memória, sabendo que é a última versão das informações e parto disto;
  4. não preciso me preocupar em descarregar as alterações posteriormente (no final do programa ou em algum ponto definido) e neste momento qualquer ganho de tempo que eu tive, foi por água abaixo, pois o tempo de gravação em disco de todas as alterações é enorme.

   Como fazemos isso?
   Após a clonagem do BD em memória, qualquer alteração ao ser executada, deve ser feita tanto em memória como em disco.
 

#include <Sqlite.au3>

; incializa SQLite
_SQLite_Startup()

; Abre BD em mmória
Local $hBD_Mem = _SQLite_Open()

; Abre BD em disco
Local $hBD_Disco = _SQLite_Open(@ScriptDir & "\BancoDeDados.db")

; ...
; Faz a clonagem conforme as técnicas explicadas em post anterior
; ...

; faz as eventuais alterações no BD mem e no BD disco
_SQLite_Exec($hBD_Mem, "UPDATE Tabela SET Estado = "SC" WHERE Codigo = 425;")
_SQLite_Exec($hBD_Disco, "UPDATE Tabela SET Estado = "SC" WHERE Codigo = 425;")

; faz as eventuais alterações no BD mem e no BD disco
_SQLite_Exec($hBD_Mem, "DELETE FROM Tabela WHERE Idade < 18;")
_SQLite_Exec($hBD_Disco, "DELETE FROM Tabela WHERE Idade < 18;")

; fecha tudo
_SQLite_Close()
_SQLite_Shutdown()

   Desta forma, mantemos os dois bancos de dados iguais e atualizados. E quaisquer consultas (SELECTs) devem ser feitos diretamente no BD em memória para obter um ganho considerável de velocidade!

 

  • A outra possibilidade envolve não manter os 2 (dois) bancos equiparados ou sincronizados, mas fazer as alterações somente em memória e depois de tudo pronto, descarregar o BD da memória em disco.

   Este procedimento pode ser feito a qualquer momento, mas normalmente é efetivado na saída do programa (final do script).
   Para tanto, infelizmente não há um comando ou comandos que possam fazer isto rapidamente.
   Felizmente a partir da versão 3.6.x do SQLite, foi implemntadado a API de Backup, que permite fazer cópia do banco "on-the-fly" (com o banco aberto e operando).
   No fórum americano, tem um tópico sobre isto (cortesia do Belini que achou) e também tem uma função para fazer o backup:
   Se quiser ver o tópico original = https://www.autoitscript.com/forum/topic/108151-sqlite-backup-api-wrapper/
   Vou anexar aqui uma versão modificada da original, já contendo as alterações sugeridas pelos integrantes do fórum naquele tópico e com algumas modificações minhas também.

   Para utilizar a função de Backup é bem simples. Segue exemplo:
 

#include <Sqlite.au3>
#include "sqlitebackup.au3"

; incializa SQLite
_SQLite_Startup()

; Abre BD em mmória
Local $hBD_Mem = _SQLite_Open()

; Abre BD em disco
Local $hBD_Disco = _SQLite_Open(@ScriptDir & "\BancoDeDados.db")

; ...
; Faz a clonagem conforme as técnicas explicadas em post anterior
; ...

; faz as eventuais alterações SOMENTE na memória
_SQLite_Exec($hBD_Mem, "UPDATE Tabela SET Estado = "SC" WHERE Codigo = 425;")

; faz as eventuais alterações SOMENTE na memória
_SQLite_Exec($hBD_Mem, "DELETE FROM Tabela WHERE Idade < 18;")

; faz o backup do BD em memória de volta para o disco (recomendado ao final do script)
_SQLite_Backup($hBD_Mem, @ScriptDir & "\BancoDeDadosCOPIA.db")

; fecha tudo
_SQLite_Close()
_SQLite_Shutdown()

 

   Mas conversando com um outro colega (meu ex-orientandor de mestrado) que é DBA, ele me comentou que alguns engines DBs aproveitam comandos de manutenção do banco (que exigem controle total sobre o mesmo) para efetivar algum tipo de cópia. Assim, fui pesquisar na documentação do SQLite e o comando VACUUM, que serve para fazer uma lmpeza interna do banco, a partir da versão 3.27 possui uma cláusula INTO que faz exatamente isto!

   Agora temos 2 (duas) opções de salvar o banco de dados da memória em disco. Faca os testes e veja qual a melhor (ou a mais rápida) que serve para o seu caso. A vantagem é que não precisa de uma função externa.
 

#include <Sqlite.au3>

; incializa SQLite
_SQLite_Startup()

; Abre BD em mmória
Local $hBD_Mem = _SQLite_Open()

; Abre BD em disco
Local $hBD_Disco = _SQLite_Open(@ScriptDir & "\BancoDeDados.db")

; ...
; Faz a clonagem conforme as técnicas explicadas em post anterior
; ...

; faz as eventuais alterações SOMENTE na memória
_SQLite_Exec($hBD_Mem, "UPDATE Tabela SET Estado = "SC" WHERE Codigo = 425;")

; faz as eventuais alterações SOMENTE na memória
_SQLite_Exec($hBD_Mem, "DELETE FROM Tabela WHERE Idade < 18;")

; faz o backup do BD em memória de volta para o disco (recomendado ao final do script) aproveitando o comando interno VACUUM
_SQLite_Exec($hBD_Mem, "VACUUM INTO '" & @ScriptDir & "\BancoDeDadosCOPIA.db'")

; fecha tudo
_SQLite_Close()
_SQLite_Shutdown()

 

   Quanto à eficiência de gravação de volta em disco, temos que lembrar que estas funções, tanto a do SQLite como a do backup da SQLite, foram desenvolvidas tendo em mente uqe estes bancos estariam abertos, sendo utilizados por mais de 1 (um) usuário, portanto durante o procedimento de fazer a cópia, é possível que haja alterações por parte de outros usuários, sendo assim, a cópia já nasceria desatualizada. A API do Backup prevê isso e se necessário, recomeça a cópia par refletir estas alterações.


   Porém naturalmente que dependendo da quantidade de usuários conectados ou das alterações que estão sendo feitas, a cópia pode demorar eternamente!

   Outro ponto interessante a ser verificado é que o 5o (quinto) parâmetro da função de Backup é o tamanho do bloco que deve ser copiado. E por tamanho do bloco, temos que olhar a estrutura interna do banco de dados para entendermos melhor este parâmetro e o porque da fixação dele em 16.

   Todo banco de dados, internamente, possui as informações gravadas em blocos como se fossem páginas de um livro. Dentro da página tem as várias informações de vários registros.

   O procedimento de backup faz cópia de "x" folhas por vez (padrão de 16). Assim caso alguma dessas folhas sejam modificadas, ela recopia somente estas folhas que estão no bloco.

   Em teoria, quanto menor este bloco melhor, pois estaríamos reduzindo a recópia (se necessário), porém ao reduzirmos o tamanho do bloco, também aumentamos o tempo necessário para copiar tudo.

   Assim, aumentar o tamanho do bloco faz com que a cópia seja mais rápida, mas mais sujeita a recópias.

   Dependendo da situação, e eu estou imaginando que em 90% (ou mais) dos casos de SQLIte com AutoIt, os bancos são praticamente exclusivos, não tem niguém além do próprio script mexendo e também não há vários scripts rodando simultameamente na rede.

   Se for este o seu caso, pode aumentar o nro de blocos para 256 para obter uma melhor performance na cópia do banco ou até mesmo colocar o valor de -1, para que seja usada a velocidade máxima.

   Mas muito cuidado com estes parâmetros. Eles devem ser cuidadosamente considerados em razão do ambiente em que o banco de dados está sendo executado.
 

_SQLite_Backup($hBD_Mem, $sCopiaBD, Default, Default, 256)

ou

_SQLite_Backup($hBD_Mem, $sCopiaBD, Default, Default, -1)

 

SQLitebackup.au3

  • Thanks 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

×