MySql查询 - 将数据扩展到新表中

时间:2017-10-19 10:52:43

标签: mysql

我将数据存储在MySQL表中,需要将其提取并以非常具体的方式将其存储到新表中:

数据位于客户表中,例如:

ID String | Region Identifier
abcdefg   | 123456
bcdefgh   | 123456
cdefghi   | 123456
defghij   | 456789
efghijk   | 456789
fghijkl   | 456789

我希望能够在某个区域标识符(该区域中有多个id字符串)下显示ID字符串的所有组合,并将其存储在另一个表中。例如,上述数据最终会出现在另一个表格中,例如:

ID Strings                 | Region Identifier | Count
abcdefg, bcdefgh, cdefghi  | 123456            |  3
abcdefg, cdefghi           | 123456            |  2
abcdefg, bcdefgh           | 123456            |  2
bcdefgh, cdefghi           | 123456            |  2
defghij, efghijk, fghijkl  | 456789            |  3
defghij, fghijkl           | 456789            |  2
defghij, efghijk           | 456789            |  2
efghijk, fghijkl           | 456789            |  2

我还想确保ID字符串(可以是数字和字母的组合)按字母顺序出现(在ID字符串字段中),并且需要将它们转换为基于字符串的整数。因此,例如(abcdefg,bcdefgh,cdefghi)将变为2454574579.(我需要能够在这3个精确字符串组合时获得此ID)。

我更愿意这样做是原始SQL,如果可能的话,但如果不是我很高兴使用python,php,javascript,但任何最快。

1 个答案:

答案 0 :(得分:0)

问题在于您需要组合的总数,这可以是无限的,具体取决于每个区域的唯一ID数。如果您有X个唯一ID,则需要进行X个自连接。 每个没有条件的加入,都可以为您生成另一个组合。

因此您需要使用存储过程。

但第一步是做一个group_concat。 我还将使用以下存储过程:https://gist.github.com/avoidwork/3749973

你使用group concat:

create table testing(
  idString varchar(20),
  region varchar(20)
);

insert into testing values("abcdefg","123456");
insert into testing values("bcdefgh","123456");
insert into testing values("cdefghi","123456");
insert into testing values("defghij","456789");
insert into testing values("efghijk","456789");
insert into testing values("fghijkl","456789");


select region, group_concat(idString) from testing group by region;

剩下的内容我将在稍后发布,是使用ascii值转换为字符的数字euivalent。并且还要按顺序执行。

更新

根据需要更改代码。 请注意,以下内容包含IDString的所有订单中的所有组合。

        #Init Stuff

#Will not work without the following command/Setting:
SET SESSION sql_mode = CONCAT(@@sql_mode, ',PIPES_AS_CONCAT');

DROP PROCEDURE IF EXISTS `sp_split`;
DROP PROCEDURE IF EXISTS `getCombinations`;

CREATE TABLE IF NOT EXISTS `temp` (
  `col` VARCHAR(100) NOT NULL
) ENGINE=MEMORY;

CREATE TABLE IF NOT EXISTS `result` (
  `idStrings` VARCHAR(100) NOT NULL,
  `region` VARCHAR(100) NOT NULL,
  `count` VARCHAR(100) NOT NULL
) ENGINE=MEMORY;

delete from result;
delete from temp;

create view  IF NOT EXISTS groupByBugWorkaroundView as select   region as region, count(distinct idString) as countInt, group_concat(idString) as csv from testing group by region;

delimiter ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_split`(IN toSplit text, IN target char(255))
  BEGIN
    # Temp table variables
    SET @tableName = 'tmpSplit';
    SET @fieldName = 'variable';

    #select toSplit;

    # Dropping table
    SET @sql := CONCAT('DROP TABLE IF EXISTS ', @tableName);
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;


    # Creating table
    SET @sql := CONCAT('CREATE TABLE IF NOT EXISTS ', @tableName, ' (', @fieldName, ' VARCHAR(1000))');
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;


    # Preparing toSplit
    SET @vars := toSplit;
    SET @vars := CONCAT("('", REPLACE(@vars, ",", "'),('"), "')");

    delete from tmpSplit;

    # Inserting values
    SET @sql := CONCAT('INSERT INTO ', @tableName, ' VALUES ', @vars);
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

    # Returning record set, or inserting into optional target
    IF target IS NULL THEN
      SET @sql := CONCAT('SELECT TRIM(`', @fieldName, '`) AS `', @fieldName, '` FROM ', @tableName);
    ELSE
      SET @sql := CONCAT('INSERT INTO ', target, ' SELECT TRIM(`', @fieldName, '`) FROM ', @tableName);
    END IF;

    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

  END
;;

#-------------------------------------------------------------------------------

CREATE PROCEDURE getCombinations()
  BEGIN

    DECLARE countInt INT DEFAULT 0;
    DECLARE csv varchar(100);
    DECLARE region varchar(100);
    DECLARE v_last_row_fetched INT;
    declare v_counter int unsigned default 1;

    DECLARE counter cursor for select  * from groupByBugWorkaroundView;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET  v_last_row_fetched=1;

    SET SESSION sql_mode = CONCAT(@@sql_mode, ',PIPES_AS_CONCAT');

    delete from result;
    delete from tmpSplit;
    COMMIT;

    open counter;
    c1_loop: loop
      fetch counter into region , countInt, csv ;

      IF  v_last_row_fetched=1 THEN LEAVE c1_loop; END IF;

      CALL sp_split(csv, null);

      #       delete from temp;
      #       insert into temp select * from tempSplit;
      #       commit;

      set @q0 = concat('insert into result select t0.variable ');
      set @q1 = concat(' from tmpSplit t0');
      set @q3 = concat(' where 1=1 ');
      set @q4 = ',\''  || region || ' \'' ;

      #-- DEBUG
      #       set @tempLog = concat('insert into templog values (\'',@q1);
      #       set @tempLog = concat(@q1, ' '');');
      #       PREPARE stmt1 FROM @tempLog;
      #       EXECUTE stmt1;
      #       DEALLOCATE PREPARE stmt1;
      #-- END DEBUG

      set v_counter = 1;
      while v_counter < countInt do

        set @q1 := concat(@q1,  ' ,tmpSplit t');
        set @q1 := concat(@q1 ,  v_counter);

        set @q0 := concat(@q0, '|| \',\' || t');
        set @q0 := concat(@q0, v_counter);
        set @q0 := concat(@q0, '.variable');

        #Necessary joins
        set @q3 := concat(@q3, ' AND not t');
        set @q3 := concat(@q3, v_counter-1);
        set @q3 := concat(@q3, '.variable = ');
        set @q3 := concat(@q3, ' t');
        set @q3 := concat(@q3, v_counter);
        set @q3 := concat(@q3, '.variable ');

        #Alphabetical order
        set @q3 := concat(@q3, ' AND not t');
        set @q3 := concat(@q3, v_counter-1);
        set @q3 := concat(@q3, '.variable > ');
        set @q3 := concat(@q3, ' t');
        set @q3 := concat(@q3, v_counter);
        set @q3 := concat(@q3, '.variable ');

        set v_counter=v_counter+1;

        set @q5 = ',\''  || v_counter || '\'' ;

        set @q9 := concat('', '');
        set @q9 := concat( @q0, @q4);
        set @q9 := concat( @q9, @q5);
        set @q9 := concat( @q9, @q1);
        set @q9 := concat( @q9, @q3);
        select @q9 as debug;

        PREPARE stmt1 FROM @q9;
        EXECUTE stmt1;
        DEALLOCATE PREPARE stmt1;
        commit;

      end while;

      delete from temp; commit;

    end loop c1_loop;
    close counter;

  END;

DELIMITER ;

CALL getCombinations();
select distinct idStrings, region, count from result order by region, count  desc;

DB Fiddle

https://www.db-fiddle.com/f/mHyWsoRjoQwESHtuLiFQ2y/0

优化更新

此版本将多个insert语句替换为仅一个insert语句:

https://www.db-fiddle.com/f/mHyWsoRjoQwESHtuLiFQ2y/0

#Will not work without the following command/Setting:
SET SESSION sql_mode = CONCAT(@@sql_mode, ',PIPES_AS_CONCAT');


create table IF NOT EXISTS testing(
  idString varchar(20),
  region varchar(20)
);

delete from testing;

insert into testing values("abcdefg","123456");
insert into testing values("bcdefgh","123456");
insert into testing values("cdefghi","123456");
insert into testing values("defghij","456789");
insert into testing values("efghijk","456789");
insert into testing values("fghijkl","456789");


DROP PROCEDURE IF EXISTS `sp_split`;
DROP PROCEDURE IF EXISTS `getCombinations`;

CREATE TABLE IF NOT EXISTS `temp` (
  `col` VARCHAR(100) NOT NULL
)
  ENGINE = MEMORY;

CREATE TABLE IF NOT EXISTS `tmpSplit` (
  `variable` VARCHAR(100) NOT NULL
)
  ENGINE = MEMORY;

CREATE TABLE IF NOT EXISTS `result` (
  `idStrings` VARCHAR(100) NOT NULL,
  `region`    VARCHAR(100) NOT NULL,
  `count`     VARCHAR(100) NOT NULL
)
  ENGINE = MEMORY;

DELETE FROM result;
DELETE FROM temp;


DROP VIEW IF EXISTS `testingWithBlanks`;
CREATE VIEW testingWithBlanks AS
  SELECT
    idString,
    region
  FROM testing
  UNION
  select  distinct ' ' as idString , region from testing;

DROP VIEW IF EXISTS `groupByBugWorkaroundView`;
CREATE VIEW groupByBugWorkaroundView AS
  SELECT
    region                   AS region,
    count(DISTINCT idString) AS countInt,
    group_concat(idString)   AS csv
  FROM testingWithBlanks
  GROUP BY region;

CREATE PROCEDURE `sp_split`(IN toSplit TEXT, IN target CHAR(255))
  BEGIN
    # Temp table variables
    SET @tableName = 'tmpSplit';
    SET @fieldName = 'variable';

    #select toSplit;

    # Dropping table
    SET @sql := CONCAT('DROP TABLE IF EXISTS ', @tableName);
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

    # Creating table
    SET @sql := CONCAT('CREATE TABLE IF NOT EXISTS ', @tableName, ' (', @fieldName, ' VARCHAR(1000))');
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

    # Preparing toSplit
    SET @vars := toSplit;
    SET @vars := CONCAT("('", REPLACE(@vars, ",", "'),('"), "')");

    DELETE FROM tmpSplit;

    # Inserting values
    SET @sql := CONCAT('INSERT INTO ', @tableName, ' VALUES ', @vars);
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

    # Returning record set, or inserting into optional target
    IF target IS NULL
    THEN
      SET @sql := CONCAT('SELECT TRIM(`', @fieldName, '`) AS `', @fieldName, '` FROM ', @tableName);
    ELSE
      SET @sql := CONCAT('INSERT INTO ', target, ' SELECT TRIM(`', @fieldName, '`) FROM ', @tableName);
    END IF;

    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

  END;


DROP FUNCTION IF EXISTS `subStringCount`;
CREATE FUNCTION `subStringCount`(sequence VARCHAR(1000), word VARCHAR(100))
  RETURNS INT(4)
DETERMINISTIC
CONTAINS SQL
  BEGIN
    DECLARE counter SMALLINT UNSIGNED DEFAULT 0;
    DECLARE word_length SMALLINT UNSIGNED;

    SET word_length = CHAR_LENGTH(word);

    WHILE (INSTR(sequence, word) != 0) DO
      SET counter = counter + 1;
      SET sequence = SUBSTR(sequence, INSTR(sequence, word) + word_length);
    END WHILE;

    RETURN counter;
  END;


CREATE PROCEDURE getCombinations()
  BEGIN

    DECLARE countInt INT DEFAULT 0;
    DECLARE csv VARCHAR(100);
    DECLARE region2 VARCHAR(100);
    DECLARE v_last_row_fetched INT;
    DECLARE v_counter INT UNSIGNED DEFAULT 1;

    DECLARE counter CURSOR FOR SELECT *
                               FROM groupByBugWorkaroundView;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_last_row_fetched = 1;

    SET SESSION sql_mode = CONCAT(@@sql_mode, ',PIPES_AS_CONCAT');

    DELETE FROM result;
    DELETE FROM tmpSplit;
    COMMIT;

    OPEN counter;
    c1_loop: LOOP
      FETCH counter
      INTO region2, countInt, csv;

      IF v_last_row_fetched = 1
      THEN LEAVE c1_loop;
      END IF;

      CALL sp_split(csv, NULL);

      #       delete from temp;
      #       insert into temp select * from tempSplit;
      #       commit;

      SET @q0 = concat('insert into result select t0.variable ');
      SET @q1 = concat(' from tmpSplit t0');
      SET @q3 = concat(' where 1=1 ');
      SET @q4 = ',\'' || region2 || ' \'';

      #-- DEBUG
      #       set @tempLog = concat('insert into templog values (\'',@q1);
      #       set @tempLog = concat(@q1, ' '');');
      #       PREPARE stmt1 FROM @tempLog;
      #       EXECUTE stmt1;
      #       DEALLOCATE PREPARE stmt1;
      #-- END DEBUG

      SET v_counter = 1;
      WHILE v_counter < countInt DO

        SET @q1 := concat(@q1, ' ,tmpSplit t');
        SET @q1 := concat(@q1, v_counter);

        SET @q0 := concat(@q0, '|| \',\' || t');
        SET @q0 := concat(@q0, v_counter);
        SET @q0 := concat(@q0, '.variable');

        #Necessary joins
        SET @q3 := concat(@q3, ' AND (not t');
        SET @q3 := concat(@q3, v_counter - 1);
        SET @q3 := concat(@q3, '.variable = ');
        SET @q3 := concat(@q3, ' t');
        SET @q3 := concat(@q3, v_counter);
        SET @q3 := concat(@q3, '.variable ');

        SET @q3 := concat(@q3, ' OR t');
        SET @q3 := concat(@q3, v_counter - 1);
        SET @q3 := concat(@q3, '.variable = ');
        SET @q3 := concat(@q3, '\' \')  ');

        #Alphabetical order
        SET @q3 := concat(@q3, ' AND not t');
        SET @q3 := concat(@q3, v_counter - 1);
        SET @q3 := concat(@q3, '.variable > ');
        SET @q3 := concat(@q3, ' t');
        SET @q3 := concat(@q3, v_counter);
        SET @q3 := concat(@q3, '.variable ');

        SET v_counter = v_counter + 1;

        SET @q5 = ',\'' || v_counter || '\'';

        SET @q9 := concat('', '');
        SET @q9 := concat(@q0, @q4);
        SET @q9 := concat(@q9, @q5);
        SET @q9 := concat(@q9, @q1);
        SET @q9 := concat(@q9, @q3);


      END WHILE;

      SELECT @q9 AS debug;

      PREPARE stmt1 FROM @q9;
      EXECUTE stmt1;
      DEALLOCATE PREPARE stmt1;
      COMMIT;

      DELETE FROM temp;
      COMMIT;

    END LOOP c1_loop;
    CLOSE counter;

  END;


CALL getCombinations();

SELECT
  idStrings,
  region,
  subStringCount(idStrings, ',') + 1 AS count
FROM
  (
    SELECT DISTINCT
      REPLACE(idStrings, ' ,', '') AS idStrings,
      region
    FROM result
  ) temp
WHERE subStringCount(idStrings, ',') > 0
ORDER BY region, subStringCount(idStrings, ',') + 1 DESC;

更新

关于人们可以改进的评论(如todo):

https://www.db-fiddle.com/f/wJ2XuB893is9ENaXxuFgCZ/0