【问题标题】:How to outer join two data sets (based on multiple primary keys)?如何外连接两个数据集(基于多个主键)?
【发布时间】:2015-03-20 10:18:19
【问题描述】:

假设我有以下两个数据集:

   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 术语)完全外部连接两个数据集?更重要的是,我可以根据多列/主键来做吗?例如,在这种情况下,按 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
                };
            });

也许有人可以帮我把它变成外部连接?

【问题讨论】:

  • 该调用从select 回调中引发错误。 “未捕获的类型错误:无法读取未定义的属性‘成本’”。你可以先解决这个问题
  • SQL 会不会像 SELECT year, cost, revenue FROM revenueTestData FULL OUTER JOIN costTestData ON revenueTestData.year = costTestData.year
  • 那将只使用年份作为主键加入。最好还有一个AND revenueTestData.customer = costTestData.customer,用于多个主键连接。
  • 该功能只支持一键加入
  • 我知道。我想做一个外连接,如果可能,但不一定,使用多个键。

标签: javascript join outer-join


【解决方案1】:

这里的代码将对单个键进行完全连接。你必须从两边扫描它,你显示的代码是左连接,而不是内连接。支持两个键应该不会太难,无限键需要一点额外的。

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)
&lt;pre id="pre"&gt;&lt;/pre&gt;

【讨论】:

  • 太棒了,这正是我需要的!谢谢! :) 有机会使用多个主键吗?
  • @Cos 我们会把它作为家庭作业留给你;)你至少必须证明你已经尝试过了。如果您尝试过但无法获得,请发布一个单独的问题,显示您尝试过的内容、实际结果和预期结果
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-22
  • 1970-01-01
  • 2019-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多