Translate

terça-feira, 14 de janeiro de 2014

MySql SUM - Soma

A função SUM retorna a soma de valores de uma coluna.

SINTAXE
SELECT SUM(nome_da_coluna) FROM nome_da_tabela;

Para os 6 exemplos abaixo, utilizaremos a tabela "tb_fornecedor". Veja a imagem abaixo:

Caso tenha interesse faça o download dos exemplos ou veja os scripts no GitHub.




1º Exemplo

Cenário: um funcionário quer calcular o valor total das despesas de uma empresa.

Solução: o valor das despesas estão armazenados na coluna valor, logo devemos somar os valores desta coluna.
Para calcularmos a soma, executamos a sentença abaixo:

SELECT SUM(valor) FROM tb_fornecedor;

Após a execução, teremos o gasto total com as despesas. Conforme podemos visualizar na imagem abaixo:

O nome da coluna aparece como "SUM(valor)", mas vamos supor que precisamos que seja exibido "total".
Podemos modificar o nome desta coluna, ou seja, criar um alias (apelido). Colocamos o alias depois do "AS
SELECT SUM(valorAS total FROM tb_fornecedor;

Após a execução, o nome da coluna será exibido como "total".


2º Exemplo

Cenário: O funcionário de uma empresa quer calcular o valor total das despesas por segmento, ou seja:

  • Total de gastos com o segmento Papelaria e informática
  • Total de gastos com o segmento Marcenaria
  • Total de gastos com o segmento Serralheria
  • Total de gastos com o segmento Limpeza e higiene

Solução: antes de efetuarmos a soma, devemos agrupar os segmentos que estão armazenados na coluna "segmento". Para agruparmos utilizaremos o " GROUP BY".

Para calcularmos a soma por segmento, executamos a sentença abaixo:

SELECT segmento, SUM(valor) AS total 
FROM tb_fornecedor 
GROUP BY segmento;

Após a execução, teremos o gasto total com as despesas agrupado por segmento. Conforme podemos visualizar na imagem abaixo:




Para ordenar o total em ordem crescente, ou seja, do valor menor para o maior, deve-se usar "ORDER BY" seguido do nome da coluna, neste caso a coluna ordenada será 'total'.
Para ordenar os valores, utilizamos a sentença abaixo:

SELECT 
segmento, 
SUM(valor) AS total 
FROM tb_fornecedor 
GROUP BY segmento
ORDER BY total;

Após a execução, teremos os valores em ordem crescente. Conforme podemos visualizar na imagem abaixo:

Para ordenar o total em ordem decrescente, ou seja, do maior valor para o menor devemos acrescentar o "DESC" depois do "ORDER BY".
Para ordenar os totais em ordem decrescente, utilizamos a sentença abaixo:

SELECT 
segmento, 
SUM(valor) AS total 
FROM tb_fornecedor 
GROUP BY segmento
ORDER BY total DESC;

Após a execução, teremos os valores totais em ordem decrescente.  Conforme podemos visualizar na imagem abaixo:


3º Exemplo

Cenário: Este cenário é um pouco parecido com o anterior,  vamos calcular as despesas por segmento, mas agora considerando a quantidade de produtos.
Observação: perceba que foi incluída a coluna quantidade na tabela "tb_fornecedor".




Solução: dentro da função "SUM" devemos fazer a multiplicação da quantidade pelo valor do produto. Exemplo: gastamos R$ 335,00 com o segmento "Limpeza e higiene", pois compramos
  • R$ 15,00 de detergente     (3 *   5,00);
  • R$ 200,00 de desinfetante (5 * 40,00);
  • R$ 120,00 de papel toalha (2 * 60,00);
Total para o segmento "Limpeza e higiene": 15,00 + 200,00 + 120,00 = 335,00

    Para calcularmos a soma por segmento, executamos a sentença abaixo:

    SELECT 
    segmento, 
    SUM(quantidade * valor) AS total 
    FROM tb_fornecedor 
    GROUP BY segmento
    ORDER BY total;

    Após a execução, teremos os totais por segmento. Conforme podemos visualizar na imagem abaixo:


    4º Exemplo

    Cenário: Vamos calcular o total das despesas por mês. Neste caso, para "setembro / 2013", "outubro / 2013" e "novembro / 2013".





    O primeiro passo é saber como extrair o mês e o ano de uma data. 

    Para extrair o mês e o ano de uma data utilizaremos a função "extract".

    Exemplo da utilização de extract:

    SELECT
    data, 
    extract(month from data) AS mes,
    extract(year from data) AS ano
    FROM tb_fornecedor;

    Significado:

    extract(parte_da_data from nome_da_coluna)
    • parte_da_data: podemos passar qual a parte da data que queremos, por exemplo,  day para o dia ou year para o ano, entre outros.
    • nome_da_coluna: nome da coluna de uma tabela. Neste caso vamos escolher a coluna "data" da tabela "tb_fornecedor".
    Após a execução, teremos uma coluna com o ano, e uma coluna com o mês. Conforme podemos visualizar na imagem abaixo:




    Agora que já sabemos utilizar as função "extract", vamos utilizá-la para fazer o calculo das despesas para os meses de setembro, outubro e novembro de 2013.

    SELECT 
    extract(month from data) AS mes,
    SUM(quantidade * valor) AS total 
    FROM tb_fornecedor
    WHERE extract(year from data) = 2013 
    GROUP BY mes
    ORDER BY mes;

    Após a execução, teremos o total para cada mês.



    Caso queiramos exibir os meses por extenso e na língua portuguesa, ou seja, setembro, outubro e novembro devemos configurar a variável de sistema do mysql "lc_time_name". Em caso de dúvida veja o artigo "Mysql - formatar data e hora":

    SELECT
    /*Formata a data em português devido a configuração da variável de sistema do mysql chamada "lc_time_names". Em caso de dúvida veja o artigo de formatação de data*/ 
    date_format(data'%M/%Y') AS mes, 
    SUM(quantidade * valor) AS total 
    FROM tb_fornecedor
    WHERE extract(year FROM data) = 2013 
    GROUP BY  mes
    /*Orderna pela ordem numérica do mês (...9,10, 11)* observe o "m" do date_format em minúsculo*/ 
    ORDER BY date_format(data'%m/%Y') ;

    Após a execução, o mês será exibido por extenso. Conforme podemos visualizar na imagem abaixo:

    5º Exemplo

    Cenário: Vamos calcular o total das despesas por mês e por segmento. Para isso vamos agrupar por mês e segmento, ou seja o "GROUP BY" será acompanhado pelo mês e pelo segmento.

    SELECT
    extract(month FROM data)  AS mes,
    segmento, 
    SUM(quantidade * valor) AS total 
    FROM tb_fornecedor
    WHERE extract(year FROM data) = 2013 
    GROUP BY messegmento
    ORDER BY messegmento;

    Após a execução, as despesas serão agrupadas por mês e segmento. Conforme podemos visualizar na imagem abaixo:


    Caso queiramos exibir os meses por extenso, ou seja, setembro, outubro e novembro podemos utilizar a função "date_format" na sentença:

    SELECT
    /*Formata a data em português devido a configuração da variável de sistema do mysql chamada "lc_time_names". Em caso de dúvida veja o artigo de formatação de data*/ 
    date_format(data'%M/%Y') AS mes, 
    segmento, 
    SUM(quantidade * valor) AS total 
    FROM tb_fornecedor
    WHERE extract(year FROM data) = 2013 
    GROUP BY mes,  segmento
    /*Orderna pela ordem numérica do mês (...9,10, 11)* observe o "m" do date_format em minúsculo*/ 
    ORDER BY date_format(data'%m/%Y')segmento;

    Após a execução, o meses serão exibidos por extenso. Conforme podemos visualizar na imagem abaixo:



    6º Exemplo

    Cenário: queremos saber quais os meses em que as despesas ultrapassaram R$2000, ou seja foram maior que R$2000?




    Solução: para sabermos quais os meses em que as despesas ultrapassaram R$2000 vamos adicionar a clausula "HAVING" a sentença.

    SELECT
    /*Formata a data em português devido a configuração da variável de sistema do mysql chamada "lc_time_names". Em caso de dúvida veja o artigo de formatação de data*/ 
    date_format(data'%M/%Y') AS mes,
    SUM(quantidade * valor) AS total 
    FROM tb_fornecedor
    WHERE extract(year FROM data) = 2013 
    GROUP BY mes  
    HAVING SUM(quantidade * valor) > 2000
    /*Orderna pela ordem numérica do mês (...9,10, 11)* observe o "m" do date_format em minúsculo*/ 
    ORDER BY date_format(data'%m/%Y');

    Após a execução, só serão exibidos os meses nos quais as despesas ultrapassaram R$ 2000,00. Conforme podemos visualizar na imagem abaixo:


    Em breve, postarei mais exemplos da função sum.

    17 comentários:

    1. Muito legal. Mas e como seria a soma se tivéssemos por exemplo três colunas com data em que precisa-se saber qual é maior ou menor que outra
      Valor/Data1/Data2/Data3

      ResponderExcluir
    2. Muito bom meu amigo estava igual louco atráz disso!!
      Obrigado.

      ResponderExcluir
    3. Muito bom, é uma pena que estou tentando colocar o mês Set, Out, Nov, Dez e não consigo.
      Dentro do SQLyog digitei SELECT DATE_FORMAT(DATA, '%b') AS mes e antes dessa linha digitei SET lc_time_names=pt_BR; funciona, mas como vou colocar essa linha no html. Por favor se for possível me ajudem. carlos.teixeira@terra.com.br

      ResponderExcluir
    4. Muito obrigado Kelly Silva Costa. Vc nos ajudou muito. Parabéns pelo trabalho.

      ResponderExcluir
    5. E se no campo segmento eu quisesse separar os textos de higiene e limpeza por ex em duas colunas ?

      ResponderExcluir
    6. Kelly... preciso de uma ajuda... preciso apenas exibir o total de um campo na tabela... mas ao colocar os codigos ele não exibe nada.


      Pode me ajudar? só preciso que seja somado o campo visitas e seja exibido na tela o total das visitas...

      ResponderExcluir
    7. o codigo que estou usando

      $sql = mysql_query( "SELECT SUM (visitas) as total FROM destaques");
      while($nl = mysql_fetch_array($sql)){
      echo $total;
      }

      ResponderExcluir
    8. achei muito bom e muito esclarecedor esse cara do post
      será que e gostaria de fazer um pedido de ajuda pois estou a muito tempo quebrando a cabeça com isso
      já tentei uma porrada de INNER JOINs e GROUP BYs e nada
      quando resolvo a separação pelo owner com GROUP BY não consigo fazer as contagens de cada item de cada um deles
      tenho esta table abaixo

      owner_id item_id count
      FULANO_silva 3470 1
      CICLANO_santos 59 4
      FULANO_silva 3470 60
      CICLANO_santos 3470 68000
      FULANO_sauro 59 100

      e gostaria que ela me retornasse os dados assim

      owner_id qtd_item3470 qtd_item59
      CICLANO_santos 68000 4
      FULANO_silva 61 0
      FULANO_sauro 0 100

      conforme a tabela resposta quero q ela me retorne as contagens de cada item que owner_id (dono do item) tem, ordenado primeiramente pelo item 3470 e depois pelo item 59
      o mais próximo que cheguei da resposta foram estes dois aqui selects abaixo

      esse está incompleto
      SELECT items.owner_id, items.item_id, items.count FROM items WHERE items.item_id = '59' or items.item_id = '3470'
      ORDER BY items.count


      e este esta errado
      SELECT items.owner_id, items.item_id, items.count FROM items WHERE items.item_id = '59' or items.item_id = '3470'
      ORDER BY items.count


      desde já agradeço quem puder ajudar...

      ResponderExcluir
    9. Fantástico.. fiquei muito tempo procurando por esta dica.. Mas o ditado é verídico.. que procurando.. acha.. Deus a Abençoe..

      ResponderExcluir
    10. Olá Kely Costa,
      Bom Dia, seria possível me dar mais um help complementar nesta matéria..
      Bem; Após ter conseguido à somatória no dbGrid por seguimentados, preciso enviá-los para respectivos dbEdits ou edtis também por seguimento.
      Você teria como me orintar nesta codificação?..

      Desde Já antecipo Meus agradecimentos, também pelas dicas anteriores deixo meus mais sinceros agradecimentos..
      Tem muito tempo que estou precisando estes códigos.. e na Web.. não consegui entendimentos para executá-los..
      Obrigado!
      Que à Paz Seja Conosco!

      ResponderExcluir
    11. Eu estou fazendo um projeto em C# e to desenvolvendo uma tela de relário e fiz o seguinte select:
      SELECT vd.id_produto , p.descricao, vd.qtde, " +
      "sum(vd.qtde*vd.vlr_unit) FROM venda_det vd inner join produtos p inner join venda_cab vc " +
      "on (vd.id_produto = p.id) WHERE vc.data BETWEEN ?dataInicio and ?dataFinal " +
      "group by vd.id_produto order by vd.qtde desc

      Que em teoria iria puxar o id do produto, a descrição do pruduto, a quantidade vendida ao total e o valor vendido desse produto filtrando por uma data seleciona um Combo Box no C# representada pelos parâmetros ?dataInicio e ?dataFinal. Mas quanto eu inicio ele ele está duplicando esses dados, onde estaria o erro?

      ResponderExcluir
      Respostas
      1. Bom dia, segue as observações sobre sua consulta,
        após as observações, inclui um exemplo que eu creio que deva
        ajudá-lo.

        Caso não fique claro, envie a estrutura das tabelas (DDL).

        --Observações sobre a consulta:

        SELECT
        vd.id_produto,
        p.descricao,

        /*Você também deve somar a quantidade sum(vd.qtde) */
        vd.qtde,


        sum(vd.qtde*vd.vlr_unit)
        FROM venda_det vd
        inner join produtos p on (vd.id_produto = p.id)

        /*inner join incompleto faltou o ON*/
        inner join venda_cab vc


        WHERE vc.data BETWEEN ?dataInicio and ?dataFinal

        /*
        *O ideal que o group by tenha a mesma quantidade de colunas do
        *select, apesar do mysql ignorar
        *group by vd.id_produto, p.descricao
        */
        group by vd.id_produto


        order by vd.qtde desc


        --------------------------------------------------------------------
        --Exemplo de sum com join no mysql

        /**
        *Criar tabela produtos.
        */
        CREATE TABLE produtos
        (
        id_produto int not null AUTO_INCREMENT,
        descricao varchar(200),
        CONSTRAINT produto_pk primary key(id_produto)
        );

        /**
        *Incluir os dados na tabela produtos.
        */
        INSERT INTO produtos(descricao) VALUES ('DVD');
        INSERT INTO produtos(descricao) VALUES ('HD 500 GB');
        INSERT INTO produtos(descricao) VALUES ('Tonner');
        INSERT INTO produtos(descricao) VALUES ('Cadeira');
        INSERT INTO produtos(descricao) VALUES ('Mesa');

        /**
        *Criar tabela venda_cab.
        */
        CREATE TABLE venda_cab
        (
        id_produto int,
        qtde int,
        vlr_unit numeric(15,2),
        data datetime,
        CONSTRAINT produto_fk foreign key(id_produto) REFERENCES produtos(id_produto)
        );

        /**
        *Inclui os dados na tabela venda_cab
        */
        INSERT INTO venda_cab VALUES(1, 1, 259.10, '2018-09-01 23:59:59');
        INSERT INTO venda_cab VALUES(1, 2, 300.00, '2018-09-07 22:44:06');

        INSERT INTO venda_cab VALUES(2, 8, 200.06, '2018-09-02 12:13:19');
        INSERT INTO venda_cab VALUES(2, 5, 220.00, '2018-09-08 15:44:25');

        INSERT INTO venda_cab VALUES(3, 9, 70.00, '2018-09-03 10:14:59');
        INSERT INTO venda_cab VALUES(3, 10, 90.06, '2018-09-10 16:24:59');

        INSERT INTO venda_cab VALUES(4, 49, 40.29, '2018-09-06 06:43');
        INSERT INTO venda_cab VALUES(4, 80, 30.00, '2018-09-11 05:44');

        INSERT INTO venda_cab VALUES(5, 49, 540.00, '2018-09-07 06:21');
        INSERT INTO venda_cab VALUES(5, 43, 530.37, '2018-09-12 10:22');

        /**
        *Consultar produtos vendidos dentro de um período
        */
        SELECT
        vd.id_produto,
        p.descricao,
        sum(vd.qtde) as qtd_total,
        sum(vd.qtde * vd.vlr_unit) as valor_total
        FROM venda_cab vd
        inner join produtos p on (vd.id_produto = p.id_produto)
        where
        CAST(data AS DATE) >= CAST('2018-09-01' AS DATE) AND
        CAST(data AS DATE) <= CAST('2018-09-30' AS DATE)
        group by
        vd.id_produto,
        p.descricao
        order by vd.qtde desc;

        Excluir
    12. Este comentário foi removido pelo autor.

      ResponderExcluir
    13. kelly achei no Blog, justamente o que estava procurando em 2020, me ajudou bastante:)

      ResponderExcluir
    14. Boas tarde!
      Preciso Pegar resultado "Sum(valor) As total" do MySql no CSharp. No MySql aparece o resultado dessa consulta, mas como pegar esse resultado em um programa usando Csharp?

      ResponderExcluir