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 / 278585
Accepted
kenorb
kenorb
Asked: 2020-10-24 11:10:57 +0800 CST2020-10-24 11:10:57 +0800 CST 2020-10-24 11:10:57 +0800 CST

Como extrair atributos de certificado de uma única coluna e dividir em muitas?

  • 772

Na minha tabela eu tenho um campo (digamos cert_attr) que armazena Certificate X.509 Attributes .

Aqui está o exemplo de 3 linhas (cada linha corresponde a um campo):

"CN=User1, OU=Eng, O=Company Ltd, L=D4, S=Dublin, C=IE"
"CN=User2, OU=Eng, O=Company Ltd, L=D2, S=Dublin, C=IE"
"OU=Eng, O=Company Ltd"

E estou tentando dividir o valor de um campo em colunas separadas usando SELECTda seguinte maneira:

SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(cert_attr, "CN=", -1), ", ", 1) as CN,
SUBSTRING_INDEX(SUBSTRING_INDEX(cert_attr, "OU=", -1), ", ", 1) as OU,
SUBSTRING_INDEX(SUBSTRING_INDEX(cert_attr, "O=", -1), ", ", 1) as O,
SUBSTRING_INDEX(SUBSTRING_INDEX(cert_attr, "L=", -1), ", ", 1) as L,
SUBSTRING_INDEX(SUBSTRING_INDEX(cert_attr, "ST=", -1), ", ", 1) as ST,
SUBSTRING_INDEX(SUBSTRING_INDEX(cert_attr, "C=", -1), ", ", 1) as C
FROM mytable

que funciona, no entanto, há um problema para as linhas que estão faltando alguns atributos.

Portanto, no caso em que o atributo está ausente na string do campo, espero que a coluna esteja vazia, mas ela retorna a string inteira.

Os dois primeiros exemplos de linha estão funcionando conforme o esperado, o que retorna as seguintes colunas corretamente:

| CN    | OU  | O           | L  | S.     | C  |
| ----- | --- | ----------- | -- | ------ | -- |
| User1 | Eng | Company Ltd | D4 | Dublin | IE |
| User2 | Eng | Company Ltd | D2 | Dublin | IE |

O problema está no exemplo da 3ª linha, que espero retornar uma string vazia quando o padrão de substring não for encontrado:

| CN         | OU  | O           | L          | S.         | C          |
| ---------- | --- | ----------- | ---------- | ---------- | ---------- |
| OU=Eng,... | Eng | Company Ltd | OU=Eng,... | OU=Eng,... | OU=Eng,... |

mas em vez disso, a string inteira é retornada.

Pergunta:

Existe alguma maneira de retornar uma string vazia quando SUBSTRING_INDEX()não consegue encontrar a substring? Ou talvez haja alguma outra função (como uma expressão regular) ou outra solução alternativa?

Meu objetivo é extrair os dados para o arquivo TSV tendo esses atributos em colunas separadas com valores válidos:

mysql mytable < query.sql > cert_attributes.tsv
mysql regex
  • 1 1 respostas
  • 47 Views

1 respostas

  • Voted
  1. Best Answer
    nbk
    2020-10-25T09:02:07+08:002020-10-25T09:02:07+08:00

    A primeira parte é apenas para mostrar que o procedimento funciona

    CREATE tABLE tablecertificate  (
    stationery_name varchar(500) 
    
    INSERT INTO tablecertificate values 
    ("CN=User1, OU=Eng, O=Company Ltd, L=D4, S=Dublin, C=IE"),
    ("CN=User2, OU=Eng, O=Company Ltd, L=D2, S=Dublin, C=IE"),
    ("OU=Eng, O=Company Ltd")
    
    CREATE PROCEDURE `splitcertifcate`()
    BEGIN
     DECLARE current_pos INT DEFAULT 1;
     DECLARE delim CHAR DEFAULT ',';
     DECLARE current VARCHAR(100) DEFAULT '';
     DECLARE CN VARCHAR(100) DEFAULT '';
     DECLARE OU VARCHAR(100) DEFAULT '';
     DECLARE O VARCHAR(100) DEFAULT '';
     DECLARE L VARCHAR(100) DEFAULT '';
     DECLARE S VARCHAR(100) DEFAULT '';
     DECLARE C VARCHAR(100) DEFAULT '';
     DECLARE rest_cert_part VARCHAR(100) DEFAULT '';
     DECLARE current_cert_part  VARCHAR(100) DEFAULT '';
      DECLARE finished INTEGER DEFAULT 0;
      DECLARE certificate varchar(500) DEFAULT "";
      DEClARE curcertificate 
          CURSOR FOR 
              SELECT stationery_name FROM tablecertificate;
    
      -- declare NOT FOUND handler
      DECLARE CONTINUE HANDLER 
            FOR NOT FOUND SET finished = 1;
            
            
      #Temporary Table that holds the splittet part
       DROP TEMPORARY TABLE IF EXISTS mycertificate;
      CREATE TEMPORARY TABLE mycertificate(CN VARCHAR(100), OU VARCHAR(100), O VARCHAR(100) , L  VARCHAR(100), S VARCHAR(100), C VARCHAR(100));
    
      OPEN curcertificate;
        getcertificate: LOOP
          # get first row elemnt
          FETCH curcertificate INTO certificate;
          IF finished = 1 THEN 
              #Last element reached
              LEAVE getcertificate;
          END IF;
            SET CN = '';
            SET OU = '';
            SET O = '';
            SET L = '';
            SET S = '';
            SET C = '';
          SET current_pos =  LOCATE(delim,certificate);
            SET current_cert_part = SUBSTRING(certificate,1,current_pos-1);
          SET rest_cert_part = SUBSTRING(certificate from current_pos+1);
            IF length(trim(current_cert_part)) = 0   THEN
              SET current_cert_part = rest_cert_part;
          END IF;
          #Examine first element of the string
            CASE 
              WHEN INSTR(current_cert_part, "CN=")  > 0 THEN SET CN = TRIM(current_cert_part);
              WHEN INSTR(current_cert_part, "OU=")  > 0 THEN SET OU = TRIM(current_cert_part);
              WHEN INSTR(current_cert_part, "O=")  > 0 THEN SET O = TRIM(current_cert_part);
              WHEN INSTR(current_cert_part, "L=")  > 0 THEN SET L = TRIM(current_cert_part);
              WHEN INSTR(current_cert_part, "S=")  > 0 THEN SET S = TRIM(current_cert_part);
              WHEN INSTR(current_cert_part, "C=")  > 0 THEN SET C = TRIM(current_cert_part);
            END CASE;
            WHILE current_pos <> 0 DO
              #loop throuigh the string
              set  current_pos = LOCATE(delim,rest_cert_part);
              set current_cert_part = SUBSTRING(rest_cert_part,1,current_pos-1);
              set rest_cert_part = SUBSTRING(rest_cert_part from current_pos+1);
    
              if length(trim(current_cert_part)) = 0   then
                  #ÖLast elemnt in string
                  set current_cert_part = rest_cert_part;
              end if;    
              CASE 
                  WHEN INSTR(current_cert_part, "CN=")  > 0 THEN SET CN = TRIM(current_cert_part);
                  WHEN INSTR(current_cert_part, "OU=")  > 0 THEN SET OU = TRIM(current_cert_part);
                  WHEN INSTR(current_cert_part, "O=")  > 0 THEN SET O = TRIM(current_cert_part);
                  WHEN INSTR(current_cert_part, "L=")  > 0 THEN SET L = TRIM(current_cert_part);
                  WHEN INSTR(current_cert_part, "S=")  > 0 THEN SET S = TRIM(current_cert_part);
                  WHEN INSTR(current_cert_part, "C=")  > 0 THEN SET C = TRIM(current_cert_part);
              END CASE;
          END WHILE;
            #In sert splittet strung  row in temp table
           INSERT INTO mycertificate VALUES (  CN,OU,O,L,S,C);
    
    
      END LOOP getcertificate;
      CLOSE curcertificate;
    SELECT * FROM mycertificate;
    END
    
    cALL splitcertifcate();
    
    NC | UO | O | L | S | C   
    :------- | :----- | :------------ | :--- | :------- | :---
    CN=Usuário1 | OU=Eng | O=Empresa Ltda | L=D4 | S=Dublim | C=IE
    CN=Usuário2 | OU=Eng | O=Empresa Ltda | L=D2 | S=Dublim | C=IE
             | OU=Eng | O=Empresa Ltda | | |     
    
    ✓
    

    db<>fique aqui

    O procedimento armazenado completo, incluindo a produção do arquivo tsv

    DELIMITER //
    CREATE DEFINER=`root`@`%` PROCEDURE `splitcertifcate`()
    BEGIN
     DECLARE current_pos INT DEFAULT 1;
     DECLARE delim CHAR DEFAULT ',';
     DECLARE current VARCHAR(100) DEFAULT '';
     DECLARE CN VARCHAR(100) DEFAULT '';
     DECLARE OU VARCHAR(100) DEFAULT '';
     DECLARE O VARCHAR(100) DEFAULT '';
     DECLARE L VARCHAR(100) DEFAULT '';
     DECLARE S VARCHAR(100) DEFAULT '';
     DECLARE C VARCHAR(100) DEFAULT '';
     DECLARE rest_cert_part VARCHAR(100) DEFAULT '';
     DECLARE current_cert_part  VARCHAR(100) DEFAULT '';
        DECLARE finished INTEGER DEFAULT 0;
        DECLARE certificate varchar(500) DEFAULT "";
        DEClARE curcertificate 
            CURSOR FOR 
                SELECT stationery_name FROM tablecertificate;
    
        -- declare NOT FOUND handler
        DECLARE CONTINUE HANDLER 
            FOR NOT FOUND SET finished = 1;
            
        #Temporary Table that holds the splittet part
         DROP TEMPORARY TABLE IF EXISTS mycertificate;
        CREATE TEMPORARY TABLE mycertificate(CN VARCHAR(100), OU VARCHAR(100), O VARCHAR(100) , L  VARCHAR(100), S VARCHAR(100), C VARCHAR(100));
    
        OPEN curcertificate;
        getcertificate: LOOP
            # get first row elemnt
            FETCH curcertificate INTO certificate;
            IF finished = 1 THEN 
                #Last element reached
                LEAVE getcertificate;
            END IF;
            SET CN = '';
            SET OU = '';
            SET O = '';
            SET L = '';
            SET S = '';
            SET C = '';
            SET current_pos =  LOCATE(delim,certificate);
            SET current_cert_part = SUBSTRING(certificate,1,current_pos-1);
            SET rest_cert_part = SUBSTRING(certificate from current_pos+1);
            IF length(trim(current_cert_part)) = 0   THEN
                SET current_cert_part = rest_cert_part;
            END IF;
            #Examine first element of the string
            CASE 
                WHEN INSTR(current_cert_part, "CN=")  > 0 THEN SET CN = TRIM(current_cert_part);
                WHEN INSTR(current_cert_part, "OU=")  > 0 THEN SET OU = TRIM(current_cert_part);
                WHEN INSTR(current_cert_part, "O=")  > 0 THEN SET O = TRIM(current_cert_part);
                WHEN INSTR(current_cert_part, "L=")  > 0 THEN SET L = TRIM(current_cert_part);
                WHEN INSTR(current_cert_part, "S=")  > 0 THEN SET S = TRIM(current_cert_part);
                WHEN INSTR(current_cert_part, "C=")  > 0 THEN SET C = TRIM(current_cert_part);
            END CASE;
            WHILE current_pos <> 0 DO
                #loop throuigh the string
                set  current_pos = LOCATE(delim,rest_cert_part);
                set current_cert_part = SUBSTRING(rest_cert_part,1,current_pos-1);
                set rest_cert_part = SUBSTRING(rest_cert_part from current_pos+1);
    
                if length(trim(current_cert_part)) = 0   then
                    #ÖLast elemnt in string
                    set current_cert_part = rest_cert_part;
                end if;    
                CASE 
                    WHEN INSTR(current_cert_part, "CN=")  > 0 THEN SET CN = TRIM(current_cert_part);
                    WHEN INSTR(current_cert_part, "OU=")  > 0 THEN SET OU = TRIM(current_cert_part);
                    WHEN INSTR(current_cert_part, "O=")  > 0 THEN SET O = TRIM(current_cert_part);
                    WHEN INSTR(current_cert_part, "L=")  > 0 THEN SET L = TRIM(current_cert_part);
                    WHEN INSTR(current_cert_part, "S=")  > 0 THEN SET S = TRIM(current_cert_part);
                    WHEN INSTR(current_cert_part, "C=")  > 0 THEN SET C = TRIM(current_cert_part);
                END CASE;
            END WHILE;
            #In sert splittet strung  row in temp table
           INSERT INTO mycertificate VALUES (  CN,OU,O,L,S,C);
    
    
        END LOOP getcertificate;
        CLOSE curcertificate;
    
        SELECT * FROM mycertificate INTO OUTFILE "C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/cert.tsv"
        FIELDS TERMINATED BY '\t'
        ENCLOSED BY '"'
        LINES TERMINATED BY '\n';
    END//
    DELIMITER ;
    

    Arquivo tsv de resultado

    "CN=User1"  "OU=Eng"    "O=Company Ltd" "L=D4"  "S=Dublin"  "C=IE"
    "CN=User2"  "OU=Eng"    "O=Company Ltd" "L=D2"  "S=Dublin"  "C=IE"
    ""          "OU=Eng"    "O=Company Ltd"  ""       ""        ""
    

    Você deve verificar a pasta INTO OUTFILE, que deve corresponder à entrada no arquivo my.ini/cnf

    secure-file-priv='C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/'
    
    • 1

relate perguntas

  • Existem ferramentas de benchmarking do MySQL? [fechado]

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

  • Quando é o momento certo para usar o MariaDB em vez do MySQL e por quê?

  • Como um grupo pode rastrear alterações no esquema do banco de dados?

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