SQL:具有复杂子查询的查询

时间:2011-07-03 18:06:59

标签: mysql sql subquery

我的游戏数据库中有以下表格:

rankedUp (image_id, user_id, created_at)
globalRank (image_id, rank )
matchups (user_id, image_id1, image_id2)

globalRank表中的所有image_ids都被赋予一个等级,该等级是从0到1的浮点数

假设我有当前登录用户的“user_id”值,我正在寻找一个返回一对图像ID(imageid1,imageid2)的查询,以便:

  1. imageid1的排名低于imageid2,但也是排名低于imageid2
  2. 的排名
  3. matchups表没有(userid,imageid1,imageid2)或(userid,imageid2,imageid1)
  4. 排名表没有(userid,imageid1)或者如果有,则createdat列早于X小时
  5. 到目前为止,我对要求1的要求是:

    SELECT lowerImages.image_id AS lower_image, higherImages.image_id AS higher_image
    FROM global_rank AS lowerImages, global_rank AS higherImages
    WHERE lowerImages.rank < higherImages.rank
    AND lowerImages.image_id = ( 
        SELECT image_id
        FROM (
            SELECT image_id
            FROM global_rank
            WHERE rank < higherImages.rank
            ORDER BY rank DESC 
            LIMIT 1 , 1
            ) AS tmp 
        ) 
    

    但它不起作用,因为我无法在子查询中引用higherImages.rank。

    有人知道如何在一个查询中满足所有这些要求吗?

    感谢您的帮助

    编辑:

    我现在有了这个查询,但我不知道效率,我需要测试它的正确性:

    SELECT lowerImages.image_id AS lower_image,
           max(higherImages.image_id) AS higher_image
    FROM global_rank AS lowerImages, global_rank AS higherImages
    WHERE  lowerImages.rank  <  higherImages.rank
    
    AND 1  NOT IN (select 1 from ranked_up where
        lowerImages.image_id = ranked_up.image_id
        AND ranked_up.user_id = $user_id
        AND ranked_up.created_at > DATE_SUB(NOW(), INTERVAL 1 DAY))
    
    AND 1 NOT IN (
        SELECT 1 from matchups where user_id = $userId 
                AND lower_image_id = lowerImages.image_id 
                AND higher_image_id = higherImages.image_id
                UNION
                SELECT 1 from matchups where user_id = $user_id
                AND lower_image_id = higherImages.image_id 
                AND higher_image_id = lowerImages.image_id
    )
    GROUP BY 1
    

    我正在使用的“not in”语句都已编入索引,因此它们应该快速运行。我的效率问题是global_rank表的分组和选择


    此问题是对Pretty Complex SQL Query的修订,不应再回答。

2 个答案:

答案 0 :(得分:1)

select
(
select image_id, rank from
rankedup inner join globalRank 
on rankedup.image_id = globalRank .image_id
where user_id = XXX 
limit 1, 1
) as highest,
(
select image_id, rank from
rankedup inner join globalRank 
on rankedup.image_id = globalRank .image_id
where user_id = XXX 
limit 2, 1
) as secondhighest

我通常使用SQL Server,但我认为这是mysql的翻译:)

答案 1 :(得分:1)

这应该可以解决问题:

SELECT lowerImages.*, higherImages.* 
FROM globalrank AS lowerImages, globalrank AS higherImages
WHERE lowerImages.rank < higherImages.rank
AND lowerImages.image_id = ( 
    SELECT image_id
    FROM (
        SELECT image_id
        FROM globalrank
        WHERE rank < higherImages.rank
        ORDER BY rank DESC 
        LIMIT 1,1
        ) AS tmp 
    ) 
AND NOT EXISTS (
    SELECT * FROM matchups 
    WHERE user_id = $user_id 
    AND ((image_id1 = lowerImages.image_id AND image_id2 = higherImages.image_id)
        OR (image_id2 = lowerImages.image_id AND image_id1 = higherImages.image_id))
)
AND higherImages.image_id NOT IN (
    SELECT image_id FROM rankedup 
    WHERE created_at < DATE_ADD(NOW(), INTERVAL 1 DAY)
    AND USER_ID <> $user_id
)
ORDER BY higherImages.rank

我假设比赛的PK和排名包括这些表中的所有列。这将允许后两个子查询使用PK索引。您可能需要globalrank.rank上的有序索引来加速第一个子查询。