【问题标题】:Split mysql queries in array, each queries separated by ";"在数组中拆分mysql查询,每个查询用“;”分隔
【发布时间】:2011-06-12 11:30:29
【问题描述】:

我想从 phpmyadmin 导出格式中拆分 mysql 查询。每个查询将由“;”分隔但不能使用爆炸,因为“;”也可能存在于字段值的任何地方。下面是一个例子。

insert into wp_options (option_id, blog_id, option_name, option_value, autoload) values (201, 0, "tadv_btns2", "a:21:{i:0;s:14:\"fontsizeselect\";i:1;s:12:\"formatselect\";i:2;s:9:\"pastetext\";i:3;s:9:\"pasteword\";i:4;s:12:\"removeformat\";i:5;s:9:\"separator\";i:6;s:7:\"charmap\";i:7;s:5:\"print\";i:8;s:9:\"separator\";i:9;s:9:\"forecolor\";i:10;s:9:\"backcolor\";i:11;s:8:\"emotions\";i:12;s:9:\"separator\";i:13;s:3:\"sup\";i:14;s:3:\"sub\";i:15;s:5:\"media\";i:16;s:9:\"separator\";i:17;s:4:\"undo\";i:18;s:4:\"redo\";i:19;s:7:\"attribs\";i:20;s:7:\"wp_help\";}", "no");

insert into wp_options (option_id, blog_id, option_name, option_value, autoload) values (202, 0, "tadv_btns3", "a:0:{}", "no");

insert into wp_options (option_id, blog_id, option_name, option_value, autoload) values (203, 0, "tadv_btns4", "a:0:{}", "no");

insert into wp_options (option_id, blog_id, option_name, option_value, autoload) values (204, 0, "tadv_allbtns", "a:64:{i:0;s:6:\"wp_adv\";i:1;s:4:\"bold\";i:2;s:6:\"italic\";i:3;s:13:\"strikethrough\";i:4;s:9:\"underline\";i:5;s:7:\"bullist\";i:6;s:7:\"numlist\";i:7;s:7:\"outdent\";i:8;s:6:\"indent\";i:9;s:11:\"justifyleft\";i:10;s:13:\"justifycenter\";i:11;s:12:\"justifyright\";i:12;s:11:\"justifyfull\";i:13;s:3:\"cut\";i:14;s:4:\"copy\";i:15;s:5:\"paste\";i:16;s:4:\"link\";i:17;s:6:\"unlink\";i:18;s:5:\"image\";i:19;s:7:\"wp_more\";i:20;s:7:\"wp_page\";i:21;s:6:\"search\";i:22;s:7:\"replace\";i:23;s:10:\"fontselect\";i:24;s:14:\"fontsizeselect\";i:25;s:7:\"wp_help\";i:26;s:10:\"fullscreen\";i:27;s:11:\"styleselect\";i:28;s:12:\"formatselect\";i:29;s:9:\"forecolor\";i:30;s:9:\"backcolor\";i:31;s:9:\"pastetext\";i:32;s:9:\"pasteword\";i:33;s:12:\"removeformat\";i:34;s:7:\"cleanup\";i:35;s:12:\"spellchecker\";i:36;s:7:\"charmap\";i:37;s:5:\"print\";i:38;s:4:\"undo\";i:39;s:4:\"redo\";i:40;s:13:\"tablecontrols\";i:41;s:4:\"cite\";i:42;s:3:\"ins\";i:43;s:3:\"del\";i:44;s:4:\"abbr\";i:45;s:7:\"acronym\";i:46;s:7:\"attribs\";i:47;s:5:\"layer\";i:48;s:5:\"advhr\";i:49;s:4:\"code\";i:50;s:11:\"visualchars\";i:51;s:11:\"nonbreaking\";i:52;s:3:\"sub\";i:53;s:3:\"sup\";i:54;s:9:\"visualaid\";i:55;s:10:\"insertdate\";i:56;s:10:\"inserttime\";i:57;s:6:\"anchor\";i:58;s:10:\"styleprops\";i:59;s:8:\"emotions\";i:60;s:5:\"media\";i:61;s:10:\"blockquote\";i:62;s:9:\"separator\";i:63;s:1:\"|\";}", "no");

【问题讨论】:

标签: php mysql regex split


【解决方案1】:

我针对一些问题修改了“ridgerunner”函数“split_sql”:没有反引号字符串,正在跳过带有语法错误的查询,并非所有多行 cmets 都匹配或最后一个空 sql。它总是返回完整的数组来调试每个查询或重新组装以在 MySQL 中进行分析;

