考虑需要像这样显示数据的情况:
Parent 1 info
Child 1A info
Child 1B info
...
Parent 2 info
Child 2A info
Child 2B info
...
请注意,孩子只深入一层,因此无需进入数据库级别的“嵌套集”。比如我现在的项目中,数据需要这样显示:
First name | Last name | City | ...
---------------------------------
John | Doe | Denver
Sales:
---------------------
Date | Total | ...
-----------------
Jan 1 | $100
Jan 15 | $200
Feb 1 | $100
Suzie | Springer | New York
Sales:
---------------------
Date | Total | ...
-----------------
...
我的问题是关于获取此页面数据所需的 SQL,同时仍通过使用 LIMIT 子句(或等效子句)进行分页。
在这种情况下,应首先列出最近销售的帐户,但当然每个帐户都需要将其所有销售记录在其下,直到一年前。
让我先问一个更简单的情况:假设排序顺序无关紧要。然后我可以简单地按帐户 ID 排序(简化示例):
SELECT sh.account_id, a.first_name, a.last_name,
sh.sale_id, sh.total, sh.payment_time
FROM sales_header sh
JOIN account a on sh.account_id = a.account_id
WHERE a.account_type = 'parent'
ORDER BY sh.account_id
但是,当引入分页时,如何确保将特定帐户的所有销售额保存在一起?很难知道 LIMIT 应该有多大。
现在让我们添加所需的真正排序顺序:
SELECT sh.account_id, a.first_name, a.last_name,
sh.sale_id, sh.total, sh.payment_time
FROM sales_header sh
JOIN account a on sh.account_id = a.account_id
WHERE a.account_type = 'parent'
ORDER BY sh.payment_time
检索所有行时,没有问题——我可以简单地运行查询,然后在我的应用程序代码(本例中为 PHP)中按 account_id 对结果进行索引。
但是,如果我添加一个 LIMIT,那么我可能无法获得每个帐户的所有销售额,尤其是对于既有旧销售额又有近期销售额的账户。
我已经想出了一个解决方案,但它相当复杂,特别是因为我正在处理动态查询参数而不是我在这里展示的简化版本。我的解决方案是运行两个单独的查询。
首先,获取我需要的所有帐户 ID:
SELECT DISTINCT sh.account_id
FROM sales_header sh
JOIN account a on sh.account_id = a.account_id
WHERE a.account_type = 'parent'
ORDER BY sh.payment_time
LIMIT 10
然后,将 ID 放入名为 $account_ids 的 PHP 数组中,然后构建返回显示页面所需的实际结果的查询:
$sql = 'SELECT sh.account_id, a.first_name, a.last_name,
sh.sale_id, sh.total, sh.payment_time
FROM sales_header sh
JOIN account a on sh.account_id = a.account_id
WHERE sh.account_id IN ('. implode(',', $account_ids). ')
ORDER BY sh.payment_time';
当然,这也可以通过将第一个查询的 SQL 放在 implode() 函数所在的位置,在单个查询中完成,例如:
WHERE sh.account_id IN (SELECT DISTINCT sh.account_id ... LIMIT 10)
但这引起了对子查询和数据库可移植性限制的担忧——我正在使用一个框架,该框架允许您使用可移植到不同数据库的 limit() 方法设置限制,但我不确定如果它会如何反应例如,我尝试在 SQL Server 这样的子查询中使用限制。
所以,我真正的问题是:这是解决问题的最佳方法,还是有替代(更简单)的解决方案?你在类似的情况下做了什么?