Página 1 de 1
PROCEDURE de TROCO
Enviado: 20 Mai 2021 11:39
por JoséQuintas
Gostei da coisa, a primeira solução de principiante foi esta
Código: Selecionar todos
CREATE PROCEDURE `ze_troco`(
IN `nValorOriginal` DOUBLE(16,2)
)
BEGIN
DECLARE nValor DOUBLE(16,2);
SET @nTroco100 = 0;
SET @ntroco50 = 0;
SET @ntroco20 = 0;
SET @ntroco10 = 0;
SET @ntroco5 = 0;
SET @ntroco2 = 0;
SET @ntroco1 = 0;
SET @ntroco050 = 0;
SET @ntroco025 = 0;
SET @ntroco010 = 0;
SET @ntroco005 = 0;
SET @ntroco001 = 0;
SET nvalor = nvalororiginal;
if nvalor >= 100 then
SET @ntroco100 = FLOOR( nvalor / 100 );
SET nvalor = nvalor - ( 100 * @ntroco100 );
END if;
if nvalor >= 50 then
SET @ntroco50 = FLOOR( nvalor / 50 );
SET nvalor = nvalor - ( 50 * @ntroco50 );
END if;
if nvalor >= 20 then
SET @ntroco20 = FLOOR( nvalor / 20 );
SET nvalor = nvalor - ( 20 * @ntroco20 );
END if;
if nvalor >= 10 then
SET @ntroco10 = FLOOR( nvalor / 10 );
SET nvalor = nvalor - ( 10 * @ntroco10 );
END if;
if nvalor >= 5 then
SET @ntroco5 = FLOOR( nvalor / 5 );
SET nvalor = nvalor - ( 5 * @ntroco5 );
END if;
if nvalor >= 2 then
SET @ntroco2 = FLOOR( nvalor / 2 );
SET nvalor = nvalor - ( 2 * @ntroco2 );
END if;
if nvalor >= 1 then
SET @ntroco1 = FLOOR( nvalor / 1 );
SET nvalor = nvalor - ( @ntroco1 );
END if;
if nvalor >= 0.5 then
SET @ntroco050 = FLOOR( nvalor / 0.5 );
SET nvalor = nvalor - ( 0.5 * @ntroco050 );
END if;
if nvalor >= 0.25 then
SET @ntroco025 = FLOOR( nvalor / 0.25 );
SET nvalor = nvalor - ( 0.25 * @ntroco025 );
END if;
if nvalor >= 0.1 then
SET @ntroco010 = FLOOR( nvalor / 0.1 );
SET nvalor = nvalor - ( 0.1 * @ntroco010 );
END if;
if nvalor >= 0.05 then
SET @ntroco005 = FLOOR( nvalor / 0.05 );
SET nvalor = nvalor - ( 0.05 * @ntroco005 );
END if;
if nvalor >= 0.01 then
SET @ntroco001 = FLOOR( nvalor / 0.01 );
SET nvalor = nvalor - ( 0.01 * @ntroco001 );
END if;
SELECT * FROM (
SELECT 100 AS moeda, @ntroco100 AS qtd
UNION SELECT 50, @ntroco50
UNION select 20, @ntroco20
UNION SELECT 10, @ntroco10
UNION SELECT 5, @ntroco5
UNION SELECT 2, @ntroco2
UNION SELECT 1, @ntroco1
UNION SELECT 0.5, @ntroco050
UNION SELECT 0.25, @ntroco025
UNION SELECT 0.1, @ntroco010
UNION SELECT 0.05, @ntroco005
UNION SELECT 0.01, @ntroco001 ) AS X
WHERE qtd > 0
;
END

7 notas de 100, 1 nota de 50, 1 nota de 20, 1 nota de 5, 1 nota de 2, 1 moeda de 0.50, 1 moeda de 0.25, 2 moedas de 0.01
total 777.77
sem o erro de cálculo de ponto flutuante.
PROCEDURE de TROCO
Enviado: 20 Mai 2021 11:59
por JoséQuintas
Com variáveis diretas, ao invés de @variavel
Código: Selecionar todos
CREATE PROCEDURE `ze_troco`(
IN `nValorOriginal` DOUBLE(16,2)
)
BEGIN
DECLARE nValor DOUBLE(16,2);
DECLARE nTroco100 INT DEFAULT 0;
declare ntroco50 INT DEFAULT 0;
declare ntroco20 INT DEFAULT 0;
declare ntroco10 INT DEFAULT 0;
declare ntroco5 INT DEFAULT 0;
declare ntroco2 INT default 0;
declare ntroco1 INT DEFAULT 0;
declare ntroco050 INT DEFAULT 0;
declare ntroco025 INT default 0;
declare ntroco010 INT DEFAULT 0;
declare ntroco005 INT DEFAULT 0;
declare ntroco001 INT DEFAULT 0;
SET nvalor = nvalororiginal;
if nvalor >= 100 then
SET ntroco100 = FLOOR( nvalor / 100 );
SET nvalor = nvalor - ( 100 * ntroco100 );
END if;
if nvalor >= 50 then
SET ntroco50 = FLOOR( nvalor / 50 );
SET nvalor = nvalor - ( 50 * ntroco50 );
END if;
if nvalor >= 20 then
SET ntroco20 = FLOOR( nvalor / 20 );
SET nvalor = nvalor - ( 20 * ntroco20 );
END if;
if nvalor >= 10 then
SET ntroco10 = FLOOR( nvalor / 10 );
SET nvalor = nvalor - ( 10 * ntroco10 );
END if;
if nvalor >= 5 then
SET ntroco5 = FLOOR( nvalor / 5 );
SET nvalor = nvalor - ( 5 * ntroco5 );
END if;
if nvalor >= 2 then
SET ntroco2 = FLOOR( nvalor / 2 );
SET nvalor = nvalor - ( 2 * ntroco2 );
END if;
if nvalor >= 1 then
SET ntroco1 = FLOOR( nvalor / 1 );
SET nvalor = nvalor - ( ntroco1 );
END if;
if nvalor >= 0.5 then
SET ntroco050 = FLOOR( nvalor / 0.5 );
SET nvalor = nvalor - ( 0.5 * ntroco050 );
END if;
if nvalor >= 0.25 then
SET ntroco025 = FLOOR( nvalor / 0.25 );
SET nvalor = nvalor - ( 0.25 * ntroco025 );
END if;
if nvalor >= 0.1 then
SET ntroco010 = FLOOR( nvalor / 0.1 );
SET nvalor = nvalor - ( 0.1 * ntroco010 );
END if;
if nvalor >= 0.05 then
SET ntroco005 = FLOOR( nvalor / 0.05 );
SET nvalor = nvalor - ( 0.05 * ntroco005 );
END if;
if nvalor >= 0.01 then
SET ntroco001 = FLOOR( nvalor / 0.01 );
SET nvalor = nvalor - ( 0.01 * ntroco001 );
END if;
SELECT * FROM (
SELECT 100 AS moeda, ntroco100 AS qtd
UNION SELECT 50, ntroco50
UNION select 20, ntroco20
UNION SELECT 10, ntroco10
UNION SELECT 5, ntroco5
UNION SELECT 2, ntroco2
UNION SELECT 1, ntroco1
UNION SELECT 0.5, ntroco050
UNION SELECT 0.25, ntroco025
UNION SELECT 0.1, ntroco010
UNION SELECT 0.05, ntroco005
UNION SELECT 0.01, ntroco001 ) AS X
WHERE qtd > 0
;
END
Acabou sendo uma rotina interessante de estudo.
Tem o SELECT de valores
Tem o SELECT com UNION, que junta os outros SELECTs
Tem o SELECT encima de tudo, pra filtrar valores zero.
Tem a criação de variáveis
Tem IF/ENDIF
Tô pensando se não dava pra criar um SELECT com os valores de "notas", e depois um DO WHILE fazendo um por um, com INSERT no temporário, ficaria menor.
É parecido com o que faríamos no Harbour.
Apesar do MySQL não ter array, a base virtual acaba sendo uma espécie de array.
Tudo diferente, mas tudo igual, só que diferente... muito interessante
Só não sei se vai dar pra fazer isso do jeito que comentei...
PROCEDURE de TROCO
Enviado: 20 Mai 2021 13:38
por JoséQuintas
Deu trabalho, muita pesquisa, provavelmente deve ter opção melhor, mas funcionou.
Código: Selecionar todos
BEGIN
DECLARE X, nValor DOUBLE(16,2);
DECLARE z,nqtd INT;
DECLARE sp1_cursor CURSOR FOR SELECT valor FROM tmpmoeda;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET z=1;
SET nvalor = nvalororiginal;
DROP TEMPORARY TABLE if EXISTS tmpmoeda;
DROP TEMPORARY TABLE if EXISTS tmpvalores;
CREATE TEMPORARY TABLE tmpmoeda ( valor DOUBLE(16,2) ) ;
CREATE TEMPORARY TABLE tmpvalores (qtd INT(10), valor DOUBLE(16,2) );
insert into tmpmoeda select 100 AS valor union SELECT 50 union SELECT 20 union SELECT 10
UNION SELECT 5 UNION select 2 UNION select 1 UNION ALL select 0.5 as valor
UNION select 0.25 UNION select 0.10 UNION select 0.05 UNION select 0.01 ;
OPEN sp1_cursor;
REPEAT
FETCH sp1_cursor INTO x;
IF nValor >= x AND X <> 0 then
set nQtd = FLOOR( nValor / X );
INSERT INTO tmpvalores VALUES ( nQtd, x );
SET nvalor = nvalor - ( nqtd * x );
END if;
UNTIL z=1
END REPEAT;
close sp1_Cursor;
SELECT * FROM tmpvalores;
DROP TEMPORARY TABLE tmpmoeda;
DROP TEMPORARY TABLE tmpvalores;
END

Cria uma tabela temporária com a definição das moedas, e cria outra pra ir armazendo o resultado.
E retorna essa temporária de resultados.
PROCEDURE de TROCO
Enviado: 20 Mai 2021 13:40
por JoséQuintas
Não precisa mais do x <> 0.
É que durante testes defini x como inteiro, e por isso não dava certo, dava divisão por zero, e por isso acrescentei o teste durante o teste... rs
A tabela temporária é visível entre comandos, por isso coloquei pra apagar.
Acho que só some quando fechar conexão.
PROCEDURE de TROCO
Enviado: 20 Mai 2021 13:45
por JoséQuintas
JoséQuintas escreveu:A tabela temporária é visível entre comandos, por isso coloquei pra apagar.
Acho que isso a torna perigosa pra uso pesado.
PROCEDURE de TROCO
Enviado: 20 Mai 2021 14:03
por JoséQuintas
Aproveitei pra expandir.
De repente vai pagar funcionário em dinheiro...
Mas estou preferindo a primeira opção, pelo detalhe da tabela temporária não ser tão temporária assim.
A não ser que crie uma tabela FIXA pras notas/moedas.
PROCEDURE de TROCO
Enviado: 20 Mai 2021 14:18
por JoséQuintas
Qual a vantagem de deixar no MySQL?
Pro aplicativo, é chamar a rotina e fazer um browse do resultado.
Pois é... o aplicativo vai ter SAY/GET/BROWSE... vai sobrar pouca exceção pro aplicativo tratar.
Do jeito que é hoje: basta caçar a função na internet, não importa se usa Harbour, xHarbour, ASP, Delphi, etc.
PROCEDURE de TROCO
Enviado: 20 Mai 2021 14:39
por Itamar M. Lins Jr.
Olá!
basta caçar a função na internet,
Estava lendo "parte" de uns pensamentos sobre esse assunto.
A Microsoft está UNIFICANDO tudo. Não tem como abraçar tudo, pq ocorre perder o foco.
Por isso acabou com Win10X e outras coisas, linguagens. Empresa precisa de LUCRO e para isso precisa apresentar soluções.
Microsoft is looking to address the fragmentation in the Windows developer ecosystem through Windows UI and Project Reunion
Adding, or migrating to, Windows UI makes it easier to support other platforms, such as iOS, Android, macOS, Web and Linux, via the Uno Platform
The Future of Windows (and other Platforms) Development
https://www.infoq.com/articles/future-w ... velopment/
https://platform.uno/ -> plataforma que promete UNIFICAR tudo!
E nessa luta diária para ter mais lucros acaba precisando diminuir funcionários 1 funcionário passa a fazer trabalho de 2, 3 pessoas...
Ora ela tenta andar para um lado, ora vai para outro e acaba sedendo espaço para outros explorarem.
Não tem como, o mundo é PLURAL e nunca a Microsoft vai conseguir abraçar, solucionar todas as situações que se apresentam. Até pq, mesmo com a SOLUÇÃO na mão, as pessoas escolhem outras, por inúmeras questões.
Resultado é que ela está delegando a comunidade LINUX muita coisa.
Microsoft quer adotar recurso de segurança do Linux no Windows
https://tecnoblog.net/441643/microsoft- ... a-windows/
Saudações,
Itamar M. Lins Jr.
PROCEDURE de TROCO
Enviado: 20 Mai 2021 15:19
por JoséQuintas
Ela está pra trocar a partição NT pra uma existente no Linux, isso também, e acho que outras coisas mais.
Eu já comentei isso.
Acho que o Windows vai acabar virando Linux, aí ela não vai mais ser responsabilizada por nada.
Desde o W7 ela vém simplificando/unificando tudo.
Não faz sentido várias linguagens de programação separadas, usando os mesmos recursos centrais, por isso o Visual Studio virou uma coisa só.
O NET Framework foi outra coisa que unificou tudo, pra permitir mudar tudo de uma vez.
Ela vém fazendo isso faz tempo, mas sem tirar o Windows do ar, igual eu fiz com meus aplicativos ao trocar base de dados, pro usuário não perceber mudanças.
Talvez o sub-sistema Linux seja a forma de permitir migração de uma coisa pra outra, aos poucos.
A partir da próxima versão, programas GUI Linux rodam lado a lado com Windows.
Isso significa que poderemos estar usando programas Linux sem saber.
Talvez.... seja até interessante isso de passar funções/procedures pra MySQL, porque tá tudo mudando rápido.
Acho que isso de ter mais lucros, também está relacionado, como você já disse, de ter menos funcionários.
Menos despesas também significa mais lucro, e menos trabalho.
Se o núcleo do Windows for trocado pra Linux... pode reduzir muito o trabalho/despesa.
A dúvida agora pode ser: Rodar Ubuntu encima do núcleo da Microsoft.... isso é considerado fora dos padrões Linux?
Rodar programas Linux no núcleo Microsoft.... isso é aceito?
Poder rodar tudo grátis encima do núcleo pago.... isso é aceito?
Sei lá o que vém pela frente....
PROCEDURE de TROCO
Enviado: 20 Mai 2021 17:30
por JoséQuintas
Achei uma função do MySQL interessante, mas cai ainda em como retornar a lista.
Aqui a simulação da função ELT()
Código: Selecionar todos
FUNCTION MaiorTroco( nValor )
LOCAL nCont, nNota
FOR nCont = 1 TO 13
nNota := Elt( nCont, 200, 100, 50, 20, 10, 5, 2, 1, 0.5, 0.25, 0.10, 0.05, 0.01 )
IF nValor >= nNota
RETURN nNota
ENDIF
NEXT
RETURN nValor
FUNCTION Elt( ... )
LOCAL nItem, aList
aList := hb_AParams()
nItem := aList[ 1 ]
hb_aDel( aList, 1, .T. )
IF nItem > Len( aList )
RETURN Nil
ENDIF
RETURN aList[ nItem ]
Facilita na parte da lista, simulando um array, mas não adianta eliminar variáveis, se vou ter que retornar um select, e não vou ter as variáveis.
PROCEDURE de TROCO
Enviado: 20 Mai 2021 17:58
por JoséQuintas
Interessante também:
tempo de resposta menos de um milésimo de segundo.
PROCEDURE de TROCO
Enviado: 21 Mai 2021 18:47
por JoséQuintas
Outro teste, usando um select. (ou vários)
PROCEDURE de TROCO
Enviado: 21 Mai 2021 19:01
por JoséQuintas
Acabo às vezes comparando o MySQL ao Excel, ao tentar explicar ao cliente: é uma base igual Excel onde posso ter fórmulas.
Vamos por partes:
o mais interno é este:
isso vai gerar uma lista com as moedas.
Código: Selecionar todos
(
SELECT 200 as troco union select 100 union SELECT 50 union SELECT 20 union SELECT 10
UNION SELECT 5 UNION select 2 UNION select 1 UNION select 0.5
UNION select 0.25 UNION select 0.10 UNION select 0.05 UNION select 0.01 ) AS B
O do meio, são 3 colunas, uma vém dessa acima, e as outras duas são calculadas:
Código: Selecionar todos
SELECT TROCO,
CASE WHEN @VALOR >= TROCO THEN
FLOOR( @VALOR / TROCO )
ELSE 0
END AS QTD,
CASE WHEN @VALOR >= TROCO THEN
@VALOR := @VALOR - ( FLOOR( @VALOR / TROCO ) * TROCO )
END AS VALOR
FROM ...
A primeira calculada é a quantidade de notas daquele valor, para o valor analisado. Por exemplo, só vai ter nota de 200 se o valor for >= 200, senão será ZERO.
Código: Selecionar todos
CASE WHEN @VALOR >= TROCO THEN
FLOOR( @VALOR / TROCO )
ELSE 0
END AS QTD,
Além do cálculo acima, preciso do resto da divisão, conforme forem encontradas notas
É pra isso que serve a fórmula 2
Código: Selecionar todos
CASE WHEN @VALOR >= TROCO THEN
@VALOR := @VALOR - ( FLOOR( @VALOR / TROCO ) * TROCO )
END AS VALOR
O que falta?
Eliminar as notas ZERADAS, afinal não interessam.
Também não interessa a terceira coluna de cálculo, só as duas primeiras.
É pra isso o select externo
Pronto, cálculos efetuados.
E através de consulta à tabela que não existe fisicamente, com valores de moeda.
PROCEDURE de TROCO
Enviado: 21 Mai 2021 20:12
por JoséQuintas
Comparando as duas rotinas.
Acho que a primeira ainda contém herança de outras linguagens de programação, e a segunda está mais "estilo SQL".
A primeira usa variáveis, enquanto a segunda usa tabelas/subtabelas, exatamente o que existe num servidor de base de dados.