mySQL 查询返回根据'LIMIT' 使用而改变 |数据库

Posted

技术标签:

【中文标题】mySQL 查询返回根据\'LIMIT\' 使用而改变 |数据库【英文标题】:mySQL query return changing based on 'LIMIT' useage | DatabasemySQL 查询返回根据'LIMIT' 使用而改变 |数据库 【发布时间】:2021-11-01 00:56:45 【问题描述】:

我的网站有一个使用 phpmysql 数据库来存储和提取数据的消息传递系统。

我有一个 _CONVERSATION 表和一个 _MESSAGE 表。前者存储有关与对话关联的收件箱数据的信息。后者比前者弱,并存储包括消息发送日期在内的单个消息数据。当用户加载消息页面时,我希望按用户最近的对话顺序加载收件箱。为此,我创建了一个查询,该查询从 _MESSAGE 表中选择不同的 convoID,该表按 messageID 排序(在按消息日期排序时也可以正常工作,也会出现同样的问题)。

当用户加载消息页面时,我使用所讨论的查询来提取用户参与的最后 10 个对话。我对此使用了限制,并使用 PDO while-fetch 将数据加载到数组中。

这按预期发生,没有问题。

有限制的 PDO SQL:

'SELECT distinct convoID from _MESSAGE where receiverID = :userID or senderID = :userID order by messageID desc limit '.(int)$ext[0].';'
/// userID = 40 (same every time for testing)
/// $ext[0] = 10
/// RESULT: 171, 8, 194, 193, 187, 178, 173, 157, 12, 151 (EXPECTED)

当用户在收件箱中向下滚动时,网站会加载前十个之外的更多对话。我没有限制地运行相同的查询。我运行 while-fetch 直到找到最后一个加载的用户,然后我将接下来的五个项目加载到返回的数组中。一旦加载了五个新项目,我就会跳出 PHP while 循环。

这是我注意到一些奇怪行为的地方。我没有得到预期的结果,并且正在重复一些 convoID。我设置了一个echo $row['convoID'].', '; 来获取完整的查询。

无限制的 PDO SQL:

'SELECT distinct convoID from _MESSAGE where receiverID = :userID or senderID = :userID order by messageID desc;'
/// userID = 40 (same every time for testing)
/// Set up to echo five items after last convoID is found
/// RESULT: 194, 193, 187, 178, 173, 171, 157, 151, 136, 13, 3, 6, 8, 10 (UNEXPECTED)

来自 mySQL 工作台的 SQL:

select distinct convoID from _MESSAGE where receiverID = 40 or senderID = 40 order by messageID desc; 
# RETURNS: 171,8,194,193,187,178,173,157,12,151,etc (EXPECTED)

这是我想要并期望从这个查询中得到的回报。

这不是 PDO 第一次按照我的预期启动。我想知道是什么导致了这种奇怪的行为,以及如何在不使用限制的情况下从 PDO 查询中获得预期结果。

我在查询中写错了吗?如果是这样,为什么在 mySQL 工作台中运行相同的精确查询时没有问题?

这里是完整的php函数供参考:

function get_convos($conn, $userID, $ext = ['10','']) 
  /// EXT: ['How many to pull','pull all convos after']
  $_rtn = [];
  $l = 0;
  $sql = null;
  if ($ext[1] == '') 
    $sql = $conn->prepare('SELECT distinct convoID from _MESSAGE where receiverID = :userID or senderID = :userID order by messageID desc limit '.(int)$ext[0].';');
    $sql->execute(['userID' => $userID]);
   else 
    $sql = $conn->prepare('SELECT distinct convoID from _MESSAGE where receiverID = :userID or senderID = :userID order by messageID desc;');
    $sql->execute(['userID' => $userID]);
  
  $ready = false;
  while ($row = $sql->fetch(PDO::FETCH_ASSOC)) 
    echo $row['convoID'].', ';
    $sql2 = $conn->prepare('SELECT * from _CONVERSATION where convoID = :convoID;');
    $sql2->execute(['convoID' => $row['convoID']]);
    if ($row2 = $sql2->fetch(PDO::FETCH_ASSOC)) 
      if ($ext[1] == '') 
        $_rtn[$l] = $row2;
        $l++;
       else 
        if ($ready) 
          if ($l < (int)$ext[0]) 
            $_rtn[$l] = $row2;
            $l++;
           else 
            break;
          
        
        if ($row2['convoID'] == $ext[1]) 
          $ready = true;
        
      
    
  
  return $_rtn;

感谢你们提供的任何帮助。

【问题讨论】:

【参考方案1】:

问题是ORDER BY messageID 被处理之后它从每个convoID 组中选择一个不同的消息,并且它选择哪一行是不可预测的。 MySQL 根据是否存在LIMIT 子句对查询的处理方式不同,因此您会得到不同的结果。

您需要使用确定性方法在每个对话中选择要排序的消息,例如按最新消息排序。见SQL select only rows with max value on a column

【讨论】:

谢谢!这就是最终的工作:SELECT convoID from _MESSAGE where receiverID = :userID or senderID = :userID group by convoID order by max(date) desc;

以上是关于mySQL 查询返回根据'LIMIT' 使用而改变 |数据库的主要内容,如果未能解决你的问题,请参考以下文章

MySQL--limit使用注意

MySQL 简单查询

MYSQL查询前30条数据

MySql 中 count 与 limit 混用的后果

MySQL的limit 优化

MyBatis怎样实现MySQL动态分页