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 / 343714
Accepted
ToC
ToC
Asked: 2024-11-20 03:53:40 +0800 CST2024-11-20 03:53:40 +0800 CST 2024-11-20 03:53:40 +0800 CST

Sql Server: Consulta para analisar e validar códigos

  • 772

Temos uma tabela #ValidCode com uma lista de códigos válidos como: 'A', 'B', 'C', etc. Outra tabela chamada #SourceData com dados de entrada — que vêm como uma combinação de tokens válidos e inválidos (às vezes duplicados).

Ex:

  • 'A;B;C' ( válido )
  • 'A;A;A;A;A;B' ( Válido )
  • 'ad;df;A;B' ( inválido )

Tentando encontrar uma abordagem de consulta ótima para processar essas strings para encontrar linhas válidas em #SourceData . Veja o exemplo abaixo:

DROP TABLE IF EXISTS #ValidCode
GO
CREATE TABLE #ValidCode
(
      ID        INT             IDENTITY(1,1)
    , Code      CHAR(1)
)
INSERT INTO #ValidCode (Code) VALUES ('A'), ('B'), ('C')
GO
DROP TABLE IF EXISTS #SourceData 
GO
CREATE TABLE #SourceData 
(
      ID        INT             IDENTITY(1,1)
    , Codes     VARCHAR(500)
    , Is_Valid  BIT
    , Is_Split  BIT
)

INSERT INTO #SourceData (Codes) 
VALUES    ('A;B;C')
        , ('B;A')
        , ('B;B;B;C;C;A;A;B')
        , ('B;Z;1')
        , ('B;ss;asd')


SELECT * FROM #ValidCode
SELECT * FROM #SourceData

A consulta processaria os dados na tabela #SourceData e atualizaria o sinalizador Is_Valid para que eles pudessem ser consumidos no processo subsequente.

Regras :

  • Cada token deve ser válido para que toda a linha da coluna seja válida (linhas 1 a 3)
  • Mesmo que um token seja inválido, o valor da linha inteira será inválido (linhas 4 e 5)

Então, esta é a saída preferida:

EU IA Códigos É_válido
1 ABC 1
2 B;Um 1
3 B;B;B;C;C;A;A;B 1
4 B;Z;1 0
5 B;ss;asd 0

Abordagem atual : Faça um loop por cada linha em #SourceData e divida-as no delimitador ';', depois compare-as com a tabela #ValidCode . Se todos os tokens forem individualmente válidos, marque a linha em #SourceData como válida ( flag Is_Valid ). Caso contrário, marque como inválida. A WHILEabordagem de loop funciona, mas é lenta.

O #SourceData pode ter até 3 milhões de linhas. Com cada linha tendo várias combinações de valores válidos duplicados ('A;A;A;A') e inválidos ('A;as;sdf;B')

Existe uma abordagem melhor?

Obrigado!

query-performance
  • 2 2 respostas
  • 53 Views

2 respostas

  • Voted
  1. Doug Hills
    2024-11-20T04:44:21+08:002024-11-20T04:44:21+08:00

    -- primeira coisa que vem à mente:

    SELECT 
        sd.ID
        , sd.Codes
        , CASE 
            WHEN NOT EXISTS (
                SELECT x.[value] 
                FROM string_split(sd.Codes, ';') as x
                LEFT OUTER JOIN #ValidCode as vc
                    ON x.[value] = vc.Code
                WHERE vc.Code IS NULL
            )
            THEN 1
            ELSE 0
          END as is_valid
    FROM #SourceData as sd
    

    Pode ser mais ideal criar uma tabela filha para os códigos SourceData divididos em linhas.

    • 1
  2. Best Answer
    J.D.
    2024-11-20T21:30:36+08:002024-11-20T21:30:36+08:00

    Uma maneira relacional de fazer isso é dividindo o #SourceDataprimeiro (felizmente você tem acesso à STRING_SPLIT()função apesar de estar em uma versão desatualizada do SQL Server), depois obtendo as linhas que não correspondem ao seu #ValidCodese, finalmente, usando essas linhas para determinar o que Is_Validhá na #SourceDatatabela original.

    Aqui está um exemplo de como fazer isso:

    ;WITH _BadData AS
    (
        SELECT DISTINCT SD.ID
        FROM #SourceData AS SD
        CROSS APPLY STRING_SPLIT(SD.Codes, ';') AS SS
        WHERE NOT EXISTS
        (
            SELECT 1 AS RowExists
            FROM #ValidCode AS VC
            WHERE SS.[value] = VC.Code
        )
    )
    
    SELECT
        SD.ID,
        SD.Codes,
        ISNULL(SD.Is_Valid, IIF(BD.ID IS NULL, 1, 0)) AS Is_Valid,
        SD.Is_Split
    FROM #SourceData AS SD
    LEFT JOIN _BadData AS BD
        ON SD.ID = BD.ID;
    

    Aqui está um repositório dbfiddle.uk demonstrando esse código .

    Observe que dependendo do tamanho #SourceDatae do plano de execução gerado, você pode querer materializar os resultados da STRING_SPLIT() função, todo o CTE em si, ou ambos, para uma tabela temporária primeiro, antes de usá-la na segunda metade da consulta acima para o final LEFT JOIN. Mas eu presumo que isso deve ser mensuravelmente melhor do que fazer um loop em suas linhas, uma por uma.

    • 1

relate perguntas

  • SQL obtendo IDs de uma tabela com várias entradas em outra tabela

  • Tabela chave/valor com limitadores

  • selecionando linhas que têm n condições de chave estrangeira satisfeitas

  • Qual é o nome desse tipo de consulta e qual é um exemplo eficiente?

  • Como (e por que) o TOP impacta um plano de execução?

Sidebar

Stats

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

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 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

    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
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • 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
    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

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