Как ВЫБРАТЬ новейшие четыре объекта на категорию?

Попробуйте это:

ORDER BY 1, 2

ИЛИ

ORDER BY rsc.RadioServiceCodeId, rsc.RadioServiceCode + ' - ' + rsc.RadioService
31
задан gung - Reinstate Monica 30 May 2014 в 03:53
поделиться

6 ответов

Это проблема с наибольшим числом n на группу, и это очень распространенный вопрос SQL.

Вот как я решаю ее с помощью внешних соединений:

SELECT i1.*
FROM item i1
LEFT OUTER JOIN item i2
  ON (i1.category_id = i2.category_id AND i1.item_id < i2.item_id)
GROUP BY i1.item_id
HAVING COUNT(*) < 4
ORDER BY category_id, date_listed;

Я предполагаю, что первичным ключом таблицы item является item_id , и это монотонно увеличивающийся псевдоключ. То есть большее значение в item_id соответствует более новой строке в элементе .

Вот как это работает: для каждого элемента есть некоторое количество других элементов, более новых . Например, есть три элемента новее, чем четвертый самый новый элемент. Новее самого нового товара нет. Поэтому мы хотим сравнить каждый элемент ( i1 ) с набором элементов ( i2 ), которые являются более новыми и имеют ту же категорию, что и i1 . Если количество этих новых элементов меньше четырех, i1 является одним из тех, которые мы включаем. В противном случае не включайте его.

Прелесть этого решения в том, что оно работает независимо от того, сколько у вас категорий, и продолжает работать, если вы измените категории. Он также работает, даже если количество элементов в некоторых категориях меньше четырех.


Другое решение, которое работает, но полагается на функцию пользовательских переменных MySQL:

SELECT *
FROM (
    SELECT i.*, @r := IF(@g = category_id, @r+1, 1) AS rownum, @g := category_id
    FROM (@g:=null, @r:=0) AS _init
    CROSS JOIN item i
    ORDER BY i.category_id, i.date_listed
) AS t
WHERE t.rownum <= 3;

MySQL 8.0.3 представил поддержку стандартных оконных функций SQL. Теперь мы можем решить эту проблему так же, как и другие СУБД:

WITH numbered_item AS (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY item_id) AS rownum
  FROM item
)
SELECT * FROM numbered_item WHERE rownum <= 4;
80
ответ дан 27 November 2019 в 21:39
поделиться

не очень красиво, но:

SELECT image 
FROM item 
WHERE date_listed IN (SELECT date_listed 
                      FROM item 
                      ORDER BY date_listed DESC LIMIT 4)
0
ответ дан 27 November 2019 в 21:39
поделиться

В зависимости Насколько постоянны ваши категории, следующий простейший маршрут

SELECT C.CategoryName, R.Image, R.date_listed
FROM
(
    SELECT CategoryId, Image, date_listed
    FROM 
    (
      SELECT CategoryId, Image, date_listed
      FROM item
      WHERE Category = 'Pet Supplies'
      ORDER BY date_listed DESC LIMIT 4
    ) T

    UNION ALL

    SELECT CategoryId, Image, date_listed
    FROM
    (        
      SELECT CategoryId, Image, date_listed
      FROM item
      WHERE Category = 'Pet Food'
      ORDER BY date_listed DESC LIMIT 4
    ) T
) RecentItemImages R
INNER JOIN Categories C ON C.CategoryId = R.CategoryId
ORDER BY C.CategoryName, R.Image, R.date_listed
0
ответ дан 27 November 2019 в 21:39
поделиться

Это решение является адаптацией из другого решения SO , спасибо RageZ за то, что нашел этот связанный / похожий вопрос.

ПРИМЕЧАНИЕ

Это решение кажется удовлетворительным для варианта использования Джастина. В зависимости от вашего варианта использования вы можете проверить решения Билла Карвина или Дэвида Андреса в этой публикации. Мой голос за решение Билла! Посмотрите, почему, поскольку я помещаю оба запроса рядом друг с другом; -)

Преимущество моего решения в том, что оно возвращает одну запись для каждого category_id (информация из таблицы элементов "свернута"). Основным недостатком моего решения является его отсутствие читабельности и растущая сложность по мере увеличения количества желаемых строк (скажем, 6 строк на категорию, а не 6). Также это может быть немного медленнее по мере роста количества строк в таблице элементов. (Тем не менее, все решения будут работать лучше с меньшим количеством подходящих строк в таблице элементов, и поэтому рекомендуется периодически удалять или перемещать старые элементы и / или вводить флаг, чтобы помочь SQL отфильтровать строки на раннем этапе)

Первая попытка (не сработало !!!) ...

Проблема с этим подходом заключалась в том, что подзапрос [справедливо, но плохо для нас] создавал очень много строк на основе декартовых произведений, определенных самосоединениями ...

SELECT id, CategoryName(?), tblFourImages.*
FROM category
JOIN (
    SELECT i1.category_id, i1.image as Image1, i2.image AS Image2, i3.image AS Image3, i4.image AS Image4
    FROM item AS i1
    LEFT JOIN item AS i2 ON i1.category_id = i2.category_id AND i1.date_listed > i2.date_listed
    LEFT JOIN item AS i3 ON i2.category_id = i3.category_id AND i2.date_listed > i3.date_listed
    LEFT JOIN item AS i4 ON i3.category_id = i4.category_id AND i3.date_listed > i4.date_listed
) AS tblFourImages ON tblFourImages.category_id = category.id
--WHERE  here_some_addtional l criteria if needed
ORDER BY id ASC;

Вторая попытка. (работает нормально!)

Для подзапроса добавлено предложение WHERE, в соответствии с которым указанная дата должна быть последней, второй, третьей и т. д. для i1, i2, i3 и т. д. соответственно (а также с учетом пустых случаев когда для данного идентификатора категории меньше 4 элементов). Также были добавлены несвязанные пункты фильтра для предотвращения отображения записей, которые «проданы», или записей, не имеющих изображения (дополнительные требования)

. Эта логика предполагает, что нет повторяющихся значений даты в списке (для заданного category_id). В противном случае в таких случаях образуются повторяющиеся строки. Фактически, указанная дата используется для монотонно увеличивающегося первичного ключа, как определено / требуется в решении Билла.

SELECT id, CategoryName, tblFourImages.*
FROM category
JOIN (
    SELECT i1.category_id, i1.image as Image1, i2.image AS Image2, i3.image AS Image3, i4.image AS Image4, i4.date_listed
    FROM item AS i1
    LEFT JOIN item AS i2 ON i1.category_id = i2.category_id AND i1.date_listed > i2.date_listed AND i2.sold = FALSE AND i2.image IS NOT NULL
          AND i1.sold = FALSE AND i1.image IS NOT NULL
    LEFT JOIN item AS i3 ON i2.category_id = i3.category_id AND i2.date_listed > i3.date_listed AND i3.sold = FALSE AND i3.image IS NOT NULL
    LEFT JOIN item AS i4 ON i3.category_id = i4.category_id AND i3.date_listed > i4.date_listed AND i4.sold = FALSE AND i4.image IS NOT NULL
    WHERE NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i1.date_listed)
      AND (i2.image IS NULL OR (NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i2.date_listed AND date_listed <> i1.date_listed)))
      AND (i3.image IS NULL OR (NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i3.date_listed AND date_listed <> i1.date_listed AND date_listed <> i2.date_listed)))
      AND (i4.image IS NULL OR (NOT EXISTS (SELECT * FROM item WHERE category_id = i1.category_id AND date_listed > i4.date_listed AND date_listed <> i1.date_listed AND date_listed <> i2.date_listed AND date_listed <> i3.date_listed)))
) AS tblFourImages ON tblFourImages.category_id = category.id
--WHERE  --
ORDER BY id ASC;

Теперь ... сравните следующее, где я представляю ключ item_id и использую решение Билла для предоставления списка из них на «внешний» запрос. Вы можете понять, почему подход Билла лучше ...

SELECT id, CategoryName, image, date_listed, item_id
FROM item I
LEFT OUTER JOIN category C ON C.id = I.category_id
WHERE I.item_id IN 
(
SELECT i1.item_id
FROM item i1
LEFT OUTER JOIN item i2
  ON (i1.category_id = i2.category_id AND i1.item_id < i2.item_id
      AND i1.sold = 'N' AND i2.sold = 'N'
      AND i1.image <> '' AND i2.image <> ''
      )
GROUP BY i1.item_id
HAVING COUNT(*) < 4
)
ORDER BY category_id, item_id DESC
5
ответ дан 27 November 2019 в 21:39
поделиться

хорошо, после поиска в Google быстрый ответ будет ли это невозможно, по крайней мере, на mysql

этот поток для ссылка

, возможно, вам следует кэшировать результат этого запроса, если вы боитесь, что сервер упадет, и хотите, чтобы код работал лучше

-1
ответ дан 27 November 2019 в 21:39
поделиться

приведенный ниже код показывает способ сделать это в цикле. это определенно требует большого редактирования, но я надеюсь, что это поможет.

        declare @RowId int
 declare @CategoryId int
        declare @CategoryName varchar(MAX)

 create table PART (RowId int, CategoryId int, CategoryName varchar)
 create table  NEWESTFOUR(RowId int, CategoryId int, CategoryName varchar, Image image)
        select RowId = ROW_NUMBER(),CategoryId,CategoryName into PART from [Category Table]


        set @PartId = 0
 set @CategoryId = 0 
 while @Part_Id <= --count
 begin
   set @PartId = @PartId + 1
          SELECT @CategoryId = category_id, @CategoryName = category_name from PART where PartId = @Part_Id
          SELECT RowId = @PartId, image,CategoryId = @category_id, CategoryName = @category_name   FROM item into NEWESTFOUR where category_id = :category_id 
ORDER BY date_listed DESC LIMIT 4

 end
 select * from NEWESTFOUR
 drop table NEWESTFOUR
        drop table PART
0
ответ дан 27 November 2019 в 21:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: