如何外连接两个数据集(基于多个主键)?
How to outer join two data sets (based on multiple primary keys)?
假设我有以下两个数据集:
var revenueTestData = [
{"YEAR": "2007", "MONTH": "1", "CUSTOMER": "Customer1", "REVENUE": "1938.49488391425"},
{"YEAR": "2007", "MONTH": "1", "CUSTOMER": "Customer2", "REVENUE": "75.9142774343491"},
{"YEAR": "2007", "MONTH": "2", "CUSTOMER": "Customer2", "REVENUE": "99.3456067931875"}];
和
var costTestData = [
{"YEAR": "2009", "MONTH": "1", "CUSTOMER": "Customer4", "COST": "14425"},
{"YEAR": "2009", "MONTH": "1", "CUSTOMER": "Customer4", "COST": "7591"},
{"YEAR": "2009", "MONTH": "2", "CUSTOMER": "Customer5", "COST": "31875"}];
我如何(在 sql 术语中)完全外部连接两个数据集?更重要的是,我可以基于多个 columns/primary 键来完成吗?例如,在这种情况下,按 YEAR 和 CUSTOMER 加入并获取 YEAR、CUSTOMER、REVENUE 的所有值,即使年份不匹配(在这种情况下,缺失的列将为空)。
我遇到了以下编写精美的函数,我可以使用它进行 LEFT JOIN 并决定将哪些列包含在我的结果集中,但是当年份不匹配时,它们就会从结果集中消失(正如在内部联接中所预期的那样):
function innerjoinData(primary, foreign, primaryKey, foreignKey, select) {
var m = primary.length, n = foreign.length, index = [], c = [];
for (var i = 0; i < m; i++) { // loop through m items
var row = primary[i];
index[row[primaryKey]] = row; // create an index for primary table
}
for (var j = 0; j < n; j++) { // loop through n items
var y = foreign[j];
var x = index[y[foreignKey]]; // get corresponding row from primary
c.push(select(x, y)); // select only the columns you need
}
return c;
}
调用示例如下所示:
var testChartData= innerjoinData(revenueTestData, costTestData, "YEAR", "YEAR", function (a, b) {
return {
Year: b.YEAR,
Cost: a.COST,
Revenue: b.REVENUE
};
});
也许有人可以帮我把它变成一个外部连接?
这是对单个键进行完全连接的代码。您必须从两侧扫描它,您显示的代码是在进行左连接,而不是内部连接。支持双键应该不会太难,无限键会多花点钱。
function innerjoinData(primaryTable, foreignTable, primaryKey, foreignKey, selectColumns) {
var primaryIndex = mapFromArray(primaryTable, primaryKey),
foreignIndex = mapFromArray(foreignTable, foreignKey),
resultSet = [];
// Look for misses and matches from the left
for (var i = 0; i < primaryTable.length; i++) {
var primaryRow = primaryTable[i];
var match = foreignIndex[primaryRow[primaryKey]];
resultSet.push(selectColumns(primaryRow, match || {}));
}
// Look for just misses from the right
for (var i = 0; i < foreignTable.length; i++) {
var foreignRow = foreignTable[i];
if (!primaryIndex.hasOwnProperty( foreignRow[foreignKey] )) {
resultSet.push(selectColumns({}, foreignRow))
}
}
return resultSet;
function mapFromArray(list, keyByProp) {
var map = {};
for (var i = 0, item; item = list[i]; i++) {
map[item[keyByProp]] = item;
}
return map;
};
}
var revenueTestData = [{
"YEAR": "2006",
"MONTH": "1",
"CUSTOMER": "Customer1",
"REVENUE": "1938.49488391425"
}, {
"YEAR": "2007",
"MONTH": "1",
"CUSTOMER": "Customer2",
"REVENUE": "75.9142774343491"
}, {
"YEAR": "2008",
"MONTH": "2",
"CUSTOMER": "Customer2",
"REVENUE": "99.3456067931875"
}];
var costTestData = [{
"YEAR": "2007",
"MONTH": "1",
"CUSTOMER": "Customer4",
"COST": "14425"
}, {
"YEAR": "2008",
"MONTH": "1",
"CUSTOMER": "Customer4",
"COST": "7591"
}, {
"YEAR": "2009",
"MONTH": "2",
"CUSTOMER": "Customer5",
"COST": "31875"
}];
var testChartData = innerjoinData(costTestData, revenueTestData, "YEAR", "YEAR", function (primaryRow, foreignRow) {
return {
Year: foreignRow.YEAR || primaryRow.YEAR,
Cost: primaryRow.COST,
Revenue: foreignRow.REVENUE,
Customer:foreignRow.CUSTOMER
};
});
document.getElementById('pre').innerHTML = JSON.stringify(testChartData, null, 4)
<pre id="pre"></pre>
假设我有以下两个数据集:
var revenueTestData = [
{"YEAR": "2007", "MONTH": "1", "CUSTOMER": "Customer1", "REVENUE": "1938.49488391425"},
{"YEAR": "2007", "MONTH": "1", "CUSTOMER": "Customer2", "REVENUE": "75.9142774343491"},
{"YEAR": "2007", "MONTH": "2", "CUSTOMER": "Customer2", "REVENUE": "99.3456067931875"}];
和
var costTestData = [
{"YEAR": "2009", "MONTH": "1", "CUSTOMER": "Customer4", "COST": "14425"},
{"YEAR": "2009", "MONTH": "1", "CUSTOMER": "Customer4", "COST": "7591"},
{"YEAR": "2009", "MONTH": "2", "CUSTOMER": "Customer5", "COST": "31875"}];
我如何(在 sql 术语中)完全外部连接两个数据集?更重要的是,我可以基于多个 columns/primary 键来完成吗?例如,在这种情况下,按 YEAR 和 CUSTOMER 加入并获取 YEAR、CUSTOMER、REVENUE 的所有值,即使年份不匹配(在这种情况下,缺失的列将为空)。
我遇到了以下编写精美的函数,我可以使用它进行 LEFT JOIN 并决定将哪些列包含在我的结果集中,但是当年份不匹配时,它们就会从结果集中消失(正如在内部联接中所预期的那样):
function innerjoinData(primary, foreign, primaryKey, foreignKey, select) {
var m = primary.length, n = foreign.length, index = [], c = [];
for (var i = 0; i < m; i++) { // loop through m items
var row = primary[i];
index[row[primaryKey]] = row; // create an index for primary table
}
for (var j = 0; j < n; j++) { // loop through n items
var y = foreign[j];
var x = index[y[foreignKey]]; // get corresponding row from primary
c.push(select(x, y)); // select only the columns you need
}
return c;
}
调用示例如下所示:
var testChartData= innerjoinData(revenueTestData, costTestData, "YEAR", "YEAR", function (a, b) {
return {
Year: b.YEAR,
Cost: a.COST,
Revenue: b.REVENUE
};
});
也许有人可以帮我把它变成一个外部连接?
这是对单个键进行完全连接的代码。您必须从两侧扫描它,您显示的代码是在进行左连接,而不是内部连接。支持双键应该不会太难,无限键会多花点钱。
function innerjoinData(primaryTable, foreignTable, primaryKey, foreignKey, selectColumns) {
var primaryIndex = mapFromArray(primaryTable, primaryKey),
foreignIndex = mapFromArray(foreignTable, foreignKey),
resultSet = [];
// Look for misses and matches from the left
for (var i = 0; i < primaryTable.length; i++) {
var primaryRow = primaryTable[i];
var match = foreignIndex[primaryRow[primaryKey]];
resultSet.push(selectColumns(primaryRow, match || {}));
}
// Look for just misses from the right
for (var i = 0; i < foreignTable.length; i++) {
var foreignRow = foreignTable[i];
if (!primaryIndex.hasOwnProperty( foreignRow[foreignKey] )) {
resultSet.push(selectColumns({}, foreignRow))
}
}
return resultSet;
function mapFromArray(list, keyByProp) {
var map = {};
for (var i = 0, item; item = list[i]; i++) {
map[item[keyByProp]] = item;
}
return map;
};
}
var revenueTestData = [{
"YEAR": "2006",
"MONTH": "1",
"CUSTOMER": "Customer1",
"REVENUE": "1938.49488391425"
}, {
"YEAR": "2007",
"MONTH": "1",
"CUSTOMER": "Customer2",
"REVENUE": "75.9142774343491"
}, {
"YEAR": "2008",
"MONTH": "2",
"CUSTOMER": "Customer2",
"REVENUE": "99.3456067931875"
}];
var costTestData = [{
"YEAR": "2007",
"MONTH": "1",
"CUSTOMER": "Customer4",
"COST": "14425"
}, {
"YEAR": "2008",
"MONTH": "1",
"CUSTOMER": "Customer4",
"COST": "7591"
}, {
"YEAR": "2009",
"MONTH": "2",
"CUSTOMER": "Customer5",
"COST": "31875"
}];
var testChartData = innerjoinData(costTestData, revenueTestData, "YEAR", "YEAR", function (primaryRow, foreignRow) {
return {
Year: foreignRow.YEAR || primaryRow.YEAR,
Cost: primaryRow.COST,
Revenue: foreignRow.REVENUE,
Customer:foreignRow.CUSTOMER
};
});
document.getElementById('pre').innerHTML = JSON.stringify(testChartData, null, 4)
<pre id="pre"></pre>