我遇到类似于以下示例的MySQL问题。
示例表:
父母
PassportID – ParentNAME
098765432 – Kate
012345678 – John
111222333 – Mary
的子
PassportID – ChildNAME – ParentID
211222333 – Peter – 111222333
222333444 – Gabriel – 012345678
222222222 – Lara – 111222333
233333333 – Angela – 012345678
244444444 – Philip – 012345678
255555555 – Michael – 111222333
277777777 – Betty – 098765432
266666666 – Eleanor – 098765432
299999999 – Amanda – 111222333
288888888 – Robert – 111222333
我知道如何使用原始ID加入和排序这些表:
HTTP:!sqlfiddle.com /#9 / 98b5a / 1/0
由于某种原因,SQLfiddle开始失败,所以我在其他很酷的MySQL测试器中重现了这个例子: http://rextester.com/EYIX74197
但我希望显示简单的增长数字,而不是显示原始ID。所以,问题是:
如何从这两个表中进行选择,并通过以下方式获取所有这些人的列表,其中包含几个自动编号列,这些列显示人员的基于1的年龄等级:
示例结果:
ParentAgeRANK - ParentNAME – ChildBornRANK – ChildNAME
1 – John – 1 – Gabriel
1 – John – 2 – Angela
1 – John – 3 – Philip
2 – Kate – 1 – Eleanor
2 – Kate – 2 – Betty
3 – Mary – 1 – Peter
3 – Mary – 2 – Lara
3 – Mary – 3 – Michael
3 – Mary – 4 – Robert
3 – Mary – 5 – Amanda
我想我需要使用几个mysql变量@ParentAgeRank和@ChildBornRank,将它们的原始值设置为0,然后为每一行加1,但仅当父ID更改时(在第一种情况下)或子ID更改(在第二个中)。但是,当父ID更改时,@ ChildBornRank必须重置为0。 我会知道如何使用PHP脚本来执行此操作,该脚本可以评估PassportID并使用PHP变量增加Rank。
但在这种情况下,我被迫使用纯MySQL语句获得排名列表。
这个想法甚至可能吗?如何在另一个变量改变其值时重置一个变量?
非常感谢你的建议
编辑:
虽然我的例子只有10行,这是打算从两个表中运行,每个表有大约10万条记录。
@Parfait提供的第一个解决方案确实适用于几行;但是当我在现实世界中尝试它时,我的服务器就会挂起。
@Parfait的第二个解决方案确实返回了一个完整的磁盘"错误消息,所以我猜这是与此页面中的第一条评论相关的内容(连接和分组语句太多):https://dev.mysql.com/doc/refman/5.7/en/full-disk.html
答案 0 :(得分:1)
考虑相关计数子查询:
SELECT
(SELECT Count(*) FROM Parents sub
WHERE sub.PassportID <= p.PassportID) AS ParentRANK,
p.PassportID As ParentID, p.ParentNAME,
(SELECT Count(*) FROM Children sub
WHERE sub.PassportID <= c.PassportID
AND sub.ParentID = c.ParentID) AS ChildRANK,
c.PassPortID As ChildID, c.ChildNAME
FROM Parents p
INNER JOIN Children c
ON p.PassportID = c.ParentID
在聚合查询中使用JOIN
表和COUNT(DISTINCT ...))
替代排名:
SELECT
Count(DISTINCT subP.PassportID) AS ParentRANK,
p.PassportID As ParentID, p.ParentNAME,
Count(DISTINCT subC.PassportID) AS ChildRANK,
C.PassPortID As ChildID, c.ChildNAME
FROM Parents p
INNER JOIN Children c
ON p.PassportID = c.ParentID
LEFT JOIN Parents subP
ON subP.PassportID <= p.PassportID
LEFT JOIN Children subC
ON subC.PassportID <= c.PassportID
AND subC.ParentID = c.ParentID
GROUP BY p.PassportID, p.ParentName, c.PassportID, c.ChildName
ORDER BY 1,4
答案 1 :(得分:1)
SELECT CASE WHEN @prev = x.parent_id THEN @i:=@i ELSE @i:=@i+1 END parentrank
, x.parentname
, CASE WHEN @prev = x.parent_id THEN @j:=@j+1 ELSE @j:=1 END childrank
, x.childname
, @prev:=parent_id
FROM ( SELECT p.passportid parent_id
, p.parentname
, c.passportid child_id
, c.childname
FROM parents p
JOIN children c
ON c.parentid = p.passportid
) x
JOIN ( SELECT @prev:=null,@i:=0,@j:=0) vars
ORDER
BY x.parent_id
, x.child_id;
+------------+------------+-----------+-----------+------------------+
| parentrank | parentname | childrank | childname | @prev:=parent_id |
+------------+------------+-----------+-----------+------------------+
| 1 | John | 1 | Gabriel | 12345678 |
| 1 | John | 2 | Angela | 12345678 |
| 1 | John | 3 | Philip | 12345678 |
| 2 | Kate | 1 | Eleanor | 98765432 |
| 2 | Kate | 2 | Betty | 98765432 |
| 3 | Mary | 1 | Peter | 111222333 |
| 3 | Mary | 2 | Lara | 111222333 |
| 3 | Mary | 3 | Michael | 111222333 |
| 3 | Mary | 4 | Robert | 111222333 |
| 3 | Mary | 5 | Amanda | 111222333 |
+------------+------------+-----------+-----------+------------------+
答案 2 :(得分:0)
这与@Strawberry上面提供的方法基本相同:https://stackoverflow.com/a/44578041/710788
我只是把我的版本放在这里,以便更好地理解我提到的差异:
SET @prank=0, @crank=1, @curp=0, @curc=0;
SELECT
if(o.Passportid<>@curp, @prank:=@prank+1, @prank) as 'ParentRANK',
o.ParentName,
if(o.Passportid<>@curp, @crank:=1, @crank:=@crank+1) as 'ChildRANK',
o.ChildName,
if(o.Passportid<>@curp, @curp:=o.Passportid, @curp) as 'current_P'
FROM (
SELECT p.Passportid,p.ParentNAME, c.PassportID as childID,c.ChildNAME,c.ParentID
FROM parents AS p INNER JOIN children as c on p.PassportID=c.ParentID
ORDER BY p.PASSPORTID,c.PassportID
) AS o;
与553003名父母和1106983名儿童进行速度比较:
上面的解决方案
影响0行,找到1,106,983行。 3次查询的持续时间:7.020秒
@Strawberry解决方案
影响0行,找到1,106,983行。 1个查询的持续时间:6.489秒
注意:这些行比我原先说的需要处理的行多得多。我只是将它们添加到更好的测试速度差异中。