Clipper On Line • Ver Tópico - Tutorial de SQL
Página 1 de 4

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 12:07
por JoséQuintas
O SQL é simples, tem os comandos e funções básicos, mas que podem ser combinados pra muita coisa mais complexa.

Incluir:

INSERT INTO clientes ( codigo, nome ) VALUES ( 10, 'JUCA' )

excluir:

DELETE FROM clientes WHERE codigo = 10
DELETE FROM clientes WHERE nome = 'JUCA'

atualizar:

UPDATE clientes SET nome = 'JOAO' where codigo = 10

muito cuidado na exclusão/atualização, porque diferente do DBF, se não indicar o que está querendo alterar, ele altera TUDO.

Este comando altera TODOS os clientes pra 'JOAO'

UPDATE clientes SET nome = 'JOAO'

E o principal, justamente a potência do SQL, buscar informações: SELECT

SELECT * FROM clientes

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 12:11
por JoséQuintas
Um exemplo simples de combinação;

INSERT INTO fornecedores SELECT * FROM clientes

Vai incluir na tabela fornecedores, tudo que existe em clientes.

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 12:18
por JoséQuintas
Acho que a parte mais difícil pra nós que estamos acostumados com Harbour/DBF, é sobre algumas funções pra banco de dados, e não pra fórmulas.

Um bom exemplo disso são MAX( VALOR ), MIN( VALOR )

Tudo bem, é pra retornar o maior ou menor valor, mas NÃO de uma fórmula matemática, mas do banco de dados.

Isso vai retornar o maior código de clientes existente na tabela.

SELECT MAX( CODIGO ) FROM clientes

Mas... e se eu quiser uma fórmula pra ter o maior ou menor valor entre dois números, não dá pra usar o MAX()?
Não.
Pra isso, tem o GREATEST() ou LEAST(), que são funções matemáticas pra maior ou menor.

Isso é uma coisa que demora pra se acostumar, ainda mais que no código fonte Harbour vamos continuar usando Max(), e vai ser sempre a primeira opção que vém na cabeça.

Mas de quebra, essas funções tem vantagem sobre as do Harbour: não se limita a apenas dois números

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 12:24
por JoséQuintas
Convém destacar aqui, que nem todo SQL é exatamente igual.

Por exemplo, pra pegar os primeiros 10 registros de uma tabela:

SELECT * FROM tabela ORDER BY codigo LIMIT 10

Mas no SQL Server é diferente

SELECT TOP 10 * FROM tabela ORDER BY codigo

Mas tranquilo, muita coisa é padronizada, não se perde todo conhecimento de SQL ao trocar de banco de dados, apenas se ajustam algumas diferenças.

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 12:38
por JoséQuintas
Agora sobre o SELECT

Isso vai longe, porque as possibilidades são infinitas.
O que pedir é o que o servidor vai retornar, não importa se vém de 1 tabela, 1000 tabelas, se os valores são cálculos encima das tabelas, etc. etc. etc.

O mais comum é pedir de uma tabela, com um filtro e em determinada ordem

SELECT codigo, nome FROM clientes WHERE codigo < 10 ORDER BY nome

Pra que perder tempo escolhendo nome de campo, se dá pra trazer tudo de uma vez?

Exatamente por esse motivo: pra que trazer tudo, se só precisa de duas informações de cada cliente?
Tempo de rede é importante, quanto menos informação melhor, porque usa menos rede.
É trazer exatamente o que precisa, e nada mais

Quer saber a quantidade de clientes... Não precisa nem trazer os clientes, basta perguntar pro servidor

SELECT COUNT(*) AS QTD FROM clientes

Numa consulta pelo HEIDISQL não precisa, mas pelo aplicativo, vai precisar de um nome para pegar a informação.
No comando acima, vém o campo QTD que vai conter o total de registros em clientes

Basicamente esse "AS QTD" é pra dizer que esse nome vai ser o nome desse "cálculo".

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 13:56
por JoséQuintas
Total de vendas por mes
Se é por mês, precisamos dizer pro MySQL como ele obtém o mes, assim como ele retornar o mes

Há várias opções, algumas delas

SELECT DATE_FORMAT( DATA, '%Y-%m' ), SUM( VALOR )
FROM VENDAS
GROUP BY DATE_FORMAT( DATA, '%Y-%m' )

SELECT YEAR( DATA ), MONTH( DATA ), SUM( VALOR )
FROM VENDAS
GROUP BY YEAR( DATA ), MONTH( DATA )

SELECT CONCAT( LPAD( YEAR( DATA ), 4, '0' ), '-', LPAD( MONTH( DATA ), 2, '0' ) ), SUM( VALOR )
FROM VENDAS
GROUP BY CONCAT( LPAD( YEAR( DATA ), 4, '0' ), '-', LPAD( MONTH( DATA ), 2, '0' ) )

SELECT CONCAT_WS( '-', LPAD( YEAR( DATA ), 4, '0' ), LPAD( MONTH( DATA ), 2, '0' ) ), SUM( VALOR )
FROM VENDAS
GROUP BY CONCAT_WS( '-', LPAD( YEAR( DATA ), 4, '0' ), LPAD( MONTH( DATA ), 2, '0' ) )

De um jeito ou de outro, obtemos o resultado
Qual deles é melhor? sei lá... ainda não me preocupei com isso, mas o primeiro parece mais prático

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 14:41
por JoséQuintas
Também dá pra selecionar do que foi selecionado, é chamado de sub-select

Primeiro um detalhe no comando anterior: faltou dar um nome para as "novas colunas"

SELECT 
DATE_FORMAT( DATA, '%Y-%m' ) AS MES,
SUM( VALOR ) AS SOMA
FROM VENDAS
GROUP BY DATE_FORMAT( DATA, '%Y-%m' )


Se esse vai ser um sub-select, também precisamos dar um nome a esse "temporario".
Ele vai acabar sendo usado assim

( SELECT 
DATE_FORMAT( DATA, '%Y-%m' ) AS MES,
SUM( VALOR ) AS SOMA
FROM VENDAS
GROUP BY DATE_FORMAT( DATA, '%Y-%m' )
)
AS PRIMEIROSELECT

Podemos fazer depois

SELECT MES, SOMA FROM ( Aqui_Entra_o_Comando_Acima ) AS PRIMEIROSELECT


Note que o select usa os nomes resultado do comando anterior.
NÃO pode usar nome repetido, existente na(s) tabela(s) usada(s) no comando, já que no caso de nome repetido o SQL não vai saber a qual deles se refere.
Muita atenção nisso. Tudo depende de como o comando é formado, há casos onde pode fazer isso, desde que esteja claro de onde vém a informação.
Com certeza, em cada resultado não pode ter nome repetido, mas podemos usar o AS pra trocar o nome.
SELECT MES, MES AS OUTROMES, SOMA, SOMA AS OUTRASOMA FROM ( Aqui_Entra_o_Comando_Acima ) AS PRIMEIROSELECT

o resultado vão ser os campos mes, outromes, soma, outrasoma

Que tal mostrar isso acima, um mês por coluna? 2020-07 2020-06 2020-05
E que tal um cliente por linha?

Tá, tudo bem, mas antes disso vamos a uma coisa importante:
Vamos mostrar só os meses 5, 6 e 7? Então não precisamos somar tudo, só os valores destes três meses.
E o melhor é alterar no que faz a soma, pra não ter tanta informação na memória do MySQL, antes de fazer o resto
SELECT 
CLIENTE, DATE_FORMAT( DATA, '%Y-%m' ) AS MES, SUM( VALOR ) AS SOMA
FROM VENDAS
WHERE DATA BETWEEN '2020-05-01' AND 2020-07-31'
GROUP BY CLIENTE, DATE_FORMAT( DATA, '%Y-%m' )

Pronto.
Agora vamos ao select encima desse select
SELECT
CLIENTE,
SUM( IF( MES = '2020-07', SOMA, 0 ) ) AS JULHO,
SUM( IF( MES = '2020-06', SOMA, 0 ) ) AS JUNHO,
SUM( IF( MES = '2020-05', SOMA, 0 ) ) AS MAIO
FROM ( O_SELECT_ACIMA ) AS PRIMEIROSELECT
GROUP BY CLIENTE

Nada extraordinário, usa o valor, se o valor pertencer à coluna
O detalhe a mais aqui, é que precisa agrupar por cliente, senão vai continuar saindo um mês em cada linha, por isso o group by

O comando inteiro:
SELECT
   CLIENTE,
   SUM( IF( MES = '2020-07', SOMA, 0 ) ) AS JULHO,
   SUM( IF( MES = '2020-06', SOMA, 0 ) ) AS JUNHO,
   SUM( IF( MES = '2020-05', SOMA, 0 ) ) AS MAIO
FROM
   (
   SELECT
      CLIENTE, DATE_FORMAT( DATA, '%Y-%m' ) AS MES, SUM( VALOR ) AS SOMA
   FROM VENDAS
   WHERE DATA BETWEEN '2020-05-01 AND 2020-07-31'
   GROUP BY CLIENTE, DATE_FORMAT( DATA, '%Y-%m' )
   ) AS PRIMEIROSELECT

GROUP BY CLIENTE

Lógico, não precisa ser nome grande, pode ser A, ao invés de PRIMEIROSELECT

Mas aqui já deu pra ter uma idéia de como as possibilidades são infinitas.

A partir daí, é pesquisar funções disponíveis, e tudo que pode ser feito.

Mas faltou uma coisa:
NÃO está limitado a uma tabela por vez, podemos buscar qualquer coisa de qualquer lugar, junto, misturado, relacionado, etc. etc.
É TUDO, qualquer informação de qualquer lugar, usando um único comando, tanto faz se a informação está parte em uma tabela ou parte em outra, ou de várias tabelas separadas.... é um único comando trazendo tudo de todas.

Nota: fui escrevendo os comandos durante o post, pode ter algum erro, mas é lógico... quando chegar a hora de usar, uma pesquisa rápida resolve qualquer eventual problema.

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 14:55
por JoséQuintas
No comando acima
É interessante ter o nome dos clientes.
O que precisa?
o nome do campo, e fazer algum tipo de relacionamento entre o código desta tabela com o código da tabela de clientes

SELECT
   CLIENTE,
   TABCLI.NOME,
   SUM( IF( MES = '2020-07', SOMA, 0 ) ) AS JULHO,
   SUM( IF( MES = '2020-06', SOMA, 0 ) ) AS JUNHO,
   SUM( IF( MES = '2020-05', SOMA, 0 ) ) AS MAIO
FROM
   (
   SELECT
      CLIENTE, DATE_FORMAT( DATA, '%Y-%m' ) AS MES, SUM( VALOR ) AS SOMA
   FROM VENDAS
   WHERE DATA BETWEEN '2020-05-01 AND 2020-07-31'
   GROUP BY CLIENTE, DATE_FORMAT( DATA, '%Y-%m' )
   ) AS PRIMEIROSELECT
INNER JOIN TABCLI ON TABCLI.CODIGO = PRIMEIROSELECT.CLIENTE
GROUP BY CLIENTE
ORDER BY NOME


A atenção nisso é o seguinte:

INNER JOIN TABCLI ON TABCLI.CODIGO = PRIMEIROSELECT.CLIENTE

porque relacionei com o primeiro resultado e não com vendas?
porque pra somar cada um, não interessa o nome do cliente, seria só perda de tempo, então faço o relacionamento no "temporario" dos totais

e porque não relacionar com cliente do SELECT principal?
o select principal não existe, ele vai ser resultado da pesquisa.
Como ele vai ser encima do "primeiroselect", é exatamente esse que está disponível para o select principal/final e para fazer o relacionamento.

o resultado vai ser clientes em ordem alfabética, mostrando as vendas de cada mês, um em cada coluna.
Resultado pronto pra um browse/grid, ou pra um relatório.

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 15:04
por JoséQuintas
Sou um quase principiante ensinando outros principiantes.

Considerem tudo apenas como didático, e não como forma de usar na prática.
Ainda estou aprendendo também... e pode ter jeito mais prático pra fazer essas mesmas coisas.
Quando minhas bases estiverem com milhões de registros vou poder dizer se tem jeito mais rápido pra isso.
Por enquanto, com algumas centenas de milhares de registros, tá atendendo bem.

Pra curiosidade.... no ADO isso é usado assim:

oResultado := oConexao:Execute( "comando SQL" )

Manda o comando pro servidor, e o servidor executa o comando e devolve o que o comando pediu.

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 15:55
por JoséQuintas
Só reforçando novamente:

É o servidor SQL quem executa os comandos
Pode ser servidor MySQL, SQL Server, Firebird, etc.

E se é o servidor quem vai fazer o trabalho pesado....
tanto faz se usar ADO, SQLMIX, RDDSQL, etc. a velocidade vai ser a mesma.

Trata-se apenas de gosto pessoal, e de usar comandos SQL... se não usar comandos SQL não vai tirar vantagem nenhuma do servidor.

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 18:27
por Fernando queiroz
cQuery1:="SELECT  "
   cQuery1+="FORPRO.PRODUTOS_ID,  "
   cQuery1+="FORPRO.DESPRO, "
   cQuery1+="produtos.TIPUNI,  "
   cQuery1+="produtos.PRECUS, "
   cQuery1+="produtos.ESTATU, "
   cQuery1+="produtos.ESTL02, "
   cQuery1+="ROUND((SUM(pedidositens.QTDPRO) / " + STRZERO(DAY(M->DAT_HOJE),2,0) + ") * " + STRZERO(PRAZO,3,0) + ") - (produtos.ESTATU + produtos.ESTL02) AS QTDPRO "
   cQuery1+="FROM ( "
   cQuery1+="SELECT DISTINCT forpro.FORNECEDOR_ID, forpro.PRODUTOS_ID, forpro.DESPRO "
   cQuery1+="FROM forpro ) AS FORPRO "
   cQuery1+="LEFT JOIN pedidositens ON pedidositens.PRODUTOS_ID = forpro.PRODUTOS_ID  "
   cQuery1+="JOIN pedidos ON DATE_FORMAT( pedidos.DATVEN, '%Y-%m') = '" + + STRZERO(YEAR(M->DAT_HOJE),4,0) + "-" + STRZERO(MONTH(M->DAT_HOJE),2,0) + +  "' AND pedidos.ST = '0' AND pedidos.PEDIDOS_Id = pedidositens.PEDIDOS_ID   "
   cQuery1+="LEFT JOIN produtos ON PRODUTOS.PRODUTOS_Id = forpro.PRODUTOS_ID  "
   cQuery1+="WHERE FORPRO.FORNECEDOR_ID = '" + STRZERO(nFORNECEDOR_ID,11,0) + "' "
   cQuery1+="GROUP BY forpro.PRODUTOS_ID  "
   cQuery1+="HAVING SUM(pedidositens.QTDPRO) > 0 AND (ROUND((SUM(pedidositens.QTDPRO) / " + STRZERO(DAY(M->DAT_HOJE),2,0) + ") * " + STRZERO(PRAZO,3,0) + ") - (produtos.ESTATU + produtos.ESTL02)) > 0  "
   cQuery1+="ORDER BY forpro.DESPRO "


demorei mas fiz essa query meio cabeluda, show de resultado , calcula o que deve ser comprado de um determinado fornecedor baseado nas vendas dos produtos fornecidos por ele, e usando um prazo e os produtos vendidos por data, pegando a data de venda do arquivo de PEDIDOS e os itens do arquivo de PEDIDOSITENS, verificando se o PEDIDO nao foi cancelado e se o calculo de compra foi maior que zero.

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 19:27
por JoséQuintas
Vai devagar aí, acho que tem coisa errada nisso.

Ao que parece, forpro tem todo mundo que pode fornecer produto.
Significa que se rodar um fornecedor de cada vez, pode comprar a mesma coisa de todos.

Usar o dia de hoje apenas, pode ser interessante no final do mês, e com isso a query fica presa a isso
Talvez mais interessante usar um período, últimos 30 dias por exemplo.

Se isto realmente for necessário:

"SELECT DISTINCT forpro.FORNECEDOR_ID, forpro.PRODUTOS_ID, forpro.DESPRO " + ;
"FROM forpro ) AS FORPRO " + ;

talvez melhor selecionar apenas o fornecedor que interessa WHERE FORNECEDOR_ID = variavel

Não sei se poderia ser mais interessante trazer os totais e depois um select pra preencher o que falta e fazer os cálculos adicionais

Como você mesmo disse, é cabeludo, e difícil pegar os detalhes.

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 20:15
por JoséQuintas
não sei se entendi as tabelas
usando 30 dias pro cálculo

SELECT pedidositens.produtos_id, forpro.fornecedor_id, forpro.despro, 
produtos.precus, produtos.estatu, produtos.estl02,
SUM( pedidositens.qtdpro ) as vendido,round( sum( pedidositens.qtdpro ) * @prazo - ( produtos.estatu + produtos.estl02 ), 0 )

from pedidositens

inner join foxpro on forpro.produtos_id = pedidositens.produtos_id
inner join pedidos on pedidos.pedidos_id = pedidositens.pedidos_id
inner join produtos on produtos.produtos_id = pedidositens.produtos_id

where pedidos.datven between date_sub( curdate(), interval 31 day ) and date_sub( curdate(), interval 1 day )
and pedidos.st = '0'
and forpro.fornecedor_id = @IdFornecedor

group by pedidositens.produtos_id

having round( sum( pedidositens.qtdpro ) * @prazo - ( produtos.estatu + produtos.estl02 ), 0 ) > 0;

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 20:26
por JoséQuintas
O detalhe das variáveis, das duas uma: ou altera o comando via fonte, ou cria e destrói variáveis no mysql.
E significa enviar os comandos, um de cada vez, antes de depois do anterior

SET @idfornecedor = 10
SET @prazo = 20
..... comando anterior
SET @idFornecedor = NULL
SET @prazo = NULL

No heidisql ele executa um de cada vez, e dá a impressão de que o MySQL aceita

Tutorial de SQL

MensagemEnviado: 28 Jul 2020 21:22
por Fernando queiroz
Por incrível que pareça a coisa esta funcionando certinho, fiz vários testes com fornecedores variados e trouxe somente os certos, fiz o teste de São Tomé , na caneta e bateu certinho os cálculos , a única coisa que que também tive observações foi a questão do ANO/MES , mas era da forma que eles calculam.

Tutorial de SQL

MensagemEnviado: 29 Jul 2020 11:39
por Mario Mesquita
Bom dia a todos.

Quintas, vc citou o SQL Server. É o da Microsoft, né?

Dá pra usar no Harbour numa boa? Um amigo meu usa e recomenda, pq com ele deu tudo certo quando teve que deixar os DBFs.

Mas ele usa Visual Fox, aqui vejo que usam muito o MySql e que tem coisa pronta pra uso no Harbour.

Pessoalmente nada contra, sempre me vi usando o MySql, mas ele falou tanto do SQL Server...

Saudações,
Mario.

Tutorial de SQL

MensagemEnviado: 29 Jul 2020 14:19
por JoséQuintas
Mario Mesquita escreveu:Quintas, vc citou o SQL Server. É o da Microsoft, né?
Dá pra usar no Harbour numa boa? Um amigo meu usa e recomenda, pq com ele deu tudo certo quando teve que deixar os DBFs.
Mas ele usa Visual Fox, aqui vejo que usam muito o MySql e que tem coisa pronta pra uso no Harbour.
Pessoalmente nada contra, sempre me vi usando o MySql, mas ele falou tanto do SQL Server...


Cada um tem o gosto pessoal.
Estou usando o ADO da Microsoft.
A única coisa que precisa do Harbour é: oConexao := win_OleCreateObject( "ADODB.Connection" )

o ADO e o SQLMIX trabalham com ODBC, é uma espécie de RDD/Driver para o Windows/Linux.

Tem ODBC pra: MySQL, Excel, SQL Server, MySQL, Firebird, SQLite, Access, PostgreSQL, Oracle, Visual Foxpro, ADS/NTX, ADS/CDX, planilha Open Office, e muito mais.

Para ODBC/ADO, a diferença é a string de conexão - UM TEXTO.
E lógico, particularidades dos comandos SQL.

Aqui tem exemplos de string de conexão pra diversos bancos de dados
https://www.connectionstrings.com/

Tradução disso tudo:

O Harbour usa o ODBC...
Nem sabe qual é a base de dados, se uma coisa ou outra.
Ele apenas conversa com o Windows (ou Linux) e trabalha.

Para o programador:
Ao enviar comandos SQL, vai enviar comandos que o servidor aceite.
Se tem diferenças no SQL entre cada servidor, vai ter que ajustar.
Isso é um TEXTO que enviado ao servidor, NÃO é alteração de fonte de Harbour.

Mas isso, acontece até mesmo com a mesma base.
No MySQL 8 criaram a opção de CTE, pra facilitar os comandos mais complexos
Não adianta querer usar isso no MySQL 7, ou MySQL 6, ou MySQL 5, que não vai funcionar.
Então... diferença entre SQL sempre vai existir, é algo normal.

SQLMIX trabalhar com ODBC existe faz tempo, não precisa alterar nada tão cedo.
ADO trabalhar com ODBC existe faz mais tempo ainda, não precisa alterar nada tão cedo.

Quanto a MySQL e SQL Server.....
Vamos juntar a isso também o ADS - Advantage Database Server.

O SQL Server é ótimo? sim, é ótimo.... deve custar 30.000 reais
O Advantage Database Server é ótimo? sim, é ótimo... deve custar 30.000 reais
O MySQL é ótimo? sim, é ótimo... pode ser usado por 2.000 dólares por ano, mas nunca ninguém que usa grátis foi multado
O MariaDB é ótimo? sim, é ótimo... é totalmente grátis

SQL Server também tem versão grátis, mas.... tem limitações, que podem ou não ser problema.

Qual deles é melhor?
Grátis e sem limites só tem um, nem importa saber das outras diferenças kkkkkk

Tutorial de SQL

MensagemEnviado: 29 Jul 2020 14:33
por JoséQuintas
oConexao := win_OleCreateObject( "ADODB.Connection" )
oConexao:ConnectionString := "escolher uma"

oConexao:Open()
Resultado := oConexao:Execute( "SELECT * FROM CLIENTES" )
DO WHILE ! Resultado:Eof()
   ? Resultado:Fields( "CODIGO" ):Value
   ? Resultado:Fields( "NOME" ):Value
   Resultado:MoveNext()
ENDDO
Resultado:Close()
oConexao:Close()


NÃO é a string exatamente correta, é só pra exemplo
É só isto abaixo que precisa alteração no código fonte

oConexao:ConnectionString := "Driver={MariaDB ODBC 3.1 Driver};"
oConexao:ConnectionString := "Driver={MySQL ODBC 3.51 Driver};"
oConexao:ConnectionString := "Provider=Advantage OLE DB Provider;"
oConexao:ConnectionString := "Driver={MySQL ODBC 5.3 ANSI Driver};"
oConexao:ConnectionString := "Driver={SQLite ODBC Driver};Database=" + cFileName
oConexao:ConnectionString := [Provider=Microsoft.ACE.OLEDB.12.0;Data Source=] + cFileName // Excel

E eventuais diferenças no comando SQL.

Nota: Fonte/string apenas pra exemplo. Na hora de usar pra valer tem 2 ou 3 linhas a mais.

Tutorial de SQL

MensagemEnviado: 31 Jul 2020 09:37
por Mario Mesquita
Bom dia a todos.

Pois é, estou acompanhando as postagens sobre a migração de DBF para SQL, e de fato empolgado com o progresso do pessoal.
Não tenho nada contra o DBF, ao contrário, trabalho muito bem com ele, agora então com o CDX, funciona muito bem, praticamente não preciso
reindexar e a velocidade é bem aceitável, até porquê minhas tabelas não são enormes, as maiores tem no máximo 300 mil registros.

A questão mesmo é se alinhar com as novidades que existem e poderão existir, poder usar outras linguagens como apoio e até mudanças no futuro
(nunca se sabe...) e nesse ponto, o DBF te prende no mundo xbase. Apesar de ser um clippeiro convicto, simpatizo com outras linguagens como Delphi e Java.
Também ando interessado em algo que possa trabalhar pela internet, caso precise acompanhar as mudanças nesses tempos de pandemia.

Acho que o que pesa a favor do MySql pra mim, é ter muitos tópicos aqui e pessoas que usam bem e já tem boa noção desse SGDB, além do Harbour ter alguma
coisa já meio pronta para essa BD. O Server pode ser muito bom, mas pouco vejo falarem dele aqui e aquele meu amigo não tem disponibilidade de me
ajudar com ele o tempo que vou precisar para ter um domínio mínimo para migrar e abandonar o DBF.

Também vi seus posts sobre o MariaDB e penso que se é pra começar do zero, que seja com ele, já que é idêntico ao MySql mas 100% free.
Isso pesa em clientes, pois você pode garantir que eles não terão despesas adicionais com licenças e podem trabalhar regularmente sem achar que tem
uma ferramenta "pirata" na sua firma. Para empresas pequenas, custos baixos são questão de sobrevivência, te ajuda e oferecer um serviço mais em conta.

Eu já li o seu tutorial de ADO e devo reler para entender os detalhes e trabalhar com Sql. O que me atrasa é tempo, mas vou ter que dar jeito nisso
senão vou ser o último a usar DBFs.

Não sei nada dobre o SQLMix mas vou dar uma olhada nas amostras do Harbour. Se ajudar a entender mais rápido, por quê não?

Saudações,
Mario.

Tutorial de SQL

MensagemEnviado: 31 Jul 2020 10:19
por JoséQuintas
Pra efeito didático, ou talvez até pra usar mais, existe a opção de DBF.
O mais compatível acredito que seja ADS Local, compatível com SIXCDX.
Eu usava no VB6 acessando simultâneo Clipper.

Na prática o que significa?
Você pode alterar um único módulo pra usar os mesmos DBFs do resto do aplicativo, usando comandos SQL.
Faz um módulo, achou legal, faz mais outro, e mais outro... tudo ficando em SQL, mas usando os mesmos DBFs de sempre.
E vai fazendo isso, até se sentir confortável, podendo usar o tradicional ou o SQL, durante o tempo todo.

Se sentiu confortável com SQL, aí pode continuar passando pra SQL com DBF, ou pode começar a pensar em outra base de dados.

A limitação pra ADS Local chega a ser 20 terminais, é suficiente pra muitos.
ADS Local NÃO significa monousuário, significa SEM SERVIDOR ADS, que é pago.
O ODBC é grátis, então não precisa comprar nada.

É usar SQL encima dos próprios DBFs que está acostumado a usar.
Só precisa instalar ODBC do ADS.
Não tem nada a perder, só tem vantagem de poder usar comandos SQL e ficar mais rápido que o acesso a DBF normal.
No ADS os comandos são compatíveis com SQL Server.
Mas é só lembrar que a maioria dos comandos SQL são compatíveis em qualquer servidor que aceite SQL, as diferenças vão ser em comandos mais avançados, que geralmente só vamos usar muito depois de começar a aprender.

Tutorial de SQL

MensagemEnviado: 31 Jul 2020 10:53
por JoséQuintas
Usar ADS local no aplicativo significa o seguinte:

Se quiser usar o Harbour normal

USE arquivo
SET INDEX TO arquivo
GOTO TOP
....
o de sempre

SE QUISER usar ADO e ADS local, NUM ÚNICO FONTE, pode

Rs := Conexao:Execute( "SELECT ..... " )

Tutorial de SQL

MensagemEnviado: 31 Jul 2020 11:02
por Vlademiro
Quintas, o ADS local compartilha os índices com uma aplicação Harbour ?

Tutorial de SQL

MensagemEnviado: 31 Jul 2020 17:14
por JoséQuintas
Vlademiro escreveu:Quintas, o ADS local compartilha os índices com uma aplicação Harbour ?


É exatamente o que estou dizendo.
Inclusive pode misturar dentro do mesmo aplicativo, coisa que no Clipper não dava pra fazer.

A única restrição é chave compatível, senão o ADS despreza o índice diferente.

Caso não aceite StrZero(), é só substituir por Substr( Str() ) que dá no mesmo e fica compatível.

Apenas exemplo incompleto, não vai compilar.

@ 1, 0  PROMPT "DBF pelo Harbour normal"
@ 2, 0 PROMPT "DBF por ADO/ADS"
MENU TO nOpc

DO CASE
CASE nOpc == 1
   USE CLIENTES
   SET INDEX TO CLIENTES
   DO WHILE ! Eof()
        SKIP
   ENDDO
   USE
CASE nOpc == 2
   Rs := cnSQL:Execute( "SELECT * FROM CLIENTES" )   
   DO WHILE ! Rs:Eof()
      Rs:MoveNext()
   ENDDO
   Rs:CloseRecordset()
ENDCASE

Tutorial de SQL

MensagemEnviado: 01 Ago 2020 07:08
por JoséQuintas
Fui testar restaurar o backup do MySQL no SQLite.....
O MySQL tem campo INT UNSIGNED mas o SQLite não.
Já estou eliminando isso do MySQL.

Ao que parece, vai dar pra usar o mesmo backup/restore tanto no MySQL quanto no SQLite.

Só vou confirmar quando terminar de ajustar as estruturas.

Tutorial de SQL

MensagemEnviado: 01 Ago 2020 07:39
por Vlademiro
Não precisa mudar. Quando a gente faz um backup entre bancos diferentes a gente só usa o script com os dados, que são os inserts. A estrutura nao entra

Tutorial de SQL

MensagemEnviado: 01 Ago 2020 10:56
por JoséQuintas
Realmente backup com estruturas não serve entre dos dois.

No SQLite é INTEGER e não INT.
Tirando as estruturas, o backup deve servir.
Ou uma leve conversão pelo Harbour, pra não ter que criar as estruturas manualmente.

Isso é pra usar o backup do MySQL no SQLite e vice-versa.

Pra quem nunca viu, o backup é um arquivo texto, com comandos SQL.
Os comandos pra criação de arquivos são levemente diferente entre os dois.

Estou curioso pra ver até onde vai a compatibilidade com MySQL.

Tutorial de SQL

MensagemEnviado: 01 Ago 2020 15:15
por JoséQuintas
sqlite.png


Aos trancos e barrancos mas foi.
Pra quem nunca viu access e similares, é UM ÚNICO ARQUIVO que chamei de test.db, de 3.752KB

Peguei o backup do MySQL, fui fazendo os ajustes até ser aceito pelo SQLite.
Dentro tem todas as tabelas do aplicativo e índices.
Na consulta, TODAS as cidades do Brasil.
Na verdade apenas posicionei pra mostrar as informações, não foi um SELECT.
Aquele Substr( xxx, 1, 256 ) foi o HeidiSQL que colocou.

 Pasta de d:\temp

01/08/2020  15:07         3.842.048 test.db
               1 arquivo(s)      3.842.048 bytes

Tutorial de SQL

MensagemEnviado: 01 Ago 2020 15:41
por JoséQuintas
Vixe, não tem função Year()

sqlite.png


Mas por data foi

sqlite2.png

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 14:06
por JoséQuintas
Então, o que notei diferente entre SQLite e MySQL:

No MySQL tem campo INT, que pode ser INT(11) por exemplo
Já no SQLite é INTEGER
Isso altera a CRIAÇÃO da tabela, não o uso.

No MySQL tem os campos string: VARCHAR(), TEXT, CHAR(), etc. que seguem a codepage/collation da base
No SQLITE é obrigatório EM CADA CAMPO
Acaba nem aceitando criar índice pelos campos texto se não definir codepage/collation
Isso altera a criação da tabela, e de certa forma o uso, pra extrair informações em order alfabética, por exemplo, ou criar um índice por um campo string.

GROUP BY, MAX(), MIN(), AVG(), ORDER BY, e outros, são iguais

No MySQL existe DATE_FORMAT() pra formatar data
No SQLite se chama DATE(), com opções parecidas
No SQLite não existem as funções MONTH(), YEAR(), DAY()
Isso altera a extração de informações, tipo por mês/ano

