在比较列中的代码后查找两张表之间的差异行
Find Difference Rows between two Sheets after comparing their Codes in a Column
我试图找到添加到 Data
Sheet 的 NEW
行,方法是将位于列中的 Codes
与 Codes
进行比较位于 Database
Sheet 的列中。我通过找出两个代码之间的区别来做到这一点。
...
// Get Mappings array
let Maplist = shtMap.getRange(2, 1, r_Map - 1, 2).getValues();
// find new codes that have come in the Data sheet
let DataCodes = [...new Set(shtData.getRange(2, 1, r_Data - 1, 1).getValues().flat())];
let DatabaseCodes = [...new Set(shtDatabase.getRange(2, 2, r_Database - 1, 1).getValues().flat())];
let diff =[];
// ===> Below is the line I want to modify to incorporate all the logic given in my Notes section.
diff = DataCodes.reduce( (diff,x) => !DatabaseCodes.includes(x) ? [...diff, [x]] : diff, []);
// Map Emp name to diff Array ===> not working....getting error!
diff = diff.map(function(x, i , arr){
if(arr.indexOf(x) == i){
return [...diff, [arr[i][1]]);
}
}, (Maplist));
// Add Data Validation to `Status` column
var Rng = shtDatabase.getRange(r_Database + 1, 7, diff.length -1, 1);
Rng.clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList([`Open`,`Complete`], true).build();
Rng.setDataValidation(rule); // Update `Status` value
...
上面的代码给出了 Difference i.e. new Codes
已经进入 Database
Sheet。有没有办法修改上面的 Reduce function code
来拉入 entire new rows
,这样 diff Array
就可以附加到 Database
Sheet 的末尾?
注:
这里Database Sheet
中的Delivery Date
是指Data Sheet
中的FinalDate
。是否可以修改上面的代码以考虑不匹配的列名,以便 FinalDate
列值正好放在 Delivery Date
列中?
我还需要在 Database Sheet
的 Status Column
中添加一个包含值 Open,Complete
的 DataValidation dropdown
,对于 [=33] 中的每个新行=].上面的代码如何考虑数据验证代码?
如您所见,Database Sheet
中的 matching columns
不连续且与 Data Sheet
的顺序相同,而是分布在 Sheet 中].能否修改代码以将每个 diff 数组值正确放置到各自的列中?
最后,我必须将 Database Sheet
中的每个 Owner
名称与 Mapping Sheet
数组(其中包含 Owner
名称和它的相应的 Emp
名称),然后匹配其相应的 Emp
名称并将其相应地添加到 Database Sheet
中的 Emp
列。
原因:
- 我想在内存中完成所有这些,最后将这个内存数组一次性转移到
Database Sheet
。否则,重复访问(read/write)Sheets 代码到运行需要花费大量时间,尤其是数据量大的时候。这可以用一些consice代码吗?
数据Sheet:
数据库Sheet:
映射Sheet
这是 [示例文件][4] 的 link。
[4]:
编辑:
https://docs.google.com/spreadsheets/d/1DARGtbN8EyEKyF9ceuOusStvuPIXjUR_8OrqfhPxpNQ/edit?usp=sharing
@TheMaster,这是写在文件中的全部代码:
function myTest(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const shtData = ss.getSheetByName("Data");
const shtMap = ss.getSheetByName("Mapping");
const shtDatabase = ss.getSheetByName("Database");
// get Data Sheet unique list of Owners
let r_Data = FindLastRow(shtData);
let c_Data = FindLastColumn(shtData);
let list = shtData.getRange(2, 4, r_Data - 1, 1).getValues();
let Datalist = [...new Set(list.flat())];
// get Mapping Sheet unique list of Owners
r_Map = FindLastRow(shtMap);
c_Map = FindLastColumn(shtMap);
list = shtMap.getRange(2, 1, r_Map - 1, 1).getValues();
let Maplist = [...new Set(list.flat())];
// find new codes that have come in the Data sheet
r_Database = FindLastRow(shtDatabase);
c_Database = FindLastColumn(shtDatabase);
let DataCodes = [...new Set(shtData.getRange(2, 1, r_Data - 1, 1).getValues().flat())];
let DatabaseCodes = [...new Set(shtDatabase.getRange(2, 2, r_Database - 1, 1).getValues().flat())];
// find the difference between the 2 arrays and append the new ones to Mapping Sheet, then sort.
let diff = Datalist.reduce( (diff,x) => !Maplist.includes(x) ? [...diff, [x,'Unassigned']] : diff,[]);
if(diff.length !== 0){
shtMap.getRange(r_Map + 1, 1, diff.length, diff[0].length).setValues(diff);
}
// Sort the Mappings Sheet on 2nd column, then 1st column
shtMap.getDataRange().offset(1, 0, shtMap.getDataRange().getNumRows() - 1).sort([{column: 2, ascending: true}, {column: 1, ascending: true}]);
// diff =[];
// ===> Below is the line I want to modify to incorporate all the logic given in my Notes section.
diff = DataCodes.reduce( (diff,x) => !DatabaseCodes.includes(x) ? [...diff, [x]] : diff, []);
// From Notes : Map Emp name to diff Array ===> not working....getting error!
diff = diff.map( function(x, i, arr){
if(arr.indexOf(x) == i){
return [...diff, arr[1][i]];
}
}, (Maplist));
// From Notes : Add Data Validation to `Status` column
var Rng = shtDatabase.getRange(r_Database + 1, 7, diff.length -1, 1);
Rng.clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList([`Open`,`Complete`], true).build();
Rng.setDataValidation(rule); // Update `Status` value
}
function FindLastRow(sht) {
return sht.getRange(1,1).getDataRegion().getLastRow();
};
function FindLastColumn(sht) {
return sht.getRange(1,1).getDataRegion().getLastColumn();
};
编辑:
@Tanaike,我更新了 post 中的屏幕截图并更新了传播 sheet。例如Data
sheet 中的黄色行是 new rows
,因此需要正确放置在 Database
sheet 中,并在 Status
中添加数据验证列,Emp
名称在 Emp
列中(在将 Owner
与映射 Sheet 匹配之后)。 Data
sheet 中的 FinalDate
列是 Database
sheet 中的 Delivery Date
列。
我们的想法是创建一个consice代码来创建一个二维数组(应该包括数据验证和Emp名称),将所有新数据正确地放置在Database
sheet .我想避免每次都将数据写入 sheet 以更新 Database
sheet.
中的每一列
如何将以下示例脚本添加到 myTest()
的底部?
修改后的脚本:
从:
var Rng = shtDatabase.getRange(r_Database + 1, 7, diff.length -1, 1);
Rng.clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList([`Open`,`Complete`], true).build();
Rng.setDataValidation(rule); // Update `Status` value
}
到:
var Rng = shtDatabase.getRange(r_Database + 1, 7, diff.length -1, 1);
Rng.clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList([`Open`,`Complete`], true).build();
Rng.setDataValidation(rule); // Update `Status` value
// I added below script.
const mapObj = shtMap.getRange("A2:B" + shtMap.getLastRow()).getValues().reduce((o, [a, b]) => Object.assign(o, {[a]: b}), {});
const existingIdsObj = shtDatabase.getRange("B2:B" + shtData.getLastRow()).getValues().reduce((o, [b]) => Object.assign(o, {[b]: true}), {});
const putValues = shtData.getRange("A2:G" + shtData.getLastRow()).getValues().reduce((ar, [a,b,c,d,e,f,g]) => {
if (!existingIdsObj.hasOwnProperty(a)) ar.push([b, a, f, c, , , , d, e, , , g, , mapObj[d]]);
return ar;
}, []);
shtDatabase.getRange(shtDatabase.getLastRow() + 1, 1, putValues.length, putValues[0].length).setValues(putValues);
}
- 为了检查重复的 ID 并输入
Emp
值,我使用了 mapObj
和 existingIdsObj
的 JSON 个对象。
我试图找到添加到 Data
Sheet 的 NEW
行,方法是将位于列中的 Codes
与 Codes
进行比较位于 Database
Sheet 的列中。我通过找出两个代码之间的区别来做到这一点。
...
// Get Mappings array
let Maplist = shtMap.getRange(2, 1, r_Map - 1, 2).getValues();
// find new codes that have come in the Data sheet
let DataCodes = [...new Set(shtData.getRange(2, 1, r_Data - 1, 1).getValues().flat())];
let DatabaseCodes = [...new Set(shtDatabase.getRange(2, 2, r_Database - 1, 1).getValues().flat())];
let diff =[];
// ===> Below is the line I want to modify to incorporate all the logic given in my Notes section.
diff = DataCodes.reduce( (diff,x) => !DatabaseCodes.includes(x) ? [...diff, [x]] : diff, []);
// Map Emp name to diff Array ===> not working....getting error!
diff = diff.map(function(x, i , arr){
if(arr.indexOf(x) == i){
return [...diff, [arr[i][1]]);
}
}, (Maplist));
// Add Data Validation to `Status` column
var Rng = shtDatabase.getRange(r_Database + 1, 7, diff.length -1, 1);
Rng.clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList([`Open`,`Complete`], true).build();
Rng.setDataValidation(rule); // Update `Status` value
...
上面的代码给出了 Difference i.e. new Codes
已经进入 Database
Sheet。有没有办法修改上面的 Reduce function code
来拉入 entire new rows
,这样 diff Array
就可以附加到 Database
Sheet 的末尾?
注:
这里
Database Sheet
中的Delivery Date
是指Data Sheet
中的FinalDate
。是否可以修改上面的代码以考虑不匹配的列名,以便FinalDate
列值正好放在Delivery Date
列中?我还需要在
Database Sheet
的Status Column
中添加一个包含值Open,Complete
的DataValidation dropdown
,对于 [=33] 中的每个新行=].上面的代码如何考虑数据验证代码?如您所见,
Database Sheet
中的matching columns
不连续且与Data Sheet
的顺序相同,而是分布在 Sheet 中].能否修改代码以将每个 diff 数组值正确放置到各自的列中?最后,我必须将
Database Sheet
中的每个Owner
名称与Mapping Sheet
数组(其中包含Owner
名称和它的相应的Emp
名称),然后匹配其相应的Emp
名称并将其相应地添加到Database Sheet
中的Emp
列。
原因:
- 我想在内存中完成所有这些,最后将这个内存数组一次性转移到
Database Sheet
。否则,重复访问(read/write)Sheets 代码到运行需要花费大量时间,尤其是数据量大的时候。这可以用一些consice代码吗?
数据Sheet:
这是 [示例文件][4] 的 link。
[4]:
编辑: https://docs.google.com/spreadsheets/d/1DARGtbN8EyEKyF9ceuOusStvuPIXjUR_8OrqfhPxpNQ/edit?usp=sharing
@TheMaster,这是写在文件中的全部代码:
function myTest(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const shtData = ss.getSheetByName("Data");
const shtMap = ss.getSheetByName("Mapping");
const shtDatabase = ss.getSheetByName("Database");
// get Data Sheet unique list of Owners
let r_Data = FindLastRow(shtData);
let c_Data = FindLastColumn(shtData);
let list = shtData.getRange(2, 4, r_Data - 1, 1).getValues();
let Datalist = [...new Set(list.flat())];
// get Mapping Sheet unique list of Owners
r_Map = FindLastRow(shtMap);
c_Map = FindLastColumn(shtMap);
list = shtMap.getRange(2, 1, r_Map - 1, 1).getValues();
let Maplist = [...new Set(list.flat())];
// find new codes that have come in the Data sheet
r_Database = FindLastRow(shtDatabase);
c_Database = FindLastColumn(shtDatabase);
let DataCodes = [...new Set(shtData.getRange(2, 1, r_Data - 1, 1).getValues().flat())];
let DatabaseCodes = [...new Set(shtDatabase.getRange(2, 2, r_Database - 1, 1).getValues().flat())];
// find the difference between the 2 arrays and append the new ones to Mapping Sheet, then sort.
let diff = Datalist.reduce( (diff,x) => !Maplist.includes(x) ? [...diff, [x,'Unassigned']] : diff,[]);
if(diff.length !== 0){
shtMap.getRange(r_Map + 1, 1, diff.length, diff[0].length).setValues(diff);
}
// Sort the Mappings Sheet on 2nd column, then 1st column
shtMap.getDataRange().offset(1, 0, shtMap.getDataRange().getNumRows() - 1).sort([{column: 2, ascending: true}, {column: 1, ascending: true}]);
// diff =[];
// ===> Below is the line I want to modify to incorporate all the logic given in my Notes section.
diff = DataCodes.reduce( (diff,x) => !DatabaseCodes.includes(x) ? [...diff, [x]] : diff, []);
// From Notes : Map Emp name to diff Array ===> not working....getting error!
diff = diff.map( function(x, i, arr){
if(arr.indexOf(x) == i){
return [...diff, arr[1][i]];
}
}, (Maplist));
// From Notes : Add Data Validation to `Status` column
var Rng = shtDatabase.getRange(r_Database + 1, 7, diff.length -1, 1);
Rng.clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList([`Open`,`Complete`], true).build();
Rng.setDataValidation(rule); // Update `Status` value
}
function FindLastRow(sht) {
return sht.getRange(1,1).getDataRegion().getLastRow();
};
function FindLastColumn(sht) {
return sht.getRange(1,1).getDataRegion().getLastColumn();
};
编辑:
@Tanaike,我更新了 post 中的屏幕截图并更新了传播 sheet。例如Data
sheet 中的黄色行是 new rows
,因此需要正确放置在 Database
sheet 中,并在 Status
中添加数据验证列,Emp
名称在 Emp
列中(在将 Owner
与映射 Sheet 匹配之后)。 Data
sheet 中的 FinalDate
列是 Database
sheet 中的 Delivery Date
列。
我们的想法是创建一个consice代码来创建一个二维数组(应该包括数据验证和Emp名称),将所有新数据正确地放置在Database
sheet .我想避免每次都将数据写入 sheet 以更新 Database
sheet.
如何将以下示例脚本添加到 myTest()
的底部?
修改后的脚本:
从: var Rng = shtDatabase.getRange(r_Database + 1, 7, diff.length -1, 1);
Rng.clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList([`Open`,`Complete`], true).build();
Rng.setDataValidation(rule); // Update `Status` value
}
到:
var Rng = shtDatabase.getRange(r_Database + 1, 7, diff.length -1, 1);
Rng.clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList([`Open`,`Complete`], true).build();
Rng.setDataValidation(rule); // Update `Status` value
// I added below script.
const mapObj = shtMap.getRange("A2:B" + shtMap.getLastRow()).getValues().reduce((o, [a, b]) => Object.assign(o, {[a]: b}), {});
const existingIdsObj = shtDatabase.getRange("B2:B" + shtData.getLastRow()).getValues().reduce((o, [b]) => Object.assign(o, {[b]: true}), {});
const putValues = shtData.getRange("A2:G" + shtData.getLastRow()).getValues().reduce((ar, [a,b,c,d,e,f,g]) => {
if (!existingIdsObj.hasOwnProperty(a)) ar.push([b, a, f, c, , , , d, e, , , g, , mapObj[d]]);
return ar;
}, []);
shtDatabase.getRange(shtDatabase.getLastRow() + 1, 1, putValues.length, putValues[0].length).setValues(putValues);
}
- 为了检查重复的 ID 并输入
Emp
值,我使用了mapObj
和existingIdsObj
的 JSON 个对象。