176 lines
9.2 KiB
SQL
176 lines
9.2 KiB
SQL
create or replace function FNC_26ai_query_INSIGHTS_LIST(p_query_id IN VARCHAR2,
|
||
p_comp_id in varchar2,
|
||
p_credential in varchar2 default 'OCI_CRED')
|
||
return t_26ai_array pipelined parallel_enable
|
||
as
|
||
l_sql VARCHAR2(4000) ;
|
||
|
||
l_cursor_id INTEGER;
|
||
l_desc_tab dbms_sql.desc_tab;
|
||
l_col_cnt INTEGER;
|
||
|
||
v_labels clob;
|
||
v_label_char varchar2(400);
|
||
v_label_number varchar2(400);
|
||
v_label_date varchar2(400);
|
||
|
||
v_str_to_llm clob;
|
||
v_insigths clob;
|
||
|
||
v_has number ;
|
||
-- funcao pipeline de retorno
|
||
v_id number := 0 ;
|
||
v_array t_26ai_array := t_26ai_array();
|
||
|
||
v_ignore_group varchar2(1);
|
||
|
||
begin
|
||
|
||
begin
|
||
select query_text
|
||
into l_sql
|
||
from TB_26AI_QUERY_HISTORY
|
||
where query_id = p_query_id;
|
||
|
||
v_has := 1;
|
||
|
||
exception
|
||
when no_data_found then
|
||
v_has := 0 ;
|
||
dbms_output.put_line(' Registro nao existente para a query ');
|
||
end;
|
||
|
||
if v_has = 1 then
|
||
|
||
--
|
||
-- rotina de identificacao de grupos (data types) baseado nos tipos de dados nas colunas da consulta
|
||
--
|
||
BEGIN
|
||
|
||
v_ignore_group := 'N';
|
||
|
||
l_cursor_id := DBMS_SQL.OPEN_CURSOR;
|
||
dbms_sql.parse(l_cursor_id, l_sql, dbms_sql.native);
|
||
dbms_sql.describe_columns(l_cursor_id, l_col_cnt, l_desc_tab);
|
||
|
||
FOR i IN 1..l_col_cnt LOOP
|
||
|
||
if l_desc_tab(i).col_type not in (2,12) then -- varchar2
|
||
v_str_to_llm := v_str_to_llm || 'Column ' || i || ' Data Type VARCHAR2: ' || l_desc_tab(i).col_name || ', ';
|
||
v_label_char := v_label_char || l_desc_tab(i).col_name || ', ';
|
||
|
||
elsif l_desc_tab(i).col_type = 2 then -- number
|
||
v_str_to_llm := v_str_to_llm || 'Column ' || i || ' Data Type NUMBER: ' || l_desc_tab(i).col_name || ', ';
|
||
v_label_number := v_label_number || l_desc_tab(i).col_name || ', ';
|
||
|
||
elsif l_desc_tab(i).col_type = 12 then -- date
|
||
v_str_to_llm := v_str_to_llm || 'Column ' || i || ' Data Type DATE: ' || l_desc_tab(i).col_name || ', ';
|
||
v_label_date := v_label_date || l_desc_tab(i).col_name || ', ';
|
||
|
||
end if;
|
||
END LOOP;
|
||
v_labels := 'Colunas: (' || v_label_char || v_label_number || v_label_date || ')';
|
||
v_labels := replace(v_labels,', )',')');
|
||
|
||
EXCEPTION
|
||
WHEN OTHERS THEN
|
||
v_ignore_group := 'Y';
|
||
dbms_output.put_line( sqlerrm );
|
||
END;
|
||
|
||
v_insigths := FNC_26AI_RAG('O SQL executado no Oracle para referência: ' || l_sql || '.' ||
|
||
'Colunas e data types: ' || v_str_to_llm || '.' ||
|
||
' As colunas são classificadas de 2 tipos:' ||
|
||
' Quantificadores: São entidades, fazem a contagem de alguma informação, são as colunas de agru-padores. Ela é a informação para ser analisar.' ||
|
||
' O "Geral" será sempre implícito.' ||
|
||
' Totalizadores: Fazem a totalização de uma informação, baseada na soma, média, mínimo, máximo, etc.' ||
|
||
' O treinamento da IA precisa ser feito para que ela compreenda que colunas de tabelas que:' ||
|
||
' As que iniciam com "cd_" e que são PK, são quantificadores/entidades.' ||
|
||
' As que iniciam com "dt_" e tem tipo date/datetime/timestamp são informações de uma data, que se pode quebar a informação em dia, mês, ano e dia da semana' ||
|
||
' As que iniciam com "qt_" ou possuem "quantidade", "qtde" e são de tipos numéricos (inteiro ou decimais) são informações totalizadoras.' ||
|
||
' As que iniciam com "vl" ou possuem "valor" e são de tipos numéricos (inteiro ou decimais) são in-formações totalizadoras.' ||
|
||
' Basicamente terá um padrão de nomes. Comentários nas colunas no banco podem ajudar na formatação do resultado do insight, conforme visto mais adiante.' ||
|
||
' Os totalizadores compostos são totais extraídos da soma de várias colunas Totalizadoras. Por exemplo, uma consulta que possui as colunas "icms", "ipi", "pis", "cofins" ' ||
|
||
' irão possuir os totalizadores conforme vistos antes, com agrupamentos também conforme vistos antes. No entanto, poderá haver também um totalizador composto chamado ' ||
|
||
' "Valor dos impostos" que será o resultado da soma desses 4 impostos. Esse totalizador composto é também pode aplicar totalizações pelas colunas Quantificadores ' ||
|
||
' (Valor de impostos por geral, Valor de impostos por cd_material, etc).' ||
|
||
' Tipos de insights' ||
|
||
' Os exemplos anteriores baseiam-se em totalizações por soma, média, mínimo e máximo. Esses exemplos foram simplificados para compreendimento do funcionamento.' ||
|
||
' Avançando nesse sentido, para que os insights possam gerar informações de alto nível, outros cálculos de estatística descritiva podem ser adicionados, como média, ' ||
|
||
' mediana, moda e desvio padrão, bem como técnicas estatísticas de detecção de anomalias, como granularidades horária, diária, semanais e mensais, além de muitas' ||
|
||
' outras utilizadas normalmente em dashboard de BI’s.' ||
|
||
' Considerando os exemplos que vimos anteriormente, poderão ser gerados insights automáticos para fornecer informações que responderiam as seguintes análises:' ||
|
||
' Qual material eu mais movimento?' ||
|
||
' Qual dia da semana mais movimento materiais?' ||
|
||
' Qual a variação percentual entre o valor mínimo e o máximo do material "X"?' ||
|
||
' Qual o maior desvio entre a quantidade do material "Y";' ||
|
||
' Qual o maior e menor intervalo de tempo de movimentação de um material?' ||
|
||
' Exemplo de insight:' ||
|
||
' ID: 1' ||
|
||
' Insight: Contagem por cd_material' ||
|
||
' Informação: count(*)' ||
|
||
' Como: group by cd_material' ||
|
||
' Por exemplo: para o Oracle SQL "SELECT CD_MOVIMENTO, DT_MOVIMENTO, CD_MATERIAL, QUANTIDADE, VALOR FROM ESMOVIME" ' ||
|
||
' Temos: ' ||
|
||
' QUANTIFICADOR: select CD_MOVIMENTO, count(*) FROM ESMOVIME group by CD_MOVIMENTO ' ||
|
||
' TOTALIZADOR: select max(QUANTIDADE), min(QUANTIDADE), avg(QUANTIDADE), sum(QUANTIDADE) FROM ESMOVIME ' ||
|
||
' Gere insigths deste tipo, incluindo composicao de colunas para que seja possivel gerar maior numero de insigths possivel: ' ||
|
||
case
|
||
when v_ignore_group = 'N' then
|
||
' Composição de colunas VARCHAR2: ' || v_label_char || ' ' ||
|
||
' Composição de colunas NUMBER: ' || v_label_number || ' ' ||
|
||
' Composição de colunas DATE: ' || v_label_date
|
||
end ||
|
||
' O resultado deve ser um documento em JSON, com atributos: "tipo" (totalizador ou quantificador), ' ||
|
||
' "descricao" (se será uma contagem, soma, média, e sobre qual colunas ou colunas), "insigth", "informacao" ' ||
|
||
' (descrição de como realizar o insight), "sql" (comando). ' ||
|
||
' Exemplo de JSON e sua estrutura: ' ||
|
||
'{ "tipo": "quantificador", ' ||
|
||
' "descricao": "Contagem por CD_MOVIMENTO", ' ||
|
||
' "insight": "Contagem de movimentos", ' ||
|
||
' "informacao": "Count(*)", ' ||
|
||
' "sql": "SELECT CD_MOVIMENTO, COUNT(*) FROM ESMOVIME GROUP BY CD_MOVIMENTO" } ' ||
|
||
' Certifique-se de que o JSON gerado não contenha comentários, caracteres extras ou ' ||
|
||
' qualquer outro elemento que invalide o JSON.', p_credential,p_comp_id);
|
||
|
||
|
||
else -- v_has = 0
|
||
|
||
dbms_output.put_line(' Insights ja existem para SQL ' || p_query_id );
|
||
|
||
end if;
|
||
|
||
|
||
dbms_output.put_line(v_insigths);
|
||
|
||
-- retorno da funcao pipeline
|
||
for r1 in ( SELECT jt.tipo, jt.descricao, jt.insight, jt.informacao, jt.sql_query, p_query_id, sysdate
|
||
FROM JSON_TABLE(
|
||
replace( substr( v_insigths,
|
||
instr( v_insigths , '```' ) + 3,
|
||
instr( v_insigths , '```',1,2) - instr( v_insigths , '```' ,1,1) - 3
|
||
) , 'json', '')
|
||
,
|
||
'$[*]' COLUMNS (
|
||
tipo VARCHAR2(50) PATH '$.tipo',
|
||
descricao VARCHAR2(255) PATH '$.descricao',
|
||
insight VARCHAR2(255) PATH '$.insight',
|
||
informacao VARCHAR2(255) PATH '$.informacao',
|
||
sql_query VARCHAR2(1000) PATH '$.sql'
|
||
)
|
||
) jt ) loop
|
||
v_id := v_id + 1;
|
||
v_array.extend;
|
||
v_array(v_array.last) := t_26ai_insight_record(v_id,
|
||
r1.tipo ,
|
||
r1.descricao ,
|
||
r1.insight ,
|
||
r1.informacao ,
|
||
r1.sql_query,
|
||
p_query_id,
|
||
sysdate);
|
||
PIPE ROW( v_array(v_id) );
|
||
end loop;
|
||
|
||
end;
|
||
/ |