MySQL中的子查询返回了多行错误

3
我有一张表格,其中包含用户列表以及他们被允许访问的应用程序。该表的每一行都有一个用户ID和应用程序ID列,还有其他一些内容,只要存在这样的一行,每个用户就可以访问该应用程序。
我已经有了一些能够访问特定应用程序的用户,但我想知道哪些用户没有访问特定应用程序,并通过为每个这样的用户创建表中的行来给他们访问这个应用程序的权限。
它将类似于这样:
SET @v1 := (SELECT user_id from user_app_map WHERE app_id != <app_id_here> );

INSERT INTO user_app_map (user_id, app_id) VALUES (
    (SELECT @v1), <app_id_here> );

当我执行以上查询时,我遇到了“#1242 - 子查询返回多行”错误。
我在Google上搜索了这个错误,但是得到的结果有一些问题比这个更加复杂,所以我无法理解我想要的内容。
请告诉我如何进行这样的操作?
谢谢!
更新:我可以这样做:
INSERT INTO user_app_map (user_id, app_id)
  SELECT user_id, <app_id_here> from user_app_map WHERE app_id != <app_id_here>

但是这种方法在这种情况下行不通,因为一些用户可以访问多个应用程序,在表中有多行与他们的 id 相关。如果按照上述方式查询,我将再次给相同的人授予对同一应用程序的访问权限。
例如:用户 3 可以访问应用程序 3 和应用程序 4,这意味着 user_app_map 包含两行,其中 user_id 为 3,app_id 分别为 3 和 4。使用上述查询,我会从第二行获取 user_id,并再次创建另一行,这将是第一行不必要的重复。
2个回答

4
您只能将单个值分配给变量,因此如果此查询:
SELECT user_id from user_app_map WHERE app_id != <app_id_here>

如果返回的结果集包含多行(很可能除非您的表中只有两行),那么您将获得多行结果,从而导致异常。

为了解决这个问题,可以使用聚合函数来确保只有一行:

SET @v1 := (SELECT max(user_id) from user_app_map WHERE app_id != <app_id_here> );

如果你想插入所有值,可以尝试使用以下方法:

或者通过更紧密的where子句将行数缩小到一个。

INSERT INTO user_app_map (user_id, app_id) 
SELECT DISTINCT user_id, <app_id_here> from user_app_map WHERE app_id != <app_id_here>

是的,它会返回多行。我如何在不使用变量的情况下做到同样的事情? - Bharadwaj Srigiriraju
最后一个查询似乎有些问题...VALUES之后的括号应该在哪里结束? - Bharadwaj Srigiriraju
哈..这是CBroe在他的答案中写的相同查询。你能否请检查其他答案的评论。出于某种原因,我执行此查询时没有得到我想要的结果... - Bharadwaj Srigiriraju
@ForbiddenOverseer 是的(我应该意识到这一点)。只需添加 DISTINCT - 请参见底部编辑的查询。 - Bohemian

2
您正在使用子查询,而在此处只期望一个单一值 - 因此出现了这个错误。
但是可以很容易地使用 INSERT ... SELECT 语法来完成,例如:
INSERT INTO user_app_map (user_id, app_id)
  SELECT user_id, <app_id_here> from user_app_map WHERE app_id != <app_id_here>

该查询语句会动态地选择相关记录中的 user_id,而它返回的第二个“列”只是一个静态值。

哇...看起来这个解决了我的问题!! 我想过编写此查询,但每次插入完成时 SELECT 语句是否都有效呢?还是它只会一次选择所有记录,然后将它们插入表中?感谢您的帮助!等待回复。 :) - Bharadwaj Srigiriraju
请查看链接的手册页面,上面写着:"当同时从表中选择和插入数据时,MySQL会创建一个临时表来保存SELECT语句返回的行,然后再将这些行插入到目标表中。" - CBroe
由于某些原因,一些用户尚未获得应用程序的访问权限。WHERE app_id != <app_id_here> 是否包括其中app_id设置为NULL的项? - Bharadwaj Srigiriraju
好的,我认为这个查询存在一些问题。在我的user_app_map中,假设我有一条记录将用户3映射到应用程序3,另一条记录将用户3映射到应用程序4 - 在这个查询中仍然选择了用户3。我不想选择用户3。我该怎么做? - Bharadwaj Srigiriraju
1
如果按照上述方式进行查询,将会再次给予同一用户对同一应用的访问权限。因此,在用户ID和应用ID的组合上放置一个唯一索引,并在INSERT语句中使用IGNORE关键字,这样插入的行如果与现有行具有相同的user_id/app_id值,则会被忽略。 - CBroe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接