Notas e Técnicas Avançadas de SQL

1. Prioridade de Operações no SQL

2. Funções de Agregação

As cinco funções de agregação comuns são: MAX, MIN, SUM, AVG e COUNT.

3. Subconsultas Escalares

Subconsultas que retornam um único valor podem ser usadas em expressões.

4. Funções de Janela

Permitem realizar cálculos em um conjunto de linhas relacionadas à linha atual.

5. Ordem de Execução das Consultas SQL

t.codigo_localizacao =#{codigoLocalizacao,jdbcType=VARCHAR}

6. Especificação de Tipos de Campo

É fundamental definir os tipos de dados corretos para cada campo.

7. Otimização de Consultas SQL

<sql id="ListaDeColunasBase">
    id, nome, primeira_letra, ordem
</sql>
    
<select>
    select
    <include refid="ListaDeColunasBase" />
    from pms_marca
</select>
    
Equivalente a:

<select>
    select  id, nome, primeira_letra, ordem
    from pms_marca
</select>

8. Concatenação de Múltiplas Colunas

É possível concatenar colunas do mesmo tipo de dados para retornar um único resultado.

Método 1:
select nome_funcionario|| 'trabalha como '|| cargo as mensagem
     from empregos 
        where departamento=10 
Método 2:
SELECT concat(nome_ponto || 'endereco_ponto como A '|| observacao) as mensagem 
FROM "pontos_interesse_wisdom"

9. Lógica Condicoinal em SQL

SELECT id, nome_ponto,
		case when id<60 then 'ATUALIZAR'
					when id >100 then 'outro'
					else 'GRANDE'
					end as status
					FROM "pontos_interesse_wisdom"

10. Limitando o Número de Linhas Retornadas

SELECT id, nome_ponto,
		case when id<60 then 'ATUALIZAR'
					when id >100 then 'outro'
					else 'GRANDE'
					end as status
					FROM "pontos_interesse_wisdom"	
					LIMIT 10

11. Retorno de Linhas Aleatórias

SELECT id, nome_ponto,
		case when id<60 then 'ATUALIZAR'
					when id >100 then 'outro'
					else 'GRANDE'
					end as status
					FROM "pontos_interesse_wisdom"	
			ORDER BY random()		LIMIT 10

12. Substituição de Valores Nulos

SELECT coalesce(id_ponto,'11') FROM "pontos_interesse_wisdom"

13. Funções de Tradução e Substituição

select dados
    from visao
    order   by replace(dados,
                replace(
                    translate(dados,'0123456789','##########'),'#',''),''))

14. Verificação de Comprimento de Dados

SELECT * from info_pessoa

	WHERE length(cpf)!=18 

15. Ordenação com Valores Nulos

SELECT
	nome_funcionario,
	salario,
	comissao 
FROM
	( SELECT nome_funcionario, salario, comissao, CASE WHEN comissao IS null entao 0 ELSE 1 AS is_null FROM empregados ) AS x 
ORDER BY
	is_null,
	comissao

16. Formatação de Data em DTO:

@JsonFormat(pattern = DateUtils.PADRAO_DATA_HORA)

17. Ordenação por Dois Campos

SELECT nome_funcionario ,salario,cargo,comissao
from 
empregados order by case when cargo='VENDEDOR'entao comissao else salario end 

18. Dados da Última Semana

//postreSQL
DataAlarme >= now() - interval '10 dia'
SELECT count(*) FROM politicas_conhecimento WHERE data_criacao >= date_trunc( 'mes', now( ) )

//达梦、MySQL
DATE_SUB(curdate(), INTERVAL '10' DAY) <= DataAlarme

19. Funções de Tratamento de Datas

//MySQL:
convert(Data,'tipo_desejado') //Data pode ser tempo de entrada
//ou
date_format('valor','%Y-%m-%d %H:%i:%s') //Data pode ser tempo de entrada

//达梦:
to_char(Data,'YYYY-MM-DD HH24:MI:SS') //Data pode ser tempo de entrada
//ou
to_date(Data,'YYYY-MM-DD HH24:MI:SS') //Data pode ser tempo de entrada
//ou
date_format(Data,'%Y-%m-%d %H:%i:%s') //Data pode ser tempo de entrada

//PostgreSQL:
to_date(Data,'YYYY-MM-DD HH24:MI:SS') //Data pode ser tempo de entrada
//ou
to_char(Data,'YYYY-MM-DD HH24:MI:SS') 

