当唯一 id 与查询的其他 7 个不匹配时,如何从 MySQL 查询中绘制一行

Posted

技术标签:

【中文标题】当唯一 id 与查询的其他 7 个不匹配时,如何从 MySQL 查询中绘制一行【英文标题】:How to draw one row from a MySQL query when the unique id doesn't match 7 others queried 【发布时间】:2020-04-25 09:36:28 【问题描述】:

我有一个新闻故事数据库,我有一个阅读量最大的部分。我的新闻以 8 个故事的块显示。前 7 个来自下面的 mysql 查询,显示过去 7 天 (DESC) 中阅读最多的前 7 个故事。这正如我所期望的那样工作,并显示前 7 个阅读最多的新闻故事。


$query = "
SELECT * 
    FROM news 
 WHERE STR_TO_DATE(day, '%d %M %Y') >= DATE_SUB(curdate(), INTERVAL 1 WEEK) 
 ORDER 
      BY mostRead DESC 
 LIMIT 7
";

$results = mysqli_query($dbc, $query)or die('Error querying database');

while ($rows = mysqli_fetch_array($results))

echo news stories



我正在努力研究如何形成下一个 MySQL 查询。我需要显示的第 8 个新闻故事必须是我的数据库中第一个不在阅读最多的前 7 个新闻故事中的故事。这是为了避免 8 层楼的重复。

例如,如果一个新的新闻报道有大量的点击量,我不希望它出现在前 7 名,然后也作为第 8 条新闻报道,因为它仍然是最新条目。

【问题讨论】:

请注意,函数不能使用索引,所以如果你能想办法去除它们,性能将得到不可估量的提升 @StevenLafferty 。 . .我很困惑。为什么不直接将“7”改为“8”来获取 8 条头条新闻? 【参考方案1】:

如果您运行的是 MySQL 8.0,则可以使用 row_number()rank()

order by
    case when rank() over(order by mostRead desc) <= 7,
        then mostRead 
        else 0
    end desc,
    str_to_date(day, '%d %M %Y') desc
limit 8

如果当前行排在前 7 位,则第一个排序条件中的条件表达式返回 mostRead,否则返回 0(因此所有其他行都是并列的)。然后,第二个排序条件使用日期。剩下要做的就是将结果集限制为 8 行。

【讨论】:

我的 MySQL 非常有限,我使用 phpMyAdmin,由我的服务提供商提供,从我可以在数据库服务器下收集到的版本:服务器版本:5.7.23-23 - Percona Server (GPL ),第 23 版,修订版 500fcf5。甚至不接近 MySQL 8.0!这是否意味着上述建议的功能将无法运行?【参考方案2】:

您可以使用UNION 向结果集中添加额外的行。这些查询将适用于较旧的 MySQL 版本(在 5.7.26 上测试)。

实现这一点的方法很少,您可以从表中添加前 8 行,让 UNION 过滤重复项,然后通过在查询末尾添加 LIMIT 8 只选择一条记录:

(SELECT *
   FROM news
   WHERE STR_TO_DATE(day, '%d %M %Y') >= DATE_SUB(curdate(), INTERVAL 1 WEEK)
   ORDER BY mostRead DESC
   LIMIT 7)
UNION
  (SELECT *
   FROM news
   ORDER BY str_to_date(day, '%d %M %Y') DESC
   LIMIT 8)
LIMIT 8

或者您可以自己过滤更适合高级用例的行。

  (SELECT *
   FROM news
   WHERE STR_TO_DATE(DAY, '%d %M %Y') >= DATE_SUB(curdate(), INTERVAL 1 WEEK)
   ORDER BY mostRead DESC
   LIMIT 7)
UNION
  (SELECT *
   FROM news
   WHERE id NOT IN
       (SELECT id
        FROM
          (SELECT *
           FROM news
           WHERE STR_TO_DATE(day, '%d %M %Y') >= DATE_SUB(curdate(), INTERVAL 1 WEEK)
           ORDER BY mostRead DESC
           LIMIT 7) temp)
   ORDER BY str_to_date(day, '%d %M %Y') DESC
   LIMIT 1)

我们添加了temp 表,因为旧版本的 MySQL 不支持 LIMIT & IN/ALL/ANY/SOME 子查询。

【讨论】:

谢谢大家的回答。正如我所说,我不是专家,但我会解决这些问题,现在让你知道我的进展情况。非常感谢cmets,谢谢【参考方案3】:

我需要显示的第 8 个新闻故事必须是我的数据库中第一个不在阅读次数最多的前 7 个新闻故事中的故事。

这是你想要的吗?

SELECT n.* 
FROM news n
WHERE STR_TO_DATE(day, '%d %M %Y') >= DATE_SUB(curdate(), INTERVAL 1 WEEK) 
ORDER BY mostRead DESC 
LIMIT 8
------^ this is the change

如果您的应用程序中已经有 7 并且需要获得不同的,那么您需要处理 id:

SELECT n.* 
FROM news n
WHERE STR_TO_DATE(day, '%d %M %Y') >= DATE_SUB(curdate(), INTERVAL 1 WEEK) AND
     n.id NOT IN ($id1, $id2, $id3, $id4, $id5, $id6, $id7)
ORDER BY mostRead DESC 
LIMIT 1

【讨论】:

以上是关于当唯一 id 与查询的其他 7 个不匹配时,如何从 MySQL 查询中绘制一行的主要内容,如果未能解决你的问题,请参考以下文章

使用 Mongoose 从 JSON 对象数组中查询具有匹配 ID 的集合

Mongoose find - 从查询中返回所有匹配的至少一个

如何从唯一 id 基础 varchar 数据类型中获取值

在 R 中,当 ID 不唯一时,如何从每个 ID 的数据框中获取倒数第二行? [复制]

当firebase查询与数据库中的任何内容都不匹配时如何调用函数

当join匹配多行时,如何从一个表中选择行?