【问题标题】:Select/Order data from two tables从两个表中选择/排序数据
【发布时间】:2012-11-18 17:05:35
【问题描述】:

我有两张表,其中包含两个不同游戏的游戏数据。为了简单起见,假设他们只共享一个名为Timestamp 的列(特别是他们有不同数量的列)。我想呈现一个包含两个表中信息的列表,同时按Timestamp 排序。

我目前正在做的工作,但我几乎可以打赌,有更好的方法可以做到这一点。我最关心的是某个时候的性能(移动应用程序)。这是一个代表结构的存根——相信我,我知道这看起来有多可怕。我只是想先让它工作,现在我正在寻找改进。 ;)

var readyA,
    readyB = false;

var dataA, 
    dataB;

function doLoop () {
    setTimeout(renderData, 100);
}

function renderData () {
    if (!readyA || !readyB) {
        doLoop();
        return;
    }

    var dataAll = dataA.concat(dataB);
    dataAll.sort(function (a,b) {
        return a['Timestamp'] <= b['Timestamp'];
    });

    // pass data into a template depending on from which game it is and render it
    // ...
}

// wait for both queries to finish
doLoop();

// select data from game A
myDatabaseClass.query('SELECT ... FROM GameA', function (results) {
    dataA = new Array(results.rows.length);
    for (var i=0; i<results.rows.length; i++) { 
        dataA[i] = results.rows.item(i); 
    }

    readyA = true;
});

// select data from game B
myDatabaseClass.query('SELECT ... FROM GameB', function (results) {
    dataB = new Array(results.rows.length);
    for (var i=0; i<results.rows.length; i++) { 
        dataB[i] = results.rows.item(i); 
    }

    readyB = true;
});

现在的问题是我是否可以通过某种UNIONJOIN 在查询中以某种方式简化它。显然,Timeout 结构很糟糕,但如果查询可以在一个查询中完成(或至少一个事务——数据库类可以处理),它会自动折叠为一个简单的回调函数。

编辑:我确实找到了这个 (Pull from two different tables and order),但整个 NULL AS some_column 感觉很脏。真的没有更好的选择吗?

【问题讨论】:

  • @Fahim Parkar:这有点离题,但是“提前致谢”有什么问题?
  • 哦,好吧。那么——我想保持礼貌,但如果它被认为是杂乱无章的,我会把它排除在外。谢谢!

标签: javascript mysql sqlite


【解决方案1】:

查询的结果始终是具有固定列数的单个表,因此所有SELECTs 必须具有相同的列数:

SELECT a1, a2, a3,   Timestamp FROM GameA
UNION ALL
SELECT b1, b2, NULL, Timestamp FROM GameB
ORDER BY Timestamp

UNION ALLUNION 快​​,因为它不会尝试删除重复项。)

【讨论】:

  • 谢谢。列的类型重要吗?这两个表都有很多列。有些列实际上是相同的,但大多数不是。另外,在 SQLite 中,我以后可以轻松地检测出一行来自哪个表吗?在另一个线程中,我读到还选择了 "GameA" AS Type 之类的东西,但这似乎在 SQLite 中不起作用。
  • 哦,UNION ALLUNION 更快的提示也很有帮助。谢谢!
  • 由于 SQLite 的动态类型,列类型对此无关紧要。在 SQL 中,字符串使用单引号。
  • 谢谢,我会用单引号再试一次!
【解决方案2】:

你的代码很不错。从像我这样的 SQL 黑客的角度来看,您正在客户端执行 UNION 和 ORDER BY。这没什么不好。你似乎做的几乎是对的。你的“concat”相当于客户端的UNION,你的“排序”相当于ORDER BY。

你说如果你使用服务器端的UNION 操作,NULL as missing-column 的构造感觉有点脏。但是,显然要将两个不同的结果集视为相同,以便您可以对它们进行排序,以便您必须以某种方式使它们彼此一致。您的排序函数中的a['Timestamp'] &lt;= b['Timestamp'] 排序标准也是一种使两个结果集相互一致的方案。它可能比使用 UNION 的性能更低。

不要害怕使用NULL as missing-column 使UNION 中的两个结果集相互一致。它不脏,也不贵。

请考虑以某种方式限制您的 SELECT 操作,也许是通过一系列时间戳。这将允许您的系统扩展,特别是如果您在用于限制 SELECT 的列上放置索引。

(顺便说一句,你的排序函数有一个错误。排序函数需要根据第一项小于、等于还是大于第二项返回-1、0或+1。您正在返回一个真/假值。这不能正常工作。)

(您将两个查询并行化到同一个 MySQL 实例。这很聪明,但实际上可能是随着游戏规模的扩大而使 My​​SQL 过载的公式。请记住,您游戏的每个用户都有自己的机器在运行Javascript,但它们都共享您的 MySQL。)

【讨论】:

  • 感谢您的详细评论。在这种情况下,我实际上并不担心黑客或用户共享 MySQL,因为这是关于在手机上运行的 SQLite,所以每个用户都有自己的数据库(并操作自己的数据库..我的意思是,如果他们愿意,我不会阻止他们)。我知道比较函数的缺陷,虽然我可以肯定地知道“0”的情况永远不会发生,但无论如何我都会让它变得更好。游戏数量限制的实现方式是当存在一定数量的条目时会要求用户清空数据库[tbc]
  • ... 因为这个数据库实际上只是保存临时游戏。我想摆脱并行查询(通常还不错)的原因是摆脱 Timeout 构造。无论如何,我不确定并行查询在手机上的性能有多好。感谢您的意见,我想我会采用符合方案的“脏”(;))解决方案。
  • 许多排序算法将某些项目与自身进行比较。
  • 说得有道理——没想到。
  • 我最终使用了两个查询的原始方法,但是我只是从两个查询中调用了doIt 而不是超时构造(这已经足够了——无论哪个最后完成都将成为主要部分doIt 的实际执行)。我这样做是因为表不是很小,而且我觉得这使代码更易于维护,所以除非有一个很好的论据反对使用两个查询而不是UNION ALL,我现在会坚持下去。
猜你喜欢
  • 2017-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-13
  • 2012-12-16
  • 2012-09-13
  • 1970-01-01
相关资源
最近更新 更多