20. Consulta de Dados Comuns em Duas Tabelas

SELECT
	e.nome_funcionario,
	e.id_funcionario 
FROM
	empregados AS e,
	alunos AS s 
WHERE
	e.nome_funcionario = s.nome_funcionario 
	AND e.id_funcionario = s.id_funcionario

21. Consulta com Formatação de Tempo

select  id,
            nome,
            data,
            conteudo,
            canal
        from reclamacoes_vento
        <where>
            <if test="data!=null and data!=''">
                and to_char(data,'YYYY-MM-dd') =#{data}
            </if>
            <if test="nome!=null and nome!=''">
                and nome like ('%'||#{nome}||'%')
            </if>
        </where>

22. Escape de Caracteres em XML

to_char(tempo_fim_plano_isolamento,'YYYY-mm-dd') &lt;=#{dias}

23. Verificação de Igualdade entre Tabelas

select * from empregados where id>30 except select * from empregados where id>50

24. Atribuição de Valores para Nulos

select coalesce(conta_sucesso, 1) from tabelaA

25. Inserção com Valores Padrão

INSERT into dept values (1,DEFAULT,'ddddd ')

26. Cópia de Estrutura de Tabela sem Dados

CREATE TABLE dept2 as SELECT * FROM dept where 1=0

27. Restrição de Edição a Colunas Específicas

CREATE VIEW empregados_novos as SELECT cod_depto ,nome_depto from dept 

Ao definir permissões, permitir apenas edição nesta visualização

28. Limite de Tipo Integer no pgsql

select cast(10*1024*1024*1024  as bigint)

29. Conversão de String para Array

string_to_array(codigo_imovel, '#')

30. Operadores ANY e ALL

LEFT JOIN info_apartamento sai ON sai.codigo_imovel = any (string_to_array(spi.codigo_imovel, '#'))

31. SQL Retornando Listas com Subconsultas

1. Retornando objeto
<resultMap id="BaseResultMap" type="io.renren.modules.project.unit.entity.WisdomUnitEntity">
        <id column="id" jdbcType="BIGINT" property="id" />
        <result column="unit_name" property="unitName"  jdbcType="VARCHAR" />
        <result column="bashichu_code" property="bashichuCode"  jdbcType="VARCHAR"  />
        <result column="community_code" property="communityCode"  jdbcType="VARCHAR" />
        <result column="grid_code" property="gridCode"  jdbcType="VARCHAR"  />
        <result column="address" property="address" jdbcType="VARCHAR"  />
        <result column="property_company" property="propertyCompany"  jdbcType="VARCHAR"  />
        <result column="property_phone" property="propertyPhone"   jdbcType="VARCHAR" />
        <result column="manage_name" property="manageName" jdbcType="VARCHAR"  />
 </resultMap>
2. Retornando coleção de objetos
<select id="getDualPhoto" resultType="io.renren.project.building.storiedbuilding.dto.WisdomUnitDTO">
        select wu.*
            from prédio_comercial as wcb
            inner join unidade as wu on wcb.nome_prédio=wu.nome_prédio_comercial where baimo_id=#{baimoId}
    </select>
    <resultMap id="BaseResultMap" type="io.renren.project.building.storiedbuilding.dto.WisdomCommercialBuildingDTO" autoMapping="true">
        <collection property="wisdomUnitDTOS" column="baimo_id"
                    ofType="io.renren.project.building.storiedbuilding.dto.WisdomUnitDTO"
                    select="getDualPhoto"/>
    </resultMap>
    <select id="listCommerciaBuilding"
            resultMap="BaseResultMap">
        select  *,
        (SELECT count(*) FROM prédio_comercial as wcb
               inner join unidade as wu on wcb.nome_prédio=wu.nome_prédio_comercial  where baimo_id=#{baimoId}) as numero,
        (SELECT sum(numero_funcionarios) FROM prédio_comercial as wcb
               inner join unidade as wu on wcb.nome_prédio=wu.nome_prédio_comercial  where baimo_id=#{baimoId}) as soma
        from prédio_comercial  where baimo_id=#{baimoId}
    </select>

32. Obtenção de Ponto Central no pgsql

ST_Centroide

ST_Within(st_centroid(geometria_origem),geometria_destino)

33. Conversão de Múltiplos Campos para JSON

select alunos.*, array_to_json( array_agg (row_to_json(notas))) AS JsonArray
from alunos
left join notas on alunos.id = notas.id_aluno
group by alunos.id


34. Substring e Divisão de Strings

1. DIVIDIR_PARTES
A função DIVIDIR_PARTES() divide uma string usando um delimitador específico e retorna a N-ésima parte. Sintaxe:

DIVIDIR_PARTES(string, delimitador, posição)

string : String a ser dividida
delimitador: Caractere usado como separador
posição: Qual parte retornar (começa em 1), deve ser um número positivo. Se o valor exceder o número de partes, retorna string vazia.
Exemplo:

35. Agrupamento por Campo com Combinação de Linhas

MySQL: distinct para remoção de duplicatas

select demo_table.nome, group_concat(distinct area separator ',') as nome_combinado
from demo_table
group by nome


Pgsql: distinct para remoção de duplicatas

select nome ,
       array_to_string(array (select unnest(array_agg(distinct area))), ',') as nome_combinado
from demo_table
group by nome


36. Atualização com Junção de Tabelas

UPDATE tabela_alvo
SET campo1 = fonte.campo1,
 campo2 = fonte.campo2,

FROM
    tabela_fonte fonte
WHERE
    tabela_alvo.codigo = fonte.codigo

37. Mascaramento de Número de Telefone

SELECT CONCAT(LEFT(numero_telefone, 3), '****', 
RIGHT(numero_telefone, 4)) AS numero_telefone_mascarado 
FROM tabela_contatos;

38. Formatação de Data

SELECT * FROM "registro_fluxo" where data_criacao >=  '2023-07-11'::timestamp

39. Formatação de String em XML

 <if test="serviceId == '1426030897226063874'.toString">
                srl.is_export,
            </if>

40. Uso de Parâmetros em Condições WHERE

update estoque_produto set total = total - #{quantidade}
            where codigo_produto = #{codigoProduto} and (total - #{quantidade}) >= 0

41. Ordenação por Data Convertida de String

SELECT * FROM "registros_qywx" ORDER BY to_timestamp(tempo_msg, 'YYYY-MM-DD HH24:MI:SS.FF')  DESC


42. Dados com Múltiplos Rótulos

SELECT
            concat(#{rotulo},"id") as "id"
        FROM
            pontos_interesse_dq
        WHERE
            nome_camada = #{nomeCamada}
            AND rotulos LIKE CONCAT('%',#{rotulo},'%')
            AND status = '1'
            <if test="listaCodGrade!=null and listaCodGrade.size()>0">
                AND codigo_grade in
                <foreach collection="listaCodGrade" item="item" separator="," open="(" close=")">
                    cast(#{item} as varchar)
                </foreach>
            </if>
        ORDER BY
        ordem desc, status DESC,"id"
        LIMIT 9

43. Atualização com Junção de Tabelas

PostgreSQL formato de SQL para atualização com junção:

UPDATE tabela_alvo

SET campo1 = ft.campo1,

campo2 = ft.campo2

FROM

tabela_fonte ft

WHERE

tabela_alvo.campo = ft.campo;

Exemplo de código:

UPDATE usuario

SET nome_usuario = ft.nome,

idade = ft.idade

FROM

informacoes_usuario

WHERE

usuario.id = ft.id;

44. Combinação de Dados de Duas Tabelas

Diferença 1: Obter a interseção dos resultados

  1. union: Realiza união de dois conjuntos de resultados, sem linhas duplicadas, equivalente a distinct, com ordenação padrão;
  2. union all: Realiza união de dois conujntos de resultados, incluindo linhas duplicadas, ou seja, todos os resultados são exibidos, independentemente de serem duplicados;

Diferença 2: Operações após obter os resultados

  1. union: Ordena os resultados obtidos
  2. union all: Não ordena os resultados obtidos
SELECT NULL AS ID
	,
	'@todos' AS id_usuario,
	NULL AS openid,
	NULL AS "posicao",
	'Todos' AS NOME,
	NULL AS TIPO,
	NULL AS ATUALIZACAO,
	NULL AS data_atualizacao,
	NULL AS data_criacao,
	NULL AS criador,
	'' AS chat_id UNION ALL
SELECT
	* 
FROM
	informacoes_usuario_qywx 
WHERE
	chat_id =#{ chatId}

45. Parâmetros como Valores Fixos

SELECT NULL AS ID
                ,
               '@todos' AS id_usuario,
               NULL AS openid,
               NULL AS "posicao",
               'Todos' AS NOME,
               NULL AS TIPO,
               NULL AS ATUALIZACAO,
            NULL AS data_atualizacao,
            NULL AS data_criacao,
            NULL AS criador,
           '${chatId}' AS chat_id UNION ALL
        select * from informacoes_usuario_qywx where chat_id = #{chatId}

46. Alteração da Ordem de Retorno do SQL: Usando LinkedHashMap

<select id="selectGather" resultType="java.util.LinkedHashMap" ">
    SELECT *
    FROM  usuario
    ORDER BY horacriacao DESC LIMIT 0, 1
</select>

47. Conversão de String para Array

string_to_array( '1707231306494468097,1707231306519633921', ',' )

48. Operador de Inclusão

SELECT 
*
	
 FROM "info_envio_grupo_qywx" 

 WHERE	
 string_to_array("substring"( "replace"(tipo_mensagem, '"', ''), 2, "length"("replace"(tipo_mensagem, '"', ''))-2), ',') 
 @>  string_to_array('texto,link', ',') 

49. Problema com Tag em XML ao Passar Valores Inteiros

<if test="distance = null">
                            st_asgeojson (st_transform(geometria, 3857)) :: json AS "geometria",
                        </if>
                        <if test="distance != null ">
                            st_asgeojson ( ST_Buffer ( st_transform(geometria, 3857), ${distance})) :: json AS "geometria",
                        </if>

50. Adição do Módulo Postgis no Banco de Dados PostgreSQL

-- Habilitando extensão postgis
CREATE EXTENSION postgis;
-- Habilitando outras extensões (opcional)
CREATE EXTENSION postgis_topology;
CREATE EXTENSION fuzzystrmatch;
CREATE EXTENSION postgis_tiger_geocoder;


51. Obtenção da Data de Hoje

 DATE('now') + time '22:00'

52: Conversão de Formato

SELECT
            *
        FROM
            "info_envio_grupo_qywx"
        WHERE
            tipo_envio = '3'
          AND data_criacao::DATE  = current_date

53: Conversão de Dados para JSON e Extração de Chave

Código:
SELECT '[{"a":1},{"b":2},{"c":3}]'::JSON -> 1 -> 'b';
 
Resultado:
2

54: Problema de Ordenação com Valores Nulos

PostgreSQL fornece NULLS FIRST e NULLS LAST para controlar se valores nulos aparecem primeiro ou por último

55: Contagem de Ocorrências de uma Substring

SELECT
	"sum" ( num1 ) 
FROM
	( SELECT ( "length" ( campo ) - LENGTH ( REPLACE ( campo, 'substring', '' ) ) ) / 14 AS numl FROM "tabela" ) A

56: Ordenação com Valores Nulos

ORDER BY tempo_emprego  desc nulls last

57: Recursividade em pgsql

WITH RECURSIVO P AS (
	SELECT
		t1.* 
	FROM
		camada_sistema t1  WHERE id=1
	
 UNION ALL
	SELECT
		t2.* 
	FROM
		camada_sistema t2
		INNER JOIN P ON t2.ID = P.pid 
	) SELECT *
FROM
P

58: Retorno JSON como Null para Arrays Vazios

@JsonInclude(JsonInclude.Include.NON_EMPTY)

59: Divisão de Campo por Vírgula em Múltiplos Dados

SELECT
            "count"(*) as NumPoliticas ,
            "unnest"(REGEXP_SPLIT_TO_ARRAY(categoria_pergunta, ',')) as TipoPolitica
        FROM
            "politicas_conhecimento_wisdom"
        GROUP BY tipo

60: Erro com '->>' em Consulta JSON

@InterceptorIgnore(tenantLine = "true") TableVO getTable(nomeTabela);

Esta anotação, pelo seu significado literal, deve ignorar o interceptor do MyBatisPlus, resolvendo o problema

61: Separação de Caracteres em XML com Parâmetro Array

<if test="dataSourceInclude!=null and dataSourceInclude!=''">
            and fonte_dados in
            <foreach collection="dataSourceInclude.split(',')" item="fonte" open="(" separator="," close=")">
                #{fonte,jdbcType=VARCHAR}
            </foreach>
        </if>

62: União entre Array do Banco e Parâmetro

and string_to_array(t2.id_depto,',') &amp;&amp; string_to_array(#{listaIdDepto},',')

63: Soma de Valores Específicos em Campo

and string_to_array(t2.id_depto,',') &amp;&amp; string_to_array(#{listaIdDepto},',')

64: Remoção de Duplicatas com Mesmos Dados

(SELECT t1.* FROM
        adm.pessoas_excluidas_wisdom t1
        INNER JOIN ( SELECT MAX( id ) AS id FROM adm.pessoas_excluidas_wisdom GROUP BY id_documento ) t2 ON t1.id = t2.id)

65: Obtenção do Valor da Chave Primária Autoincrementada

usegeneratedkeys="true" keyproperty="id"

66: Declaração if() para Gênero

 select if(sexo=1,'Masculino','Feminino')
from usuario

67: ifnull('1','2')(usado no MySQL)

68: Otimização de SQL

NOT EXISTS é mais eficiente que NOT IN Quando a tabela principal é menor e a subconsulta maior, NOT IN é mais eficiente

69: Ponto Central em Polígono

ST_PontoSuperficie

70: Extração do Ano de Dados de Data

EXTRACT ( YEAR FROM tempo_registro )

71: Estrutura choose when

 <choose>
                <when test="tipo == 'dados_politicos'">
                    "dados_potenciais_politicos_wisdom"
                </when>
                <when test="tipo == 'dados_tecnicos'">
                    "dados_potenciais_tecnologia_wisdom"
                </when>

72: Problema com Condição de Consulta em Junção

select  MAX( id ) 
from adm.pessoas_excluidas_wisdom
 WHERE nome_tabela = 'adm_yb_todas_wjnybxx_df' and codigo_comunidade = '410102010002' group by id_documento versus 
select  * from (SELECT t1.* FROM
        adm.pessoas_excluidas_wisdom t1
        INNER JOIN ( SELECT MAX( id ) AS id FROM adm.pessoas_excluidas_wisdom GROUP BY id_documento ) t2 ON t1.id = t2.id) t1
 where nome_tabela ='adm_yb_todas_wjnybxx_df' and codigo_comunidade = '410102010002' 
 Contagem inconsistente

Na cláusula inner join, pode haver id_documento não incluídos nas condições posteriores WHERE, resultando em menos dados

73: Problema de Velocidade entre GROUP BY e WHERE

Em tabela única

SELECT count(*),nome_camada,'wisdom_ct_xqd_conexao_dlss' tname FROM "wisdom_ct_xqd_conexao_dlss" GROUP BY nome_camada

É mais rápido que consulta condicional e retorno unificado

  select
            '${nomeCamada}' as nomeCamada,
            count(*) as count
        from ${nomeTabela}
        where
            nome_camada = #{nomeCamada}

74: Passagem de Valores como Parâmetros em Subconsultas

SELECT DISTINCT
	site.id siteId,
	site.`codigo` siteCodigo,
	site.`nome` siteNome,
	site.lng_lat_alt lngLatAlt,
	site.posicao,
	hangar.`codigo` hangarCodigo,
	hangar.NOME hangarNome,
	hangar.marca hangarMarca,
	dick.label hangarMarcaNome,
	 hangar.modelo hangarModelo,
	  task.tarefa_flag AS tarefaFlag,
	task.id AS taskId,
	task.tarefa_nome AS tarefaNome,
	 site.criacao_tempo,
	 uav.video_endereco_rede uavVideoEndereco,
	 hangar.video_endereco_rede hangarVideoEndereco,
	 video.video_endereco_rede siteVideoEndereco,
	 (
	SELECT
		 t1.caminho_arquivo 
	FROM
		arquivo_anexo_sistema t1 
	WHERE
		t1.del_flag = 0  AND t1.busi_id IN ( SELECT t2.id FROM `multipla_dict_sistema` t2 WHERE t2.del_flag = 0 AND t2.`codigo` = hangar.marca ) 
	ORDER BY
		 t1.criacao_tempo DESC 
		LIMIT 1 
	) marcaImagem,
	 (
	SELECT
		 t1.caminho_arquivo 
	FROM
		arquivo_anexo_sistema t1 
	WHERE
		t1.del_flag = 0  AND t1.busi_id IN ( SELECT t2.id FROM `multipla_dict_sistema` t2 WHERE t2.del_flag = 0 AND t2.`codigo` = hangar.modelo ) 
	ORDER BY
		 t1.criacao_tempo DESC 
		LIMIT 1 
	) modeloImagem  
FROM
	site_uav site  

Tags: SQL postgresql MySQL Otimização de Consultas Funções de Agregação

Publicado em 6-8 02:06 por Thomas