#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 Я не уверен. Оконные функции выполняются после группирования, поэтому это должно работать. Попробовать это.