Как установить максимальное количество строк в день на дату в SQL?

#sql #date #amazon-athena

Вопрос:

Даны данные, которые выглядят следующим образом, где дата указана в строковом формате YYYYMMDD :

пункт вьетнамский стоимость уникальный идентификатор дата продажи
фрукты трай кей 10 abc123 20211001
фрукты трай кей 8 фу99 20211001
фрукты трай кей 9 фу99 20211001
веге rau 3 1239 рублей 20211001
веге rau 3 1239 рублей 20211001
фрукты трай кей 12 abc123 20211002
фрукты трай кей 14 abc123 20211002
фрукты трай кей 8 abc123 20211002
фрукты трай кей 5 фу99 20211002
веге rau 8 1239 рублей 20211002
веге rau 1 1239 рублей 20211002
веге rau 12 ud9213 20211002
веге rau 19 r11759 20211002
фрукты трай кей 6 фу99 20211003
фрукты трай кей 2 abc123 20211003
фрукты трай кей 12 abc123 20211003
веге rau 1 ud97863 20211003
веге rau 9 r112359 20211003
фрукты трай кей 6 фу99 20211004
фрукты трай кей 2 abc123 20211004
фрукты трай кей 12 abc123 20211004
веге rau 9 r112359 20211004

Цель состоит в том, чтобы отобрать все строки в течение определенного периода времени, например с 2020-10-02 по 2020-10-03, и извлекать максимум 3 строки в день, например, с помощью этого запроса:

 SELECT * FROM mytable
WHERE sales_date BETWEEN '20211002' AND '20211003'
ORDER BY RAND () LIMIT 6
 

ожидаемый результат для приведенной выше таблицы таков:

пункт вьетнамский стоимость уникальный идентификатор дата продажи
фрукты трай кей 8 abc123 20211002
фрукты трай кей 5 фу99 20211002
веге rau 8 1239 рублей 20211002
fruits trai cay 12 abc123 20211003
веге rau 1 ud97863 20211003
веге rau 9 r112359 20211003

Но есть вероятность, что все 6 ожидаемых строк относятся к одному дню:

пункт вьетнамский стоимость уникальный идентификатор дата продажи
фрукты трай кей 12 abc123 20211002
фрукты трай кей 14 abc123 20211002
фрукты трай кей 8 abc123 20211002
фрукты трай кей 5 фу99 20211002
веге rau 8 1239 рублей 20211002
веге rau 1 1239 рублей 20211002

Поэтому, чтобы гарантировать, что у меня будет максимум 3 строки в день, я выполняю несколько запросов в день, т. Е.

 SELECT * FROM mytable
WHERE sales_date='20211002'
ORDER BY RAND () LIMIT 3
 

и

 SELECT * FROM mytable
WHERE sales_date='20211003'
ORDER BY RAND () LIMIT 3
 

Есть ли способ обеспечить N строк максимального ограничения в день в одном запросе?

В противном случае есть ли способ объединить эти один запрос в день в «супер-запрос»? Если мы говорим о полном годе, это будет 365 запросов, по одному в день.

Комментарии:

1. Объедините их с select ... UNION ALL select ...

2. Обратите внимание, что в вашем примере 6 строк, охватывающих 2 дня, должно быть ровно 3 строки в день.

3. LIMIT N или TOP N всегда доставляет первые N строк случайным образом. Это стандартное поведение. Хитрость заключается в том, чтобы использовать функцию ROW_NUMBER для перечисления вашего результирующего набора сначала по дате, а затем выбрать только те строки, в которых число не превышает N. Немного излишне для выборки. docs.aws.amazon.com/redshift/latest/dg/r_WF_ROW_NUMBER.html

Ответ №1:

Поскольку 6 строк за 2 дня означают ровно 3 строки в день, давайте расширим его до недели.

В подзапросе используйте row_number для присвоения номера каждой строке для каждой даты. Затем выберите только те, у которых номер строки 3 или меньше.

 select *
from (
  select
    *,
    row_number() over (partition by sales_date order by rand()) as row
  from mytable
  where sales_date between '20211002' and '20211009'
)
where row <= 3
order by rand()
limit 6
 

Комментарии:

1. Спасибо! Это элегантное решение. Небольшое продолжение, если мне нужно будет объединить некоторые поля товара group by , все row_number() over (partition by max(sales_date) order by rand()) as row равно будет работать так, как ожидалось?

2. @alvas Я не уверен. Оконные функции выполняются после группирования, поэтому это должно работать. Попробовать это.