AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 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

如何从单个列中提取证书属性并拆分为多个?

  • 772

在我的表中,我有一个cert_attr存储Certificate X.509 Attributes的字段(比如说) 。

这是 3 行的示例(每行对应一个字段):

"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"

我正在尝试使用SELECT以下方式将字段的值拆分为单独的列:

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

这可行,但是缺少某些属性的行存在问题。

因此,在字段字符串中缺少属性的情况下,我希望该列为空,但它会返回整个字符串。

前两行示例按预期工作,正确返回以下列:

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

问题在于第 3 行示例,我希望在找不到子字符串模式时返回一个空字符串:

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

而是返回整个字符串。

问题:

SUBSTRING_INDEX()当找不到子字符串时,有什么方法可以返回一个空字符串?或者也许还有其他功能(如正则表达式)或其他解决方法?

我的目标是通过将这些属性放在具有有效值的单独列中来将数据提取到 TSV 文件中:

mysql mytable < query.sql > cert_attributes.tsv
mysql regex
  • 1 1 个回答
  • 47 Views

1 个回答

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

    第一部分只是向您展示该程序有效

    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();
    
    中文 | 欧 | ○ | 大号 | 小号 | C   
    :------- | :----- | :------------ | :--- | :------- | :---
    CN=用户1 | 欧=英| O=有限公司| L=D4 | S=都柏林 | C=IE
    CN=用户2 | 欧=英| O=有限公司| L=D2 | S=都柏林 | C=IE
             | 欧=英| O=有限公司| | |     
    
    ✓
    

    db<>在这里摆弄

    完整的存储过程,包括生成 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 ;
    

    结果 tsv 文件

    "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"  ""       ""        ""
    

    您必须检查 INTO OUTFILE 文件夹,该文件夹必须与 my.ini/cnf 文件中的条目相对应

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

相关问题

  • 是否有任何 MySQL 基准测试工具?[关闭]

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

  • 什么时候是使用 MariaDB 而不是 MySQL 的合适时机,为什么?

  • 组如何跟踪数据库架构更改?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve