Приплюсовать в подзапросе к LIMIT

Рейтинг: 0Ответов: 3Опубликовано: 27.04.2023

Нужно дописать запрос так, чтобы если в таблице action_log присутствуют записи type = 1, то к LIMIT 20 прибавилось бы это количество. То есть, к примеру, если в данной запросе будет 20 строк и из них будет 5 записей type = 1, то LIMIT 20 + 5.

            SELECT history.*,
            users.id
            FROM ( SELECT * FROM `action_log` WHERE action_id > 10 ORDER BY `action_id` DESC LIMIT 20) AS history
            LEFT JOIN users ON history.user_id = users.id
            ORDER BY `action_id` ASC

Ответы

▲ 0

Подсчитать количество type = 1 из action_log, добавить 20 и записать его в переменную:

SET @typeCount = (
  SELECT COUNT(*)
  FROM action_log
  WHERE
    type = 1
);
SET @typeCount = 20 + IFNULL(@typeCount, 0);

А затем применить его в prepared statements:

PREPARE stmt FROM '
  SELECT 
    history.*,
    users.id
  FROM
    (
      SELECT *
      FROM action_log
      WHERE
        action_id > 10
      ORDER BY
        action_id DESC
      LIMIT ?
    ) AS history
    LEFT JOIN users ON history.user_id = users.id
  ORDER BY
    action_id DESC
';
EXECUTE stmt USING @typeCount;
DEALLOCATE PREPARE stmt;

UPDATE:

При подсчете количества можно настроить условие выборки по своему. Подсчет количества с type = 1 будет примерно таким:

SET @typeCount = (
  SELECT COUNT(*) AS rowcount
  FROM 
    (
      SELECT *
      FROM
        action_log
      LIMIT 20
    ) h
  WHERE
    h.type = 1
);
SET @typeCount = 20 + IFNULL(@typeCount, 0);

Ну или можно попробовать выполнить одним select-ом. Но тяжело это воспроизвести без структуры таблиц и данных - примерно так:

SELECT
  history.*,
  users.id
FROM
  (
    SELECT *
    FROM
      (
        SELECT
          (@row_number := @row_number + 1) rownum,
          t.rowcount,
          a.*
        FROM
          action_log a
          CROSS JOIN (
            SELECT COUNT(*) rowcount
            FROM 
              (
                SELECT *
                FROM
                  action_log
                LIMIT 20
              ) h
            WHERE
              h.type = 1
          ) t
          CROSS JOIN (
            SELECT @row_number := 0
          ) n
        WHERE
          action_id > 10
      ) l
    WHERE
      l.rownum <= l.rowcount + 20
  ) history
  LEFT JOIN users ON history.user_id = users.id
ORDER BY
  action_id DESC
▲ 0

Вот как-то так:

WITH
cte1 AS (
    SELECT *, users.id
    FROM `action_log` 
    LEFT JOIN users ON history.user_id = users.id
    WHERE action_id > 10 
      AND type <> 1
    ORDER BY `action_id` DESC LIMIT 20
    ),
cte2 AS (
    SELECT *, users.id
    FROM `action_log` 
    LEFT JOIN users ON history.user_id = users.id
    WHERE action_id > 10 
      AND type = 1
      AND action_id > (
        SELECT MIN(action_id)
        FROM cte1
        )
    )
(TABLE cte1)
UNION ALL
(TABLE cte2)
ORDER BY `action_id` ASC

cte1 выбирает 20 записей с type <> 1.

cte2 выбирает все записи с type = 1, находящиеся между записями, выбранными в cte1.

Внешний запрос объединяет эти выборки и выполняет финальную сортировку.

▲ 0

Не совсем точно, но можно так

SELECT history.*, users.id,users.username
FROM 
  ( select * 
    from( 
        SELECT * 
        FROM action_log
        WHERE action_id > 10 and action_type<>1
        ORDER BY action_id DESC LIMIT 20
        )t1

  union all
    select * from(
       select * 
       from action_log
       where action_id > 10 and action_type=1
       ORDER BY action_id DESC LIMIT 20
     )t2
  ) AS history
LEFT JOIN users ON history.user_id = users.id
ORDER BY action_id ASC

Пример здесь