No MySQL: GROUP BY YEAR( data ), ANO( data )
No MySQL: GROPU BY DATE_FORMAT( data, '%Y%m" )

No SQLite: GROUP BY DATE( data, '%Y%m' )
No SQLite: GROUP BY DATE( data, '%Y' ), DATE( data, '%m' )
Nota: dei uma olhada quando testei, posso ter colocado errado agora, mas é apenas pra dar uma idéia de diferença

Ou seja, dependendo do banco de dados, podem haver certas diferenças nas funções disponíveis.
De um jeito ou de outro, acaba existindo algo equivalente.

Nisso entra uma questão importante na hora de escolher a base de dados: ONDE OBTER AJUDA
A base de dados pode ser a melhor que existe no mundo, mas.... de nada adianta isso, se não tiver aonde possamos aprender alguma coisa, ou consultar exemplos.

Tava olhando, e como opções grátis temos:

SQL SERVER Express - limitado a 1GB ou 2GB
Oracle Lite - limitado a 12GB
MySQL Community - não oficialmente - sem limites
MariaDB - sem limites

Estas opções vão ter as mesmas fraquesas dos DBFs, mas existem
Elas não tem servidor, CADA APLICATIVO pode fazer alterações pela rede, igual ao DBF, então são menos seguras, apesar de funcionarem.

Access
SQLite

Também precisa levar em conta o seguinte:
Máquina 32 bits só consegue endereçar no máximo 4GB, significa arquivos com no máximo esse tamanho.
Usando cliente/servidor, e servidor 64 bits, a estação 32 bits fica limitada a esse tamanho PRA RESULTADO DE CONSULTAS

Traduzindo: lembram que falei que as consultas SQL são como um arquivo temporário? então... o limite é pra esse "arquivo temporário".
Fazer uma consulta que retorne mais de 4GB.... sei lá... acho que isso por si só já estaria errado.... seria demorado pra rede, e seria muita informação.

Nota:
Já usei MySQL, MariaDB, SQL Server Express, Access, ADS Local, e pequenos testes com SQLite.
Não tive nenhum contato com firebird, Oracle, e outros.

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 15:30
por Vlademiro
O PostgreSQL é muito bom tb.

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 15:35
por Vlademiro
O PostgreSQL tem extensões que permitem incluir uma linguagem de programação. Já usei com Perl. Tem pgperl e pgperlu (u é de unsafed). Em um ambiente isolado fiz uma query usando pgperlu e consegui executar comandos do SO. Li tabelas DBF, arquivos texto e até SQL Server. Tudo dentro de um select PostgreSQL. Muito doido e inseguro tb... Como a própria extensão já sugere pelo título.

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 15:47
por JoséQuintas
O Access também tem isso em MDB, até telas de aplicativo.
No final, isso também permite vírus, e acabando sendo aí que os antivírus e as proteções podem começar a bloquear até base de dados.
Mas seria interessante... talvez até o aplicativo dentro da base de dados...

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 15:50
por Vlademiro
Correção: é untrusted

Olha a descrição no site

Às vezes, é desejável escrever funções Perl que não sejam restritas. Por exemplo, pode-se querer uma função Perl que envie email. Para lidar com esses casos, o PL / Perl também pode ser instalado como uma linguagem "não confiável" (geralmente chamada PL / PerlU). Nesse caso, o idioma Perl completo está disponível. Se o programa createlang for usado para instalar o idioma, o nome do idioma plperlu selecionará a variante PL / Perl não confiável.

Nesse caso pode até criar um trigger. Sempre que inserir, se o valor for maior que x, manda um email.

É arriscado, mas em alguns casos bem específicos dá pra usar. Se não desse ninguém tinha criado essa extensão para PostgreSQL.

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 15:51
por Vlademiro
Usa no Linux. Se for usar no windows aí a festa tá feita. Kkkk pode usar objetos COM, OLE , ODBC, etc

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 16:41
por JoséQuintas
Eu já tô pensando é em bases para o futuro, se é que não existem.

Seria muito interessante gerador de relatórios integrado à base de dados.
No final, tem tudo a ver.

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 17:29
por Vlademiro
O que vc tem aí com dbf já funciona. Basta retornar um dbf virtual usando sqlmix ou dbf em memória. É o caminho mais rápido.

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 18:54
por alxsts
Olá!
JoséQuintas escreveu:Seria muito interessante gerador de relatórios integrado à base de dados.

Oracle Reports
SQL Server Reporting Services
MYSQL Report Builder
Postgres Reporting Tool

Todos pagos...

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 19:16
por JoséQuintas
Interessante ler esta parte:

Top-notch performance: MySQL can perform well whether data is in GB or TB. In fact, the development of the capabilities in managing large volumes of data and its performance has undergone so many updates over the years that you can firmly trust the performance of MySQL. The core philosophy of MySQL is simple: quickly get the data in, and quickly out. This gives MySQL the ability to perform flawlessly, whether an eCommerce website needs to receive million queries a day, systems need high-speed transactional processes or you simply want a reporting software you can trust to manage all your database activities.


Desempenho de primeira linha: o MySQL pode ter um bom desempenho, independentemente de os dados estarem em GB ou TB. De fato, o desenvolvimento dos recursos para gerenciar grandes volumes de dados e seu desempenho sofreu tantas atualizações ao longo dos anos que você pode confiar firmemente no desempenho do MySQL. A filosofia principal do MySQL é simples: insira e remova rapidamente os dados. Isso dá ao MySQL a capacidade de executar com perfeição, se um site de comércio eletrônico precisa receber milhões de consultas por dia, sistemas precisam de processos transacionais de alta velocidade ou você simplesmente deseja um software de relatório em que possa confiar para gerenciar todas as suas atividades de banco de dados.

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 19:22
por JoséQuintas
Acho que vou ressucitar o meu gerador de relatórios.
Criei pra curiosidade, mas eu mesmo nunca usei.
Atende 70% dos casos, tá bom pra começar.
Talvez juntando com comandos SQL ele facilite as possibilidades.

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 19:41
por JoséQuintas
Já estou pensando aqui nas possibilidades....

Por exemplo, um relatório de vendas do mês, com totais por cliente/produto

Isso no MySQL é rápido, mas sobraria a totalização para o aplicativo...... mas.... será que sobra mesmo?

À primeira vista, poderiam ser 3 comandos com relacionamento entre eles.

E pra facilitar mais ainda.... os totais vém primeiro, e não no final, coisa que os clientes até preferem !!!

Tô amadurecendo a idéia.....
De repente não são os geradores de relatório que são rápidos... é que eles sabem como puxar as informações de forma rápida do jeito que precisam.

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 22:42
por JoséQuintas
Só amadurecendo a idéia.
Já vém totalizado por cliente e cliente/produto, pronto pro relatório.

consulta.png


Detalhe no tempo:
0,000 segundos de servidor e 0,016 segundos da rede
16 milésimos de segundo.
Nem compensa calcular durante o relatório.

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 23:17
por JoséQuintas
Não deu certo, mas aparentemente o comando está certo.

soma.png

Tutorial de SQL

MensagemEnviado: 04 Ago 2020 23:27
por JoséQuintas
Na verdade, PODE ser que deu, é que não tem comparação.

Se estou somando produto/cliente, então não é o mesmo que somar o pedido.

Tutorial de SQL

MensagemEnviado: 05 Ago 2020 00:18
por JoséQuintas
soma3.png


Agora sim, dá pra conferir/comparar.

Pode ser usado, por exemplo, num relatório de comissão, onde a comissão é por cliente/produto

Tutorial de SQL

MensagemEnviado: 19 Ago 2020 10:51
por Mario Mesquita
Pessoal, bom dia!

Tem alguma rotina de migração DBF para MySql com criação de tabelas, etc, por aqui? Algo que possa servir de ponto de partida para converter as tabelas DBF?

Fazer isso na mão parece ruim, como estou engatinhando acho que com algo programado deve ser melhor...

Procurei por aqui mas não achei, se tiver alguma dica me ajuda muito,

Desde já, agradeço a ajuda.

Saudações,
Mario.

Tutorial de SQL

MensagemEnviado: 19 Ago 2020 11:50
por Vlademiro

Tutorial de SQL

MensagemEnviado: 19 Ago 2020 12:01
por JoséQuintas
Mario Mesquita escreveu:Tem alguma rotina de migração DBF para MySql com criação de tabelas, etc, por aqui? Algo que possa servir de ponto de partida para converter as tabelas DBF?
Fazer isso na mão parece ruim, como estou engatinhando acho que com algo programado deve ser melhor...
Procurei por aqui mas não achei, se tiver alguma dica me ajuda muito,


Na prática é um bom começo pra aprendizado.

É pegar a estrutura, fazer o CREATE TABLE, e depois fazer INSERT dos campos.
Vai fazer isso depois milhares de vezes, o que custa fazer também no início?

Crie uma, dê uma olhada pelo HeidiSQL como foi criada, e faça igual.

aStruList := dbStruct()

cSQL := "CREATE TABLE " + Dbf() + "( "

FOR EACH oElement IN aStruList
   cName := oELement[ F_NAME ]
   cType := oElement[ F_TYPE ]
   nLen  := oElement[ F_LEN ]
   nDec := oElement[ F_DEC ]
   DO CASE
   CASE cType == "C"
      cSQL += cName + " VARCHAR(|  + lTrim( Str( nLen ) ) + ")"
...
NEXT


E algo parecido para INSERT.

Tutorial de SQL

MensagemEnviado: 19 Ago 2020 15:01
por Mario Mesquita
Boa tarde a todos.

Quintas, estou seguindo seus passos. Baixei o MySql e o HeidiSQL, agora vendo como faz, achei um curso no YouTube, pq o pouco que sabia azedou... vamos em frente, afinal.

Beleza, vou por aí, tudo agora é aprendizado. Mas no futuro quando migrar os DBFs em clientes, vou precisar de algo mais automatizado, melhor ter algo
pronto pra fazer isso. Nem é pra pensar nesse minuto mas é inevitável.

Tô animado, já era para eu ter subido no bonde do SQL faz tempo.

Pra quem tá meio mais ou menos como eu, o curso no YT, é sempre uma ajudinha:

https://www.youtube.com/user/bosontreinamentos

Saudações,
Mario.

Tutorial de SQL

MensagemEnviado: 19 Ago 2020 16:39
por Mario Mesquita
Valdomiro, valeu!

Agora que vi. Esse programa está no pacote do HMG 3.4.4, é um bom ponto de partida pra estudos.

Sds,
Mario.

Tutorial de SQL

MensagemEnviado: 19 Ago 2020 20:07
por JoséQuintas
É que tem o detalhe da codepage.
Depende da codepage do aplicativo, e da codepage usada no MySQL.
A prova final é sua, porque depende do conteúdo encontrado nos DBFs.

E como isso pode acontecer durante o uso depois, já se prepara a partir dos DBFs/conteúdos que tem hoje, porque teoricamente é o mesmo que vai ter depois que estiver em uso.

Uma coisa que faz muita diferença nessa inclusão em massa, é incluir vários registros por vez, ao invés de um por um.
Ao invés de INSERT pra um registro, faz INSERT PRA vários.

Aqui coloquei como limite um comando com até 256.000 caracteres.
Limitei pelo comando, e não pela quantidade.

Tutorial de SQL

MensagemEnviado: 23 Ago 2020 11:18
por Mario Mesquita
Bom dia e bom domingo a todos.

Interessante esse ponto sobre o codepage. Eu tenho tabelas em ANSI e UTF-8 pq ainda tenho coisas em HMG 3.0.46 e coisas na
versão 3.4.4. A ideia é passar tudo pra 3.4.4 com tabelas em UTF-8. Tem a parte chata de converter essas tabelas em ANSI.
E, pelo que vi, tem que se ligar no codepage da BD no MySql, né?

Uma dúvida: tenho campos que sofrem incremento tipo protocolos, números de operação ou algum tipo de numeração. Os campos são
caractere e incremento usando VAL(variável) + 1. NO caso do MySql, qual a técnica recomendada? Campo numérico com auto incremento
ou pode ser desse jeito?

Saudações,
Mario.

Tutorial de SQL

MensagemEnviado: 23 Ago 2020 20:41
por JoséQuintas
Melhor deixar por conta do MySQL, assim NUNCA vai ter problema.

Tutorial de SQL

MensagemEnviado: 24 Ago 2020 10:44
por Mario Mesquita
Bom dia e boa semana a todos.

Valeu, Quintas. Então deixo os campos como numéricos com auto incremento, certo? E formato como "@R" ou similar né? Já que não podem ser tipo caractere.

Saudações,
Mario.

Tutorial de SQL

MensagemEnviado: 24 Ago 2020 11:46
por JoséQuintas
O detalhe é este: é um campo numérico comum.
Apenas na inclusão é que pode deixar por conta do MySQL fazer a numeração.

Pode fazer:

INSERT INTO CLIENTES ( IdCodigo, Nome ) VALUES ( 10, "JOSE" )

ou:

INSERT INTO CLIENTES ( NOME ) VALUES ( "JOSE" )

E pra saber o código que foi atribuído, em seguida é fazer:
SELECT LAST_INSERT_ID()