Перекрестное соединение в Улье

#sql #datetime #join #hive #window-functions

#sql #дата и время #Присоединиться #hive #окно-функции

Вопрос:

Я пытаюсь создать новый столбец time_period во время выполнения приведенного ниже запроса. Если разница в дате между данной транзакцией и самой последней транзакцией в справочной таблице составляет менее 7 дней, то пометьте ее как recent транзакцию, в противном случае пометьте как old транзакцию.

Однако приведенный ниже запрос генерирует ошибку в подзапросе, связанном с перекрестным соединением. Ошибка «Не удается распознать ввод рядом с ‘select’ ‘(«max’

 SELECT
    c.*
    FROM(
        SELECT
         a.acct_nb,
         a.txn_date,
         a.txn_amt,
         (CASE WHEN datediff(b.most_recent_txn,a.txn_date)<7 THEN 'recent' ELSE 'old' END) AS time_period
         FROM db.t1 a
         CROSS JOIN(
              SELECT max(txn_date) AS most_recent_txn --ERROR OCCURS HERE
              FROM db.t1 b)
        )c
        WHERE c.time_period='new';
  

Что может быть причиной этой ошибки?

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

1. Возможно, вам не хватает запятой после a.txn_amt

2. Спасибо, просто опечатка при написании сокращенной версии запроса для SO. Исправил сообщение.

3. Похоже, ошибка не соответствует вашему запросу — круглые скобки находятся в другом положении

Ответ №1:

Для этого вам не нужен join . Вы можете просто использовать оконные функции:

 SELECT 
    acct_nb,
    txn_date, 
    txn_amt,
    CASE WHEN DATEDIFF(MAX(txn_date) OVER(), txn_date) < 7 
        THEN 'recent' 
        ELSE 'old' 
    END AS time_period
FROM db.t1
  

Если вам нужно фильтровать только по недавним транзакциям, то вы можете использовать подзапрос:

 SELECT *
FROM (
    SELECT acct_nb, txn_date, txn_amt, MAX(txn_date) OVER() max_txn_date
    FROM db.t1
) t
WHERE DATEDIFF(MAX(txn_date) OVER(), txn_date) < 7 
  

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

1. @Caerus . . . Оконные функции почти всегда являются лучшим решением, если существует решение, использующее их.

2. @GMB спасибо — очень элегантное решение. Чтобы убедиться, что я правильно понимаю, когда вы не указываете поле после инструкции OVER(), отображается ли окно по умолчанию для всей таблицы?

3. @Caerus: да, именно.

Ответ №2:

Псевдоним b должен быть применен к перекрестно соединяемому подзапросу, а не к таблице db.t1 внутри подзапроса:

 SELECT c.*
FROM (
  SELECT a.acct_nb, a.txn_date, a.txn_amt,
         CASE WHEN datediff(b.most_recent_txn, a.txn_date) < 7 THEN 'recent' ELSE 'old' END AS time_period
  FROM db.t1 a
  CROSS JOIN (
    SELECT max(txn_date) AS most_recent_txn
    FROM db.t1 
  ) b
) c
WHERE c.time_period='new';  
  

Кроме того, в вашем CASE выражении нет возвращаемой ветви 'new' , поэтому последнее WHERE предложение отфильтрует все строки.