Как нарисовать одну строку из запроса MySQL, если уникальный идентификатор не соответствует 7 другим запросам - PullRequest
0 голосов
/ 25 апреля 2020

У меня есть база новостей, и у меня есть наиболее читаемый раздел. Мои новости отображаются в блоке из 8 историй. Первые 7 взяты из следующего запроса MySQL ниже и отображают 7 самых читаемых историй за последние 7 дней (DES C). Это работает, как я ожидал, и отображает 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 запрос. Восьмая новость, которую мне нужно отобразить, должна быть первой в моей базе данных, которая также не входит в топ-7 самых читаемых новостей. Это сделано для того, чтобы избежать дублирования в блоке из 8 статей.

Например, если в новых новостях есть ru sh просмотров, я не хочу, чтобы они появлялись в топ-7, а затем также как восьмая новость, потому что она все еще самая новая статья.

Ответы [ 3 ]

0 голосов
/ 25 апреля 2020

Вы можете использовать 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.

0 голосов
/ 25 апреля 2020

Восьмая новость, которую мне нужно отобразить, должна быть первой в моей базе данных, которая также не входит в топ-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 в вашем приложении и вам нужно получить другой, то вам нужно иметь дело с идентификаторами:

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
0 голосов
/ 25 апреля 2020

Если вы используете 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

Условное выражение в критериях первого рода возвращает mostRead, если это текущая строка занимает место в топ-7, иначе он дает 0 (так что все остальные строки связаны). Затем второй критерий сортировки использует дату. Осталось только ограничить набор результатов 8 строками.

...