PostgreSQL:尝试添加过滤器时,子查询的列过多

时间:2019-06-28 19:50:16

标签: sql postgresql join

SELECT users.id as user_id, boats.id as boat_id
FROM users
CROSS JOIN boats
WHERE users.id NOT IN 
   (SELECT users.id as user_id, boats.id as boat_id FROM users 
    LEFT JOIN rentals ON (users.id=rentals.user_id)
    LEFT JOIN boats on (boats.id=rentals.boat_id)
    WHERE users.id=rentals.user_id)
ORDER BY users.id

我该如何拆分这些JOIN,以便不再出现“子查询列过多”错误?

3 个答案:

答案 0 :(得分:1)

您的子查询必须具有比您要比较的外部值准确的列数。

例如,您可以使用列:

SELECT users.id as user_id, boats.id as boat_id
FROM users
CROSS JOIN boats
WHERE users.id NOT IN 
   (SELECT users.id FROM users -- fixed here
    LEFT JOIN rentals ON (users.id=rentals.user_id)
    LEFT JOIN boats on (boats.id=rentals.boat_id)
    WHERE users.id=rentals.user_id)
ORDER BY users.id

或使用具有两列的元组:

SELECT users.id as user_id, boats.id as boat_id
FROM users
CROSS JOIN boats
WHERE (users.id, boats.id) NOT IN -- fixed here
   (SELECT users.id as user_id, boats.id as boat_id FROM users 
    LEFT JOIN rentals ON (users.id=rentals.user_id)
    LEFT JOIN boats on (boats.id=rentals.boat_id)
    WHERE users.id=rentals.user_id)
ORDER BY users.id

答案 1 :(得分:1)

您的查询有点难以理解。我认为这是您真正想要的逻辑:

SELECT u.id as user_id, b.id as boat_id
FROM users u CROSS JOIN
     boats b
WHERE not exists (SELECT 1
                  FROM rentals r
                  WHERE r.user_id = u.id AND
                        r.boat_id = b.id
                 );

这将返回没有租金的用户/船组合。

答案 2 :(得分:0)

您只需要在子查询中删除boat.id:

SELECT users.id as user_id, boats.id as boat_id
FROM users
CROSS JOIN boats
WHERE users.id NOT IN 
   (SELECT users.id as user_id
    FROM users 
    LEFT JOIN rentals ON (users.id=rentals.user_id)
    LEFT JOIN boats on (boats.id=rentals.boat_id)
    WHERE users.id=rentals.user_id)
ORDER BY users.id

但是,没有理由将LEFT JOIN添加到子查询中的小船上,因为它没有被使用。另外,WHERE子句无论如何都会否定LEFT JOIN来出租,因此可以简化为:

SELECT users.id as user_id, boats.id as boat_id
FROM users
CROSS JOIN boats
WHERE not exists (
    SELECT 1
    FROM rentals 
    WHERE rentals.user_id = users.id
);

我也有点怀疑您是否想在这里进行CROSS JOIN,但是我没有足够的信息来确定您想要什么。