function split_sql($sql, $rtrim = TRUE)
{
    $re = '%
        \s*                                                 # Discard leading whitespace.
            ((?:                                            # Group for content alternatives.
              [^;"\'#`\/-]+                                 # None of these [...]                  
            | \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'?           # or a single quoted string,
            | "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"?               # or a double quoted string,
            | `[^`]*`?                                      # single back quoted string
            | \/\*(?:.*?\*\/|.*)                            # or a multi-line comment,
            | (?-s)\#.*                                     # or a # single line comment (off s-modifier from here),
            | --.*                                          # or a -- single line comment,
            | -                                             # or -
            )*)                                             # One or more content alternatives
            ;                                               # Record end is a ; or string end.
        %xs';
    if ($rtrim)
        $sql = rtrim($sql, "; \t\n\r\0\x0B");
    if (preg_match_all($re, $sql.';', $matches))
        return $matches[1];        
    return [];
}

【讨论】:

    【解决方案2】:

    给定一个包含多个以分号分隔的 SQL 语句的字符串,以下函数解析出每个单独的语句并将它们全部返回到一个数组中。它使用一个(非平凡的)正则表达式和一个对 preg_match_all() 的调用,并正确处理单行和多行 cmets 以及单引号和双引号字符串(每个字符串都可能包含非终止分号)忽略):

    function split_sql($sql_text) {
        // Return array of ; terminated SQL statements in $sql_text.
        $re_split_sql = '%(?#!php/x re_split_sql Rev:20170816_0600)
            # Match an SQL record ending with ";"
            \s*                                     # Discard leading whitespace.
            (                                       # $1: Trimmed non-empty SQL record.
              (?:                                   # Group for content alternatives.
                \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'  # Either a single quoted string,
              | "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"      # or a double quoted string,
              | /\*[^*]*\*+(?:[^*/][^*]*\*+)*/      # or a multi-line comment,
              | \#.*                                # or a # single line comment,
              | --.*                                # or a -- single line comment,
              | [^"\';#]                            # or one non-["\';#-]
              )+                                    # One or more content alternatives
              (?:;|$)                               # Record end is a ; or string end.
            )                                       # End $1: Trimmed SQL record.
            %x';  // End $re_split_sql.
        if (preg_match_all($re_split_sql, $sql_text, $matches)) {
            return $matches[1];
        }
        return array();
    }
    

    编辑 2017-08-15: 修复了 @jxmallett 指出的正则表达式的多行注释部分中的错误。 编辑 2017-08-16: 整理正则表达式(添加正则表达式 shebang 并删除不必要的组 $2)。

    【讨论】:

    • 这很好,只希望它可以将 cmets 分离到自己的索引中,而不是使用以下 sql 语句将它们分组。不知道如何使用多行 cmets 来做到这一点,并且没有像检查仅在 sql 语句开头有效的关键字这样的黑客行为...... :(
    • 现在我只是用这个答案去除所有 cmets:stackoverflow.com/questions/9690448/…,然后使用 split_sql() 分解结果。
    • 不支持 PROCEDURES。
    • 和 JS 的相同正则表达式:regex = '\s*((?:\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'|"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\#.*|\\/\\*[\\w\\W]*?(?=\\*\\/)\\*\\/|--.*|[^"\';#])+(?:;|$))';
    • 当它实际上是 2 时将它作为一个查询匹配:/* comment */ SELECT * FROM foo; /* comment 2 */ SELECT * FROM bar; 这似乎是多行 cmets 的问题。在运行 split_sql 之前,我使用 '@(([\'"]).*?[^\\\]\2)|((?:\#|--).*?$|/\*(?:[^/*]|/(?!\*)|\*(?!/)|(?R))*\*\/)\s*|(?<=;)\s+@ms' 剥离了所有 cmets。
    【解决方案3】:

    一种方法是:

    按“);”分解

    它将返回语句数组

    然后在数组中每个语句的末尾连接“)”

    【讨论】:

      【解决方案4】:

      这样的事情怎么样

      $fh = fopen('/path/to/your/file.sql', 'r') or die($php_errormsg);
      while (!feof($fh)) {
          $line = fgets($fh, 4096);
          if (preg_match($pattern, $line)) { $sql_queries[ ] = $line; }
      }
      fclose($fh);
      

      其中 $pattern 可以初始化为 sql 插入查询格式。 使用换行符不是一个好的选择,因为大型 sql 插入会延伸超过一行

      【讨论】:

        【解决方案5】:

        我的建议是用独特的东西替换你的分隔符。例如,分号不会是唯一的(如您所述),因此您不能对此进行拆分。换行符(如前所述)可能是一个很好且简单的选择。

        【讨论】:

          【解决方案6】:

          这些行是否由“换行”字符分隔?如果是,就炸掉它们:

          $my_array = explode("\n",$content);

          【讨论】:

          • 实际上有些查询被分成了不止一行,所以explode("\n",$content) 不起作用
          猜你喜欢
          • 2016-12-30
          • 1970-01-01
          • 1970-01-01
          • 2017-05-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-29
          相关资源
          最近更新 更多