假设我有两个表,分别名为customers
和transactions
,示例数据如下:
客户
+----+---------------------------------+------------+------------+
| id | company | first_name | last_name |
+----+---------------------------------+------------+------------+
| 1 | Mus Donec Dignissim LLC | Tad | Hoffman |
| 2 | Aliquet Magna A LLP | Aretha | Wilkinson |
| 3 | Mauris Aliquam Foundation | Cooper | Goff |
| 4 | Quisque Libero Lacus Associates | Fulton | Beard |
| 5 | At Risus Ltd | Simone | Perkins |
| 6 | Quam Corp. | Hayfa | Hernandez |
| 7 | Vel Quam Dignissim Associates | Linus | Walker |
| 8 | A Enim Suspendisse Consulting | Emi | Wallace |
| 9 | Placerat Industries | Cody | Mendez |
| 10 | Nunc Limited | Yasir | Cunningham |
+----+---------------------------------+------------+------------+
交易
+----+-----------+-------------+------+
| id | form_type | customer_id | due |
+----+-----------+-------------+------+
| 1 | invoice | 9 | 1.08 |
| 2 | payment | 1 | 6.32 |
| 3 | invoice | 7 | 9.42 |
| 4 | payment | 9 | 3.58 |
| 5 | invoice | 7 | 5.35 |
| 6 | payment | 3 | 5.42 |
| 7 | invoice | 9 | 5.32 |
| 8 | invoice | 9 | 9.62 |
| 9 | invoice | 10 | 1.40 |
| 10 | invoice | 2 | 3.72 |
+----+-----------+-------------+------+
我想为3个客户根据某种条件(请参阅下面的SQL)选择所有交易,这些客户分别按其company
,first_name
和last_name
的字母顺序进行排序。
因此,其想法是,在输出中可以返回多于3行,因为一个特定客户可以有多个匹配交易,但总共应该只有3个客户。
我知道下面的SQL显然错误地限制了所需数据的行数,而不是单独的客户数,但这是为了使问题更清楚:
SELECT
t.id AS trans_id,
c.id AS customer_id,
c.company,
c.first_name,
c.last_name,
t.due
FROM `customers` AS c, `transactions` AS t
WHERE t.due > 0 AND t.form_type = 'invoice' AND c.id = t.customer_id
ORDER BY c.company, c.first_name, c.last_name
LIMIT 0, 3
我已经尝试过使用INNER JOIN
或Subquery的方法,但是它们要么返回了错误的数据,要么SQL对我来说似乎不合适。我正在为此寻求一些专家解决方案。
更新
我忘了提及我不能将IN
用于子查询结果,因为MySQL版本拒绝了它。
此版本的MySQL尚不支持“ LIMIT&IN / ALL / ANY / SOME子查询”。
请提供替代方法。
答案 0 :(得分:1)
方法1 -如果需要使用单个查询,并直接以所需格式获取结果:
SELECT
t.id AS trans_id,
c.id AS customer_id,
c.company,
c.first_name,
c.last_name,
t.due
FROM transactions AS t
INNER JOIN (SELECT c2.*
FROM customers AS c2
INNER JOIN transactions AS t2 ON t2.customer_id = c2.id
WHERE t2.due > 0 AND t2.form_type = 'invoice'
GROUP BY c2.id
ORDER BY c2.company, c2.first_name, c2.last_name
LIMIT 0, 3
) AS c ON c.id = t.customer_id
WHERE t.due > 0 AND
t.form_type = 'invoice'
ORDER BY c.company, c.first_name, c.last_name
方法2 -使用更高效的查询(减少WHERE
条件),然后使用应用程序代码对查询结果进行分叉,以获取所需格式:
SELECT
c.id AS customer_id,
c.company,
c.first_name,
c.last_name,
GROUP_CONCAT(CONCAT(t.id,':',t.due)) AS trans_details
FROM customers AS c
INNER JOIN transactions AS t
WHERE t.due > 0 AND
t.form_type = 'invoice'
GROUP BY c.id
ORDER BY c.company, c.first_name, c.last_name
现在,在应用程序代码中,您可以将trans_details
分叉:
// $query_results is the sql result rows obtained in associative mode
foreach ($query_results as $key => $row) {
// Get all separate transactions into array
$trans_details = explode(',', $row['trans_details']);
foreach ($trans_details as $trans) {
$temp = explode(':', $trans);
// Add trans_id and due to get desired format
$query_results[$key]['trans_id'] = $temp[0];
$query_results[$key]['due'] = $temp[1];
}
}
答案 1 :(得分:1)
我相信这是您想要的:
SELECT
t.id AS trans_id,
c.id AS customer_id,
c.company,
c.first_name,
c.last_name,
t.due
FROM (
SELECT DISTINCT c.*
FROM customers AS c
INNER JOIN transactions AS t ON t.customer_id = c.id
WHERE t.due > 0
AND t.form_type = 'invoice'
ORDER BY c.company, c.first_name, c.last_name
LIMIT 3
) AS c
INNER JOIN transactions AS t ON t.customer_id = c.id
WHERE t.due > 0
AND t.form_type = 'invoice'
ORDER BY c.company, c.first_name, c.last_name;
如果使用更高版本的MySQL的人发现了这个问题,则在MySQL 8.0中,您可以使用公用表表达式,该表表达式允许从查询中删除重复项。从https://stackoverflow.com/a/52137146/495319
查询WITH cte AS (
SELECT
t.id AS trans_id,
c.id AS customer_id,
c.company,
c.first_name,
c.last_name,
t.due,
DENSE_RANK() OVER(ORDER BY c.company, c.first_name, c.last_name) AS rn
FROM customers AS c
INNER JOIN transactions AS t ON t.customer_id = c.id
WHERE t.due > 0 AND t.form_type = 'invoice'
)
SELECT * FROM cte WHERE rn <= 3;