mirror of
https://github.com/hoshikawa2/agent-ai-mcp-server.git
synced 2026-03-06 10:11:01 +00:00
104 lines
3.1 KiB
MySQL
104 lines
3.1 KiB
MySQL
|
|
-- DROP TYPES (se existirem)
|
|
BEGIN
|
|
EXECUTE IMMEDIATE 'DROP TYPE produto_resultado_tab';
|
|
EXECUTE IMMEDIATE 'DROP TYPE produto_resultado';
|
|
EXCEPTION
|
|
WHEN OTHERS THEN NULL;
|
|
END;
|
|
/
|
|
|
|
-- Criação de um tipo de tabela para retorno da função
|
|
CREATE OR REPLACE TYPE produto_resultado AS OBJECT (
|
|
codigo VARCHAR2(50),
|
|
descricao VARCHAR2(4000),
|
|
similaridade NUMBER
|
|
);
|
|
|
|
CREATE OR REPLACE TYPE produto_resultado_tab AS TABLE OF produto_resultado;
|
|
/
|
|
|
|
-- Função de busca fonética e por palavras-chave
|
|
CREATE OR REPLACE FUNCTION fn_busca_avancada(p_termos IN VARCHAR2)
|
|
RETURN produto_resultado_tab PIPELINED
|
|
AS
|
|
v_termos SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST();
|
|
v_token VARCHAR2(1000);
|
|
v_descricao VARCHAR2(4000);
|
|
v_score NUMBER;
|
|
v_dummy NUMBER;
|
|
BEGIN
|
|
-- Dividir os termos da busca
|
|
FOR i IN 1..REGEXP_COUNT(p_termos, '\S+') LOOP
|
|
v_termos.EXTEND;
|
|
v_termos(i) := LOWER(REGEXP_SUBSTR(p_termos, '\S+', 1, i));
|
|
END LOOP;
|
|
|
|
-- Loop pelos produtos
|
|
FOR prod IN (SELECT codigo, descricao FROM produtos) LOOP
|
|
v_descricao := LOWER(prod.descricao);
|
|
v_score := 0;
|
|
|
|
-- Avaliar cada termo da busca
|
|
FOR i IN 1..v_termos.COUNT LOOP
|
|
v_token := v_termos(i);
|
|
|
|
-- 3 pontos se encontrar diretamente
|
|
IF v_descricao LIKE '%' || v_token || '%' THEN
|
|
v_score := v_score + 3;
|
|
ELSE
|
|
-- 2 pontos se foneticamente similar
|
|
BEGIN
|
|
SELECT 1 INTO v_dummy FROM dual
|
|
WHERE SOUNDEX(v_token) IN (
|
|
SELECT SOUNDEX(REGEXP_SUBSTR(v_descricao, '\w+', 1, LEVEL))
|
|
FROM dual
|
|
CONNECT BY LEVEL <= REGEXP_COUNT(v_descricao, '\w+')
|
|
);
|
|
v_score := v_score + 2;
|
|
EXCEPTION
|
|
WHEN NO_DATA_FOUND THEN NULL;
|
|
END;
|
|
|
|
-- 1 ponto se similar por escrita
|
|
BEGIN
|
|
SELECT 1 INTO v_dummy FROM dual
|
|
WHERE EXISTS (
|
|
SELECT 1
|
|
FROM (
|
|
SELECT REGEXP_SUBSTR(v_descricao, '\w+', 1, LEVEL) AS palavra
|
|
FROM dual
|
|
CONNECT BY LEVEL <= REGEXP_COUNT(v_descricao, '\w+')
|
|
)
|
|
WHERE UTL_MATCH.EDIT_DISTANCE(palavra, v_token) <= 2
|
|
);
|
|
v_score := v_score + 1;
|
|
EXCEPTION
|
|
WHEN NO_DATA_FOUND THEN NULL;
|
|
END;
|
|
END IF;
|
|
END LOOP;
|
|
|
|
-- Só retorna se houver ao menos algum match
|
|
IF v_score > 0 THEN
|
|
PIPE ROW(produto_resultado(prod.codigo, prod.descricao, v_score));
|
|
END IF;
|
|
END LOOP;
|
|
|
|
RETURN;
|
|
END;
|
|
/
|
|
|
|
-- Grant para execução, se necessário:
|
|
GRANT EXECUTE ON fn_busca_fonetica_por_palavra TO PUBLIC;
|
|
|
|
|
|
-- Testes
|
|
SELECT *
|
|
FROM TABLE(fn_busca_avancada('harry poter pedra'))
|
|
ORDER BY similaridade DESC;
|
|
|
|
SELECT * FROM TABLE(fn_busca_fonetica_por_palavra('velho mar'))
|
|
ORDER BY similaridade DESC;
|
|
|
|
|