SQL 查询到 mysql(子查询不识别外部 table)
SQL query to mysql (Subquery does not recognize outer table)
我知道 mysql 无法识别子查询中的外部 table,但遗憾的是我不知道如何解决这个问题。
首先是table结构,我有三个tables(m到n):
表 1:
舞蹈
TID | Name_Of_The_Dance
12 | Heute Tanz ich
表二:
舞者
TAID | Name_Of_Dancer
1 | Alex Womitsch
2 | Julian Berger
表 3(引用 table):
dance2dancer
TID | TAID
12 | 213
12 | 345
我要实现什么(输出):
TID | AllDancerWhoDance
12 | 213---,345---,0---,0---,0---,0---,0---,0---,0---,0---
每个输出都应该有舞蹈TID和所有跳这个舞的舞者。但是AllDancerWhoDance应该填“0---”,当我们有少于10个dancer时。当这个舞蹈中有超过 10 个舞者时,查询应将字符串减少到最多 10 个舞者。
更多需要理解的例子:
一个有 4 个舞者的舞蹈应该填满 6 个零:
9 | 213---,345---,111---,459---,0---,0---,0---,0---,0---,0---
我们是否有超过 10 名舞者的舞蹈查询应将其减少到 10:
9 | 213---,345---,111---,459---,333---,444---,445---,222---,192---,490--- (NO more zeros or dancer TAIDs)
这是我的查询:
select dancer.tid,
IF(count(dancer.taid) <= 10,
CONCAT_WS("",GROUP_CONCAT(dancer.taid,"&&&"), REPEAT(";0",10-count(dancer.taid)))
, (SELECT GROUP_CONCAT(a.taid,"&&&") from (SELECT ttt.taid from dance2dancer ttt inner join dance taenz on ttt.tid = taenz.tid where ttt.tid = dance.tid LIMIT 10) as a)
) AS "AllDancerWhoDance"
from dance inner join dance2dancer tt on dance.tid = tt.tid inner join dancer on tt.taid = dancer.taid group by dance.tid
我认为它会起作用,但问题是子查询不查看外部 table 并且 "where" 子句不起作用:
其中 ttt.tid = dance.tid
现在我的问题是:
如何在 mysql 中实现此 sql 查询?
谢谢
//更新
因为很多人询问前端代码以及为什么我需要这个查询:我们有一个 22 年的软件,需要这种格式的数据。它是由一家不复存在的公司编写的,我们没有该程序的任何源代码。我们已经将数据库和网站更改为这个新的数据模型 (m:n),但是旧程序仍然需要旧格式的数据。因此我需要这个奇怪的查询。
是的,我们也在开发一个新程序。
要让 10 名舞者参加给定的舞蹈,请执行以下操作:
select D.Name_Of_Dancer
from dancer DR, dance2dancer DD
where DD.taid = DR.taid
groupby DD.tid
Limit 10
您还可以添加 Desc 或 ASC 来对舞者列表的列表进行排序并提取前 10 位舞者。
但是要在一个列表中获得至少 10 个舞者,即使它不存在。 mysql 不可能。我的意思是告诉我前端的代码你是如何处理的,我们能做的就是计算结果的数量。如果结果是 4,我们可以简单地使用一个循环来创建 6 个其他条目以获得总共 10 个舞者。但我不建议从 mysql 端处理它们。这是一个不好的做法。
错误的原因是您无法从派生的 table(您的 from (...) as a
)内部访问外部列。为此,您必须编写类似 (...) as a where a.tid = dancer.tid
的内容,因此您将 where
放在派生的 table 之外;但是您显然必须以某种方式重写 a
以将 tid
作为列。
在你的情况下,修复你的代码会更复杂,所以我给你写了一个(更简单的)新代码:
select tid,
CONCAT_WS("",
(SELECT GROUP_CONCAT(d2d2.taid,"---")
from dance2dancer d2d2
where d2d2.tid = d2d.tid
group by d2d2.tid limit 10),
REPEAT(",0---",10-count(distinct d2d.taid))
) as `AllDancerWhoDance`
from dance2dancer d2d
group by d2d.tid
还有一个警告:这种查询(在列中使用 group_concat 或 concat)仅在最后一步用于格式化要显示的数据。如果您打算在另一个查询中使用它,例如类似 select * from dancer where INSTR('213---,345---,111---', taid) > 0
的东西,请不要,只需重写即可。
更新 不使用 limit 10
:
尽管 limit 10
应该与 group_concat 一起使用(它对我有用),如果它对你不起作用,你当然可以只连接所有内容然后取前 10 个条目之后的连接字符串。它实际上会简化查询,因为您不再需要子查询(首先只有 limit
),但可能会生成一个大的临时字符串(在 substring_index
之前)如果你和很多舞者一起跳舞。
select tid,
SUBSTRING_INDEX(CONCAT_WS("",
GROUP_CONCAT(d2d.taid,"---"),
REPEAT(",0---",10-count(distinct d2d.taid)),
','
), ',',10) as `AllDancerWhoDance`
from dance2dancer d2d
group by d2d.tid;
或者预先计算行号,每个 tid 只取前 10 行:
select d2d.tid, CONCAT_WS("",
GROUP_CONCAT(d2d.taid,"---"),
REPEAT(",0---",10-d2d.cnt)
) as `AllDancerWhoDance`
from
(select tid, taid,
(select count(*)
from dance2dancer d2d4
where d2d4.tid = d2d3.tid
and d2d4.taid <= d2d3.taid
) as rownum,
(select count(*)
from dance2dancer d2d4
where d2d4.tid = d2d3.tid
) as cnt
from dance2dancer d2d3
) as d2d
where d2d.rownum <= 10
group by d2d.tid;
我知道 mysql 无法识别子查询中的外部 table,但遗憾的是我不知道如何解决这个问题。
首先是table结构,我有三个tables(m到n):
表 1: 舞蹈
TID | Name_Of_The_Dance
12 | Heute Tanz ich
表二: 舞者
TAID | Name_Of_Dancer
1 | Alex Womitsch
2 | Julian Berger
表 3(引用 table): dance2dancer
TID | TAID
12 | 213
12 | 345
我要实现什么(输出):
TID | AllDancerWhoDance
12 | 213---,345---,0---,0---,0---,0---,0---,0---,0---,0---
每个输出都应该有舞蹈TID和所有跳这个舞的舞者。但是AllDancerWhoDance应该填“0---”,当我们有少于10个dancer时。当这个舞蹈中有超过 10 个舞者时,查询应将字符串减少到最多 10 个舞者。
更多需要理解的例子: 一个有 4 个舞者的舞蹈应该填满 6 个零:
9 | 213---,345---,111---,459---,0---,0---,0---,0---,0---,0---
我们是否有超过 10 名舞者的舞蹈查询应将其减少到 10:
9 | 213---,345---,111---,459---,333---,444---,445---,222---,192---,490--- (NO more zeros or dancer TAIDs)
这是我的查询:
select dancer.tid,
IF(count(dancer.taid) <= 10,
CONCAT_WS("",GROUP_CONCAT(dancer.taid,"&&&"), REPEAT(";0",10-count(dancer.taid)))
, (SELECT GROUP_CONCAT(a.taid,"&&&") from (SELECT ttt.taid from dance2dancer ttt inner join dance taenz on ttt.tid = taenz.tid where ttt.tid = dance.tid LIMIT 10) as a)
) AS "AllDancerWhoDance"
from dance inner join dance2dancer tt on dance.tid = tt.tid inner join dancer on tt.taid = dancer.taid group by dance.tid
我认为它会起作用,但问题是子查询不查看外部 table 并且 "where" 子句不起作用:
其中 ttt.tid = dance.tid
现在我的问题是:
如何在 mysql 中实现此 sql 查询?
谢谢
//更新
因为很多人询问前端代码以及为什么我需要这个查询:我们有一个 22 年的软件,需要这种格式的数据。它是由一家不复存在的公司编写的,我们没有该程序的任何源代码。我们已经将数据库和网站更改为这个新的数据模型 (m:n),但是旧程序仍然需要旧格式的数据。因此我需要这个奇怪的查询。
是的,我们也在开发一个新程序。
要让 10 名舞者参加给定的舞蹈,请执行以下操作:
select D.Name_Of_Dancer
from dancer DR, dance2dancer DD
where DD.taid = DR.taid
groupby DD.tid
Limit 10
您还可以添加 Desc 或 ASC 来对舞者列表的列表进行排序并提取前 10 位舞者。
但是要在一个列表中获得至少 10 个舞者,即使它不存在。 mysql 不可能。我的意思是告诉我前端的代码你是如何处理的,我们能做的就是计算结果的数量。如果结果是 4,我们可以简单地使用一个循环来创建 6 个其他条目以获得总共 10 个舞者。但我不建议从 mysql 端处理它们。这是一个不好的做法。
错误的原因是您无法从派生的 table(您的 from (...) as a
)内部访问外部列。为此,您必须编写类似 (...) as a where a.tid = dancer.tid
的内容,因此您将 where
放在派生的 table 之外;但是您显然必须以某种方式重写 a
以将 tid
作为列。
在你的情况下,修复你的代码会更复杂,所以我给你写了一个(更简单的)新代码:
select tid,
CONCAT_WS("",
(SELECT GROUP_CONCAT(d2d2.taid,"---")
from dance2dancer d2d2
where d2d2.tid = d2d.tid
group by d2d2.tid limit 10),
REPEAT(",0---",10-count(distinct d2d.taid))
) as `AllDancerWhoDance`
from dance2dancer d2d
group by d2d.tid
还有一个警告:这种查询(在列中使用 group_concat 或 concat)仅在最后一步用于格式化要显示的数据。如果您打算在另一个查询中使用它,例如类似 select * from dancer where INSTR('213---,345---,111---', taid) > 0
的东西,请不要,只需重写即可。
更新 不使用 limit 10
:
尽管 limit 10
应该与 group_concat 一起使用(它对我有用),如果它对你不起作用,你当然可以只连接所有内容然后取前 10 个条目之后的连接字符串。它实际上会简化查询,因为您不再需要子查询(首先只有 limit
),但可能会生成一个大的临时字符串(在 substring_index
之前)如果你和很多舞者一起跳舞。
select tid,
SUBSTRING_INDEX(CONCAT_WS("",
GROUP_CONCAT(d2d.taid,"---"),
REPEAT(",0---",10-count(distinct d2d.taid)),
','
), ',',10) as `AllDancerWhoDance`
from dance2dancer d2d
group by d2d.tid;
或者预先计算行号,每个 tid 只取前 10 行:
select d2d.tid, CONCAT_WS("",
GROUP_CONCAT(d2d.taid,"---"),
REPEAT(",0---",10-d2d.cnt)
) as `AllDancerWhoDance`
from
(select tid, taid,
(select count(*)
from dance2dancer d2d4
where d2d4.tid = d2d3.tid
and d2d4.taid <= d2d3.taid
) as rownum,
(select count(*)
from dance2dancer d2d4
where d2d4.tid = d2d3.tid
) as cnt
from dance2dancer d2d3
) as d2d
where d2d.rownum <= 10
group by d2d.tid;