AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 17267
Accepted
Matt Fenwick
Matt Fenwick
Asked: 2012-05-01 12:22:18 +0800 CST2012-05-01 12:22:18 +0800 CST 2012-05-01 12:22:18 +0800 CST

Como faço para criar uma função de agregação definida pelo usuário?

  • 772

Eu preciso de uma função agregada que o MySQL não fornece.

Eu gostaria que fosse no estilo SQL do MySQL (ou seja, não em C).

Como eu faço isso? O que estou travando é criar uma função agregada - os documentos não parecem mencionar como isso é feito.

Exemplos de uso desejado de uma productfunção:

mysql> select product(col) as a from `table`;
+------+
| a    |
+------+
|  144 |
+------+
1 row in set (0.00 sec)

mysql> select col, product(col) as a from `table` group by col;
+-----+------+
| col | a    |
+-----+------+
|   6 |   36 |
|   4 |    4 |
+-----+------+
2 rows in set (0.01 sec)
mysql aggregate
  • 4 4 respostas
  • 14214 Views

4 respostas

  • Voted
  1. ypercubeᵀᴹ
    2012-05-01T13:27:55+08:002012-05-01T13:27:55+08:00

    Não sei se há como definir uma nova função agregada, não sem mexer no código-fonte do MySQL.

    Mas se seus números são todos positivos, você pode derivar da identidade aritmética:

    log( product( Ai ) ) = sum( log( Ai ) )
    

    que você pode usar EXP(SUM(LOG(x)))para calcular PRODUCT(x). Teste no SQL-Fiddle :

    SELECT EXP(SUM(LOG(a))) AS product
    FROM t ;
    
    SELECT col, EXP(SUM(LOG(a))) AS product
    FROM t 
    GROUP BY col ;
    

    Quando os dados podem ter 0s, fica um pouco mais complicado:

    SELECT (NOT EXISTS (SELECT 1 FROM t WHERE a = 0)) 
           * EXP(SUM(LOG(a))) AS p
    FROM t 
    WHERE a > 0 ;
    
    SELECT d.col, 
           (NOT EXISTS (SELECT 1 FROM t AS ti WHERE ti.col = d.col AND ti.a = 0)) 
           * COALESCE(EXP(SUM(LOG(t.a))),1)  AS p
    FROM 
        ( SELECT DISTINCT col
          FROM t
        ) AS d
      LEFT JOIN
        t  ON  t.col = d.col
           AND t.a > 0
    GROUP BY d.col ;
    

    Testado no SQL-Fiddle


    Para outros SGBDs, que não possuam a autoconversão do MySQL de valores booleanos para inteiros, o

    (NOT EXISTS (SELECT ...))
    

    deve ser substituído por:

    (CASE WHEN EXISTS (SELECT 1...) THEN 0 ELSE 1 END) 
    

    Especificamente para o Oracle, serão necessárias mais algumas alterações, sem alterar a lógica da resposta, apenas porque o Oracle não segue rígido padrão ANSI em algumas áreas. Testado no SQL-Fiddle-2

    • 11
  2. Best Answer
    Colin 't Hart
    2012-10-18T06:11:28+08:002012-10-18T06:11:28+08:00

    De acordo com a documentação http://dev.mysql.com/doc/refman/5.5/en/adding-udf.html só é possível escrever funções agregadas em C. Desculpe!

    • 8
  3. Jeffrey Rolland
    2014-12-08T18:40:35+08:002014-12-08T18:40:35+08:00

    No interesse de aprender a pescar, compilei e instalei com sucesso um "Hello, World!" UDF (função definida pelo usuário) para MySQL encontrada aqui . O arquivo hello_world.so (depois de cumprido gcc -shared -o hello_world.so -I /usr/include/mysql hello_world.c) deve ser armazenado em /usr/lib/mysql/plugins/ com 755 permissões em sistemas Ubuntu linux. [O "-I /usr/include/mysql" é o caminho para os arquivos de cabeçalho mysql; Descobri que meu código não compilaria sem esse parâmetro, mas YMMV.]

    O programa não faz nada além de imprimir a string "Hello, World!" para cada registro no conjunto de dados resultante de uma consulta, mas isso é tudo o que deve fazer. Vou tentar escrever uma função de agregação PEQUENA nos próximos dias. Há um exemplo de função agregada que calcula o custo médio de um grupo de registros de preço e quantidade; a função SMALL não deve ser tão diferente dessa função no final.

    Espero que isto ajude.

    • 5
  4. golimar
    2021-04-07T23:47:21+08:002021-04-07T23:47:21+08:00

    Tecnicamente, não é uma função agregada definida pelo usuário e não é ideal, mas funciona e não precisa criar um UDF: use GROUP_CONCAT()em sua consulta, o que tornará sua consulta agregada e consolidará todos os valores em uma string separada por vírgula e em seguida, escreva uma função SQL que processe essa string.

    Exemplo (função baseada nesta resposta)::

    DELIMITER $$
    CREATE FUNCTION `replace_multiple`(_text text, _from text, _to text) RETURNS text CHARSET utf8mb4
        DETERMINISTIC
    BEGIN
    
    DECLARE _nextfrom TEXT DEFAULT NULL;
    DECLARE _nextto TEXT DEFAULT NULL;
    DECLARE _nextlenfrom INT DEFAULT NULL;
    DECLARE _nextlento INT DEFAULT NULL;
    DECLARE _valuefrom TEXT DEFAULT NULL;
    DECLARE _valueto TEXT DEFAULT NULL;
    
    iterator:
    LOOP
      -- exit the loop if the list seems empty or was null;
      -- this extra caution is necessary to avoid an endless loop in the proc.
      IF CHAR_LENGTH(TRIM(_from)) = 0 OR _from IS NULL THEN
        LEAVE iterator;
      END IF;
    
      -- capture the next value from the list
      SET _nextfrom = SUBSTRING_INDEX(_from,',',1);
      SET _nextto = SUBSTRING_INDEX(_to,',',1);
    
      -- save the length of the captured value; we will need to remove this
      -- many characters + 1 from the beginning of the string
      -- before the next iteration
      SET _nextlenfrom = CHAR_LENGTH(_nextfrom);
      SET _nextlento = CHAR_LENGTH(_nextto);
    
      -- trim the value of leading and trailing spaces, in case of sloppy CSV strings
      SET _valuefrom = TRIM(_nextfrom);
      SET _valueto = TRIM(_nextto);
    
      -- use the extracted value
      SET _text = replace(_text, _valuefrom, _valueto);
    
      -- rewrite the original string using the `INSERT()` string function,
      -- args are original string, start position, how many characters to remove,
      -- and what to "insert" in their place (in this case, we "insert"
      -- an empty string, which removes _nextlen + 1 characters)
      SET _from = INSERT(_from,1,_nextlenfrom + 1,'');
      SET _to = INSERT(_to,1,_nextlento + 1,'');
    END LOOP;
    
    RETURN _text;
    END$$
    DELIMITER ;
    

    Tábua:

    Eu iria deste para isso
    1 1 1
    2 2 dois
    3 3 três

    Consulta:

    SELECT replace_multiple('my 2 cents', GROUP_CONCAT(fromThis), GROUP_CONCAT(toThat))
    FROM t;
    

    Traduzirá para:

    SELECT replace_multiple('my 2 cents', '1,2,3', 'one,two,three')
    

    Qual para esta função personalizada específica retornarámy two cents

    • 0

relate perguntas

  • Existem ferramentas de benchmarking do MySQL? [fechado]

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

  • Quando é o momento certo para usar o MariaDB em vez do MySQL e por quê?

  • Como um grupo pode rastrear alterações no esquema do banco de dados?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como ver a lista de bancos de dados no Oracle?

    • 8 respostas
  • Marko Smith

    Quão grande deve ser o mysql innodb_buffer_pool_size?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    restaurar a tabela do arquivo .frm e .ibd?

    • 10 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve