diff --git a/macros/clean_abe_obs.sql b/macros/clean_abe_obs.sql new file mode 100644 index 00000000..b91a5929 --- /dev/null +++ b/macros/clean_abe_obs.sql @@ -0,0 +1,9 @@ + +{% macro clean_abe_obs(text) %} +CASE + WHEN {{text}} = '' THEN null + WHEN regexp_contains(lower(trim({{text}})),r'^((\.)|(none)|(baixa autom[á|a]tica)|(alta)|(alta ((com orientaç[õ|o]es)|(m[é|e]dica)|(administrativa)|(hospitalar)|(com prescr medica)))|(o+p)|(prescrevo( *e *oriento){0,1})|(prescriç[ã|a]o e orientaçao pa{0,1}ra casa)|(segue de alta com orientaç[o|õ]es gerais e sobre riscos e prescriç[a|ã]o)|((com ){0,1}orientaç[o|õ]es)|(orientaç[a|ã]o))$') THEN null + ELSE {{text}} +END + +{% endmacro %} \ No newline at end of file diff --git a/macros/clean_cid.sql b/macros/clean_cid.sql index 7e6d7182..76063ece 100644 --- a/macros/clean_cid.sql +++ b/macros/clean_cid.sql @@ -1,18 +1,33 @@ {% macro clean_cid(text) %} - +CASE +WHEN regexp_contains(lower({{text}}),'gravidez.*') THEN {{text}} +ELSE regexp_replace( regexp_replace( regexp_replace( - {{text}}, - 'Emissão de prescrição de repetição', - '' + regexp_replace( + regexp_replace( + regexp_replace( + lower({{text}}), + r'(em circunstâncias não especificadas)|(e a causas não especificadas)|(não classificad[o|a]s em outra parte)|([(sem)|(com)] confirmação bacteriológica ou histológica)|((, ){0,1}e [à|a|o]s não especificad[a|o]s)|(outras formas e as não especificadas da )|(de localização não especificada)|(^alguns)|(algumas)|(emissão de prescrição de repetição)|(, nível não especificado)', + '' + ), + '(^outr[a|o]s{0,1}( (tipos|formas) de ){0,1})|(não especificadas)', + '' + ), + r'.*[E|e]xames* .*', + 'Exame' + ), + r'(^ +)|(,{0,1} {0,1}$)|[( [][ a-z-à-ü-0-9]+[])]|(,,)', + '' ), - '[E|e]xames* .*', - 'Exame' + ' {2,}', + ' ' ), - r' [\(|\[].*[\]|\)]', - '' + ' {1,}, {1,}', + ', ' ) +END {% endmacro %} \ No newline at end of file diff --git a/models/intermediate/historico_clinico/cid/int_historico_clinico__cid_categoria.sql b/models/intermediate/historico_clinico/cid/int_historico_clinico__cid_categoria.sql index 32e20703..ecb6e321 100644 --- a/models/intermediate/historico_clinico/cid/int_historico_clinico__cid_categoria.sql +++ b/models/intermediate/historico_clinico/cid/int_historico_clinico__cid_categoria.sql @@ -1,12 +1,16 @@ +--Cria tabela de de-para da categoria e sua descrição resumida. +--O resumo de descrição é construído como o nível de agrupamento da categoria que possui o menor número de caracteres. with cids as ( select distinct categoria.id as id_categoria, categoria.descricao as categoria_descricao, + {{clean_cid('categoria.descricao')}} as categoria_descricao_c, grupo.descricao as grupo_descricao, - grupo.abreviatura as grupo_abreviatura, - char_length(categoria.descricao) as len_categoria, - char_length(grupo.descricao) as len_grupo, + {{clean_cid('grupo.descricao')}} as grupo_descricao_c, + char_length({{clean_cid('categoria.descricao')}}) as len_categoria, + char_length({{clean_cid('grupo.descricao')}}) as len_grupo, + from {{ ref("dim_condicao_cid10") }}, unnest(grupo) as grupo qualify dense_rank() over (partition by id order by grupo.comprimento asc) = 1 ), @@ -35,9 +39,9 @@ with get_best_agg_3_dig.id_categoria, case when agrupador = 'len_categoria' - then categoria_descricao + then categoria_descricao_c when agrupador = 'len_grupo' - then grupo_descricao + then grupo_descricao_c end as best_agrupador from get_best_agg_3_dig left join @@ -45,6 +49,19 @@ with on get_best_agg_3_dig.id_categoria = cids.id_categoria ) -select * from agg_3_dig where id_categoria != 'U07' +select + id_categoria, + CASE + WHEN (char_length(best_agrupador)-1 > 0) + THEN + CONCAT( + UPPER(LEFT(best_agrupador,1)), + RIGHT(best_agrupador,char_length(best_agrupador)-1) + ) + ELSE + best_agrupador + END as best_agrupador +from agg_3_dig where id_categoria != 'U07' +-- Contornando CIDs de COVID que atualmente fazem parte de um grupos de "códigos para uso de emergência", sendo não informativo para o resumo union all select 'U07', 'COVID19' \ No newline at end of file diff --git a/models/intermediate/historico_clinico/cid/int_historico_clinico__cid_subcategoria.sql b/models/intermediate/historico_clinico/cid/int_historico_clinico__cid_subcategoria.sql index f3fc2ede..a6af1291 100644 --- a/models/intermediate/historico_clinico/cid/int_historico_clinico__cid_subcategoria.sql +++ b/models/intermediate/historico_clinico/cid/int_historico_clinico__cid_subcategoria.sql @@ -1,15 +1,19 @@ +--Cria tabela de de-para da subcategoria e sua descrição resumida. +--O resumo de descrição é construído como o nível de agrupamento da subcategoria que possui o menor número de caracteres. with cids as ( select id, categoria.id as id_categoria, - cid.descricao, + cid.descricao as subcategoria_descricao, + {{clean_cid('cid.descricao')}} as subcategoria_descricao_c, categoria.descricao as categoria_descricao, + {{clean_cid('categoria.descricao')}} as categoria_descricao_c, grupo.descricao as grupo_descricao, - grupo.abreviatura as grupo_abreviatura, - char_length(cid.descricao) as len_subcategoria, - char_length(categoria.descricao) as len_categoria, - char_length(grupo.descricao) as len_grupo, + {{clean_cid('grupo.descricao')}} as grupo_descricao_c, + char_length({{clean_cid('cid.descricao')}}) as len_subcategoria, + char_length({{clean_cid('categoria.descricao')}}) as len_categoria, + char_length({{clean_cid('grupo.descricao')}}) as len_grupo, from {{ ref("dim_condicao_cid10") }} as cid, unnest(grupo) as grupo @@ -24,7 +28,7 @@ with ), get_min_len_4_dig as ( - select id, id_categoria, min(len) as min_len from pivoting_4_dig group by 1, 2 + select id, min(len) as min_len from pivoting_4_dig group by 1 ), get_best_agg_4_dig as ( @@ -44,24 +48,39 @@ with agg_4_dig as ( select get_best_agg_4_dig.id, - descricao, - get_best_agg_4_dig.id_categoria, + subcategoria_descricao, + categoria_descricao, + grupo_descricao, + id_categoria, case when agrupador = 'len_categoria' - then categoria_descricao + then categoria_descricao_c when agrupador = 'len_subcategoria' - then descricao + then subcategoria_descricao_c when agrupador = 'len_grupo' - then grupo_descricao + then grupo_descricao_c end as best_agrupador from get_best_agg_4_dig left join cids on get_best_agg_4_dig.id = cids.id ) -select * +select + id, + subcategoria_descricao, + id_categoria, + CASE + WHEN (char_length(best_agrupador)-1 > 0) + THEN + CONCAT( + UPPER(LEFT(best_agrupador,1)), + RIGHT(best_agrupador,char_length(best_agrupador)-1) + ) + ELSE best_agrupador + END as best_agrupador from agg_4_dig where id not in ('U071', 'U072') +-- Contornando CIDs de COVID que atualmente fazem parte de um grupos de "códigos para uso de emergência", sendo não informativo para o resumo union all select 'U071', 'COVID19, virus identificado', 'U07', 'COVID19' union all -select 'U072', 'COVID19, virus não identificado', 'U07', 'COVID19' +select 'U072', 'COVID19, virus não identificado', 'U07', 'COVID19' \ No newline at end of file diff --git a/models/intermediate/historico_clinico/episodio/int_historico_clinico__episodio__vitacare.sql b/models/intermediate/historico_clinico/episodio/int_historico_clinico__episodio__vitacare.sql index 9de361b2..dcac6350 100644 --- a/models/intermediate/historico_clinico/episodio/int_historico_clinico__episodio__vitacare.sql +++ b/models/intermediate/historico_clinico/episodio/int_historico_clinico__episodio__vitacare.sql @@ -63,9 +63,14 @@ with -- -=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=-- -- DIM: Condições -- -=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=-- - cid_descricao as (select * from {{ ref("raw_datasus__cid10") }}), + cid_descricao as ( + select distinct id, descricao from {{ ref("dim_condicao_cid10") }} + union all + select distinct categoria.id as id, categoria.descricao as descricao from {{ ref("dim_condicao_cid10") }} + ), condicoes as ( select + distinct gid as fk_atendimento, json_extract_scalar(condicao_json, "$.cod_cid10") as id, @@ -90,14 +95,16 @@ with array_agg( struct( condicoes.id as id, - cid_descricao.subcategoria_descricao as descricao, + cid_descricao.descricao, condicoes.situacao as situacao, condicoes.data_diagnostico as data_diagnostico ) - order by data_diagnostico desc, subcategoria_descricao + order by data_diagnostico desc, cid_descricao.descricao ) as condicoes from condicoes - left join cid_descricao on condicoes.id = cid_descricao.id_subcategoria + left join ( + select distinct id, descricao from cid_descricao + ) as cid_descricao on condicoes.id = cid_descricao.id group by fk_atendimento ), -- -=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=-- @@ -173,8 +180,8 @@ with safe_cast(datahora_fim as datetime) as saida_datahora, -- Motivo e Desfecho - upper(soap_subjetivo_motivo) as motivo_atendimento, - upper(soap_plano_observacoes) as desfecho_atendimento, + upper(trim(soap_subjetivo_motivo)) as motivo_atendimento, + upper(trim(soap_plano_observacoes)) as desfecho_atendimento, -- Condições dim_condicoes_atribuidas.condicoes, @@ -244,3 +251,4 @@ from episodios_validos {% if is_incremental() %} where data_particao >= {{ partitions_to_replace }} {% endif %} + diff --git a/models/intermediate/historico_clinico/episodio/int_historico_clinico__episodio__vitai.sql b/models/intermediate/historico_clinico/episodio/int_historico_clinico__episodio__vitai.sql index cdbf3ea4..8ed0861c 100644 --- a/models/intermediate/historico_clinico/episodio/int_historico_clinico__episodio__vitai.sql +++ b/models/intermediate/historico_clinico/episodio/int_historico_clinico__episodio__vitai.sql @@ -10,27 +10,26 @@ with -- Tabelas uteis para o episodio -- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- Desfecho do atendimento - alta_adm as ( - select gid_boletim, alta_tipo_detalhado + + alta_adm as ( -- Alta administrativa (consultas) + select + gid_boletim, + {{ process_null("alta_tipo_detalhado") }} as alta_adm_tipo, + {{clean_abe_obs('abe_obs')}} as alta_adm_descricao from {{ ref("raw_prontuario_vitai__alta") }} + qualify row_number() over ( partition by gid_boletim order by datahora desc) = 1 ), - desfecho_atendimento_all as ( + alta_internacao as ( -- Resumo de alta (internação) select resumo_alta.gid_boletim, resumo_alta.resumo_alta_datahora, - {{ process_null("resumo_alta.resumo_alta_descricao") }} - as resumo_alta_descricao, - {{ process_null("alta_adm.alta_tipo_detalhado") }} as alta_adm_tipo, {{ process_null("resumo_alta.desfecho_internacao") }} as resumo_alta_tipo, - row_number() over ( - partition by resumo_alta.gid_boletim - order by resumo_alta.resumo_alta_datahora desc - ) as ordenacao + CASE + WHEN lower(trim(resumo_alta.resumo_alta_descricao)) in ('acima','anexo','no prontuário','no prontuario') THEN null + ELSE {{ process_null("resumo_alta.resumo_alta_descricao") }} + END as resumo_alta_descricao from {{ ref("raw_prontuario_vitai__resumo_alta") }} as resumo_alta - left join alta_adm on alta_adm.gid_boletim = resumo_alta.gid_boletim - ), - desfecho_atendimento_final as ( - select * from desfecho_atendimento_all where ordenacao = 1 + qualify row_number() over ( partition by resumo_alta.gid_boletim order by resumo_alta.resumo_alta_datahora desc) = 1 ), -- Estabelecimento com infos da tabela mestre estabelecimentos as ( @@ -100,32 +99,49 @@ with -- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- Tabela de consultas -- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -- Como cada atendimento appenda informações no boletim, pegamos a queixa do - -- ultimo atendimento - queixa_all as ( - select - gid_boletim, - queixa, - inicio_datahora, - gid_profissional, - row_number() over ( - partition by gid_boletim order by inicio_datahora desc - ) as ordenacao - from {{ ref("raw_prontuario_vitai__atendimento") }} + -- Se o ultimo atendimento conter as informações de queixa do primeiro, puxamos apenas o ultimo. Caso contrário, concatenamos o primeiro e o segundo + queixas_all as + ( + select + gid_boletim, + trim(upper(queixa)) as queixa, + inicio_datahora, + gid_profissional, + row_number() over ( + partition by gid_boletim order by inicio_datahora desc + ) as ordenacao_desc, + row_number() over ( + partition by gid_boletim order by inicio_datahora asc + ) as ordenacao_asc, + FROM {{ref('raw_prontuario_vitai__atendimento')}} + order by 1 ), queixa_final as ( - select - gid_boletim, - gid_profissional, - case - when {{ process_null("queixa") }} is null - then null - else upper(trim(queixa)) - end as queixa - from queixa_all - where ordenacao = 1 + select distinct + boletins.gid_boletim, + queixa_final.gid_profissional, + CASE -- compara os caracteres que deveriam ser da queixa inicial e calcula se distancia de Levenshtein é pequena o suficiente + WHEN edit_distance(left(queixa_final.queixa,char_length(queixa_inicial.queixa)),queixa_inicial.queixa) <= (char_length(queixa_inicial.queixa))/2 + THEN upper(trim(queixa_final.queixa)) + ELSE CONCAT(upper(trim(queixa_inicial.queixa)),'\n',upper(trim(queixa_final.queixa))) + END as queixa + from + (select distinct gid_boletim from queixas_all ) as boletins + left join ( + select gid_boletim, queixa, gid_profissional + from queixas_all + where ordenacao_desc = 1 + ) as queixa_final + on queixa_final.gid_boletim = boletins.gid_boletim + left join ( + select gid_boletim, queixa + from queixas_all + where ordenacao_asc = 1 + ) as queixa_inicial + on queixa_inicial.gid_boletim = boletins.gid_boletim + ), - -- Monta estrurra array aninhada de profissionais do episódio + -- Monta estrutura array aninhada de profissionais do episódio profissional_distinct as ( select distinct queixa_final.gid_boletim as gid_boletim, @@ -137,6 +153,7 @@ with from queixa_final left join profissional on queixa_final.gid_profissional = profissional.gid ), + -- Tabela final de consulta consulta as ( select boletim.*, @@ -150,7 +167,16 @@ with ) as profissional_saude_responsavel, {{ process_null("atendimento.cid_codigo") }} as cid_codigo, {{ process_null("atendimento.cid_nome") }} as cid_nome, - desfecho_atendimento_final.alta_adm_tipo as desfecho_atendimento, + CASE + WHEN + alta_adm.alta_adm_tipo is null and alta_adm.alta_adm_descricao is null THEN null + ELSE + CONCAT( + IF(alta_adm.alta_adm_tipo is null,'',upper(trim(alta_adm.alta_adm_tipo))), + '\n', + IF(alta_adm.alta_adm_descricao is null,'',upper(trim(alta_adm.alta_adm_descricao))) + ) + END as desfecho_atendimento, case when trim(lower(boletim.atendimento_tipo)) = 'emergencia' then 'Emergência' @@ -163,14 +189,13 @@ with cast(null as string) as tipo, cast(null as string) as descricao ) as exames_realizados from boletim + left join alta_adm + on boletim.gid = alta_adm.gid_boletim left join {{ ref("raw_prontuario_vitai__atendimento") }} as atendimento on boletim.gid = atendimento.gid_boletim left join profissional_distinct on profissional_distinct.gid_boletim = boletim.gid - left join - desfecho_atendimento_final - on desfecho_atendimento_final.gid_boletim = boletim.gid where atendimento.gid_boletim is not null and boletim.internacao_data is null ), -- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @@ -208,19 +233,24 @@ with ) as profissional_saude_responsavel, internacao_distinct.cid_codigo, internacao_distinct.cid_nome, - regexp_replace( - regexp_replace( - concat( - upper(trim(desfecho_atendimento_final.resumo_alta_tipo)), - '\n', - upper(trim(desfecho_atendimento_final.resumo_alta_descricao)) - ), - '[Ó|O]BITO {1,}\n[Ó|O]BITO', - 'OBITO' - ), - 'TRANSFER[E|Ê]NCIA {1,}\nTRANSF[E|Ê]RENCIA', - 'TRANSFERÊNCIA' - ) as desfecho_atendimento, + CASE + WHEN + alta_internacao.resumo_alta_tipo is null and alta_internacao.resumo_alta_descricao is null THEN null + ELSE + regexp_replace( + regexp_replace( + concat( + IF(alta_internacao.resumo_alta_tipo is null,'',upper(trim(alta_internacao.resumo_alta_tipo))), + '\n', + IF(alta_internacao.resumo_alta_descricao is null, '',upper(trim(alta_internacao.resumo_alta_descricao))) + ), + '[Ó|O]BITO {1,}\n[Ó|O]BITO', + 'OBITO' + ), + 'TRANSFER[E|Ê]NCIA {1,}\nTRANSF[E|Ê]RENCIA', + 'TRANSFERÊNCIA' + ) + END as desfecho_atendimento, case when trim(lower(internacao_distinct.internacao_tipo)) = 'emergencia' then 'Emergência' @@ -235,8 +265,8 @@ with (select * from internacao_all where ordenacao = 1) internacao_distinct on boletim.gid = internacao_distinct.gid_boletim left join - desfecho_atendimento_final - on desfecho_atendimento_final.gid_boletim = boletim.gid + alta_internacao + on alta_internacao.gid_boletim = boletim.gid where internacao_distinct.gid_boletim is not null and boletim.internacao_data is not null @@ -330,14 +360,14 @@ with cid_distinct as ( select distinct episodios.gid as id, - IF(episodios.cid_codigo is null, c.id_subcategoria, episodios.cid_codigo) as cid_id, + IF(episodios.cid_codigo is null, c.id, episodios.cid_codigo) as cid_id, episodios.cid_nome as cid_nome, from episodios left join ( - select distinct id_subcategoria, subcategoria_descricao - from {{ ref('raw_datasus__cid10') }} + select id, descricao + from {{ ref('dim_condicao_cid10') }} ) as c - on c.subcategoria_descricao = episodios.cid_nome + on c.descricao = episodios.cid_nome where (cid_codigo is not null or cid_nome is not null) ), cid_grouped as ( diff --git a/models/marts/core/dimensions/_dimensions_schema.yml b/models/marts/core/dimensions/_dimensions_schema.yml index 34c19841..85034a28 100644 --- a/models/marts/core/dimensions/_dimensions_schema.yml +++ b/models/marts/core/dimensions/_dimensions_schema.yml @@ -521,7 +521,7 @@ models: - name: outros_profissionais description: Código SUS dos outros profissionais atribuidos a equipe - name: dim_condicao_cid10 - description: Tabela contendo a Classificação Internacional de Doenças (CID-10). + description: Tabela contendo a Classificação Internacional de Doenças (CID-10). Contém CID S44.6 e S44.5 com mesmas entradas pois S44.6 foi alterado para S44.5 em 2002. columns: - name: id description: Identificação da subcategoria do CID. diff --git a/models/marts/historico_clinico/mart_historico_clinico__episodio.sql b/models/marts/historico_clinico/mart_historico_clinico__episodio.sql index e40544c3..eb5088ee 100644 --- a/models/marts/historico_clinico/mart_historico_clinico__episodio.sql +++ b/models/marts/historico_clinico/mart_historico_clinico__episodio.sql @@ -90,7 +90,7 @@ with cid.descricao, cid.situacao, cid.data_diagnostico, - IF(cid.situacao = 'RESOLVIDO',null,{{clean_cid('best_agrupador')}}) as descricao_agg + IF(cid.situacao = 'RESOLVIDO',null,best_agrupador) as descricao_agg from deduped, unnest(condicoes) as cid LEFT JOIN {{ ref("int_historico_clinico__cid_subcategoria") }} as agg_4_dig on agg_4_dig.id = regexp_replace(cid.id,r'\.','') @@ -103,7 +103,7 @@ with cid.descricao, cid.situacao, cid.data_diagnostico, - IF(cid.situacao = 'RESOLVIDO',null,{{clean_cid('best_agrupador')}}) as descricao_agg + IF(cid.situacao = 'RESOLVIDO',null,best_agrupador) as descricao_agg from deduped, unnest(condicoes) as cid LEFT JOIN {{ ref("int_historico_clinico__cid_categoria") }} as agg_3_dig on agg_3_dig.id_categoria = regexp_replace(cid.id,r'\.','') diff --git a/models/marts/historico_clinico_app/mart_historico_clinico_app__episodio.sql b/models/marts/historico_clinico_app/mart_historico_clinico_app__episodio.sql index b638c8ff..b24c6fd0 100644 --- a/models/marts/historico_clinico_app/mart_historico_clinico_app__episodio.sql +++ b/models/marts/historico_clinico_app/mart_historico_clinico_app__episodio.sql @@ -70,7 +70,7 @@ with where tipo is not null ) as clinical_exams, array( - select descricao from unnest(condicoes) where descricao is not null + select distinct descricao from unnest(condicoes) where descricao is not null and situacao <> 'RESOLVIDO' ) as active_cids, array( select distinct resumo from unnest(condicoes) where resumo is not null and resumo != ''