MySQL对第二次加入查询的限制

MySQL对第二次加入查询的限制,mysql,join,limit,Mysql,Join,Limit,我不知道如何限制查询中的第二个联接。在我准备的示例中,我需要限制结果中每个用户的行数 表a: id | word ---------- 1 | xyz 2 | zzz 表b: name | word ------------ Peter | xyz John | xyz Jane | xyz 表c: name | product ------------ Peter | blah Peter | blah2 Peter | blah3 Peter | blah4 Peter |

我不知道如何限制查询中的第二个联接。在我准备的示例中,我需要限制结果中每个用户的行数

表a:

id | word
----------
1  | xyz
2  | zzz
表b:

name  | word
------------
Peter | xyz
John  | xyz
Jane  | xyz
表c:

name  | product
------------
Peter | blah
Peter | blah2
Peter | blah3
Peter | blah4
Peter | blah5
Peter | blah6
John | hello
John | world
John | blah
预期结果:表b的前两个条目(用户Peter和John)和表c中每个用户的前两个条目合并

name  | word | product
----------------------
Peter | xyz | blah
Peter | xyz | blah2
John  | xyz | hello
John  | xyz | world
我现在的问题是

select c.name, first_join.word, c.product from (
select b.* from a
left join b on b.word=a.word
where a.id=1
limit 2
) first_join
left join c on c.name=first_join.name
结果如下:

name  | word | product
------------------------------
Peter | xyz  | blah
Peter | xyz  | blah2
Peter | xyz  | blah3
Peter | xyz  | blah4
Peter | xyz  | blah5
Peter | xyz  | blah6
John  | xyz  | hello
John  | xyz  | world
John  | xyz  | blah

你有什么想法吗?我找到了另一条讨论这个问题的线索,但我无法将其映射到我的案例中。我知道结构并不完美,但我不允许更改表c的设计。

让我们来分析一下您的查询:

SELECT b.* FROM a
LEFT JOIN b ON b.word=a.word
WHERE a.id=1
LIMIT 2
-- This sub-query returns the following result:
+-------+------+
| name  | word |
+-------+------+
| Peter | xyz  |
| John  | xyz  |
+-------+------+
如果没有子查询的完整语法,则主要语法如下所示:

SELECT c.name, first_join.word, c.product FROM first_join
LEFT JOIN c ON c.name=first_join.name;
+-------+------+-------+---------+
| name  | word | name  | product |
+-------+------+-------+---------+
| Peter | xyz  | Peter | blah    |
| Peter | xyz  | Peter | blah2   |
| Peter | xyz  | Peter | blah3   |
| Peter | xyz  | Peter | blah4   |
| Peter | xyz  | Peter | blah5   |
| Peter | xyz  | Peter | blah6   |
| John  | xyz  | John  | hello   |
| John  | xyz  | John  | world   |
| John  | xyz  | John  | blah    |
+-------+------+-------+---------+
让我们用
*
替换
c.name,first\u join.word,c.product
。然后您将得到如下结果:

SELECT c.name, first_join.word, c.product FROM first_join
LEFT JOIN c ON c.name=first_join.name;
+-------+------+-------+---------+
| name  | word | name  | product |
+-------+------+-------+---------+
| Peter | xyz  | Peter | blah    |
| Peter | xyz  | Peter | blah2   |
| Peter | xyz  | Peter | blah3   |
| Peter | xyz  | Peter | blah4   |
| Peter | xyz  | Peter | blah5   |
| Peter | xyz  | Peter | blah6   |
| John  | xyz  | John  | hello   |
| John  | xyz  | John  | world   |
| John  | xyz  | John  | blah    |
+-------+------+-------+---------+
现在,你要问自己这是否是你想要的?如果不是,你需要确保你理解你在这里试图做什么的逻辑。例如,为什么
first\u join
子查询返回两行,而
LEFT join
子查询返回表c中的所有行? 答案是因为你在c.name=first\u join.name上的
。它匹配
表c
中出现的所有peter和john,而不考虑您在子查询中施加的限制。如果您对外部查询设置限制,它将无法正常工作

tl;博士 如果您使用的是MySQL 8.0,您可以尝试以下查询:

SELECT name,word,product FROM
(SELECT 
    b.name, b.word,c.product,
    ROW_NUMBER() OVER (PARTITION BY c.name ORDER BY c.name DESC) AS wRow
FROM 
a JOIN
b ON a.word=b.word JOIN
c ON c.name=b.name
WHERE a.id=1) r
WHERE wRow IN (1,2)
ORDER BY name DESC;

另外两个例子:

-- First: by using INNER JOIN and UNION (as suggested in the comment).
SELECT b.name,b.word,r.product FROM a JOIN b ON a.word=b.word JOIN
((SELECT * FROM c WHERE c.name='peter' LIMIT 2) UNION
(SELECT * FROM c WHERE c.name='john' LIMIT 2)) r
ON b.name=r.name 
WHERE a.id=1;

-- Second: by using LEFT JOIN.    
SELECT b.Name,b.Word,IF(p.product IS NULL,j.product,p.product) AS 'Product' 
FROM a JOIN b ON a.word=b.word LEFT JOIN
(SELECT * FROM c WHERE NAME='peter' LIMIT 2) p ON b.name=p.name LEFT JOIN
(SELECT * FROM c WHERE NAME='john' LIMIT 2) j ON b.name=j.name
WHERE a.id=1 AND b.name IN (p.name,j.name);
更新:正常。不漂亮,但是这个查询可以工作。我已经在MySQL 5.7上进行了测试


但是,如果您有一个至少具有自动递增值的列,则会容易得多。

您可以使用存储过程,选择不同的名称,循环遍历结果,并为每个名称选择两行

以下存储过程为您提供了所需的结果(这在MySQL 5.6服务器上运行,但在SQLFIDLE中不起作用):


请也包括有问题的代码。如果我有相同的任务,我会像你一样使用子查询。无论出于何种目的,子查询都与联接相同,只是您可以限制子查询中记录的数量。如果您的查询有效,并且您对此没有意见,请不要再进一步查看。即使您要重写它,最终也会获得相同的性能。您可以尝试使用
union
operator谢谢。第一个查询在您的小提琴中工作,但不幸的是我的MySQL版本是5.7,所以第一个查询对我不起作用。我会检查我是否可以毫无问题地更新MySQL。我认为其他两个例子不合适,因为其中有硬编码字符串。我想的更多的是一种广义形式,e。G使用a.id=2及以上。是的,我认为它不是动态的,所以在现实环境中不容易使用。我还有一个建议。我会更新我的答案,看看你是否可以用它来代替。我不知道有这么多不同的方法来达到目标,我从来没有使用过wRow和FIND_in_SET。不过,我会接受HelgeB的回答,因为我认为这是一个非常好的解决方案。尽管如此,还是非常感谢不同的方法!是的。由你决定接受哪个答案。。前提是这是适合您的环境的最佳实践。我正在学习自己,这是我可以提高的方法之一,所以,老实说,这是我第一次自己使用FIND_in_SET。至于wRow,它只是一个别名,所以我想你是指这个函数
ROW_NUMBER()(按c.name划分顺序按c.name描述)
。。这也是我第一次使用它非常感谢你。这正如预期的那样有效。我不知道策划这样的行为是如此的努力。我想可以用另一个子查询或其他一行程序来完成。我从未使用过过程,非常感谢代码中的注释。