Обновите таблицу из другой таблицы, используя динамические ссылки на столбцы в MySql 5.7 - PullRequest
0 голосов
/ 24 октября 2019

У меня есть две таблицы NEW_TBL и CURRENT_TBL.

Значения в CURRENT_TBL необходимо обновить, чтобы они были равны NEW_TBL. Обе таблицы имеют PK с именем tableId, но столбцы в NEW_TBL не всегда будут соответствовать CURRENT_TBL. У меня уже есть то, что мне нужно, чтобы схема была такой же, но мне нужен метод для обновления значений CURRENT_TBL на основе динамической ссылки на столбец.

Вот надуманный пример того, как я мог бы сделать это в javascript.

Начальные таблицы:

currentTable = [
  ['tableId','col2','col3','col4'],
  ['1','purple','blue','pink'],
  ['2','purple','red','orange'],
  ['3','green','yellow','purple']
];


newTable = [
  ['tableId','col2','col3','col4'],
  ['1','','blue','pink'],
  ['2','magenta','blue','pink'],
  ['4','grey','black','white']
];

Функция:

function updateCurrentTable() {
  var currentHeader = currentTable[0];
  var newHeader = newTable[0];
  var currentValues = currentTable.slice(1);
  var newValues = newTable.slice(1);

  var newIdList = newValues.map(function(val){ // Get list of newTable ids
    return val[0];
  })

  var currentIdList = currentValues.map(function(val){ // Get list of newTable ids
    return val[0];
  })

  for (var newColumn = 0; newColumn<newHeader.length; newColumn++) { // Loop through new table columns
    var columnName = newHeader[newColumn];
    var newIdColumn = newHeader.indexOf('tableId');
    var currentColumnIndex = currentHeader.indexOf(columnName);
    var currentIdIndex = currentHeader.indexOf('tableId');

    if (columnName !== 'tableId') { // The tableId column is skipped because the id will never be altered

      for (var newRow = 0; newRow<newValues.length; newRow++) { // Loop through new table rows
        var newId = newValues[newRow][newIdColumn];
        var newValue = newValues[newRow][newColumn];

        if (currentIdList.indexOf(newId) < 0) { // If tableId exists in newTable but not in currentTable, add the row to currentTable
          currentValues.push(newValues[newRow]);
          currentIdList.push(newId); // Update the id list
        }

        for (var curRow =0; curRow < currentValues.length; curRow++) { // Loop through current table rows
          var currentId = currentValues[curRow][currentIdIndex];

          if (currentColumnIndex !== currentIdIndex) { // The tableId column is skipped because the id will never be altered

            if (newIdList.indexOf(currentId) < 0) { // If tableId exists in currentTable but not newTable, remove the row from currentTable
              currentValues.splice(curRow,1);
            } else if (newId === currentId) { // If the tableIds match, update the value in the current column
              currentValues[curRow][currentColumnIndex] = newValue; 
            } 
          }
        }
      }
    }
  }

  Logger.log(currentValues)
}

Результат:

currentTable = [
  ['tableId','col2','col3','col4'],
  ['1','','blue','pink'],
  ['2','magenta','blue','pink'],
  ['4','grey','black','white']
];

Есть ли способ выполнить вышеперечисленное в SQL?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 26 октября 2019

Я нашел решение, которое динамически создает часть оператора SQL, сравнивающего столбцы (то есть «currentTable.cost = newTable.cost»), а затем запускает UPDATE JOIN с динамическим списком столбцов.

DELIMITER //
 CREATE PROCEDURE matchCurrentToNew()
 COMMENT 'Update currentTable to match newTable'
 BEGIN

    DECLARE num_rows INT;
    DECLARE col_name TINYTEXT;
    DECLARE concatStatement TINYTEXT;
    DECLARE concatFields TINYTEXT;
    DECLARE done TINYINT DEFAULT FALSE; 

    DECLARE col_names 
      CURSOR FOR
        SELECT column_name
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE table_name = 'TASKS'
        ORDER BY ordinal_position;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    SET concatStatement = "";
    OPEN col_names;

    SELECT FOUND_ROWS() into num_rows;

    the_loop: LOOP

        FETCH NEXT FROM col_names    
        INTO col_name; 

        IF done THEN
          CLOSE col_names;
          LEAVE the_loop;
        END IF;

        IF col_name <> "UniqueId" AND col_name <> "ProjectId" THEN
            SET concatFields = CONCAT_WS("=",
                                     CONCAT_WS(".","currentTable",col_name),
                                     CONCAT_WS(".","newTable",col_name)
                                    );

            SET concatStatement = CONCAT(concatStatement,",",concatFields);         
        END IF;

    END LOOP the_loop;

    #     Remove comma at the beginning of the concatStatement string

    SET concatStatement = TRIM(LEADING "," FROM concatStatement);

    SET @sqlText = CONCAT(
      'UPDATE currentTable  
      JOIN newTable
      ON currentTable .UniqueId = newTable.UniqueId 
      AND currentTable .ProjectId = newTable.ProjectId
      SET ', concatStatement
    );

    PREPARE stmt FROM @sqlText;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

 END //
 DELIMITER ;
0 голосов
/ 24 октября 2019

Я понимаю, что вы хотите сопоставить таблицы в столбце tableId и обновить colHeader в current_tbl с соответствующим значением из new_tbl.

. Для этого вы можете воспользоватьсясинтаксис MySQL update ... join ... set:

update current_tbl c
inner join new_tbl n on c.tableId   = n.tableId
set c.colHeader = n.colHeader
...