SQL выбор максимального значения DENSE_RANK () и затем среднего - PullRequest
0 голосов
/ 17 января 2020

Я хотел бы изменить запрос ниже, чтобы он сохранял только самое высокое значение VISIT_flag, сгруппированное по CUSTOMER_ID, TRANS_TO_DATE, а затем усредняющее значение VISIT_flag по CUSTOMER_ID.

У меня проблемы с выяснением, как взять максимальное значение DENSE_RANK () и агрегировать, взяв среднее.

(
SELECT  
    CUSTOMER_ID,
    TRANS_TO_DATE ,
    DENSE_RANK() OVER( PARTITION BY CUSTOMER_ID, TRANS_TO_DATE ORDER BY HOUR - RN)  VISIT_flag
from  (
    SELECT  
        CUSTOMER_ID,
        TRANS_TO_DATE,
        TO_NUMBER(REGEXP_SUBSTR(HOUR,'\d+$')) HOUR,
        ROW_NUMBER() OVER( PARTITION BY CUSTOMER_ID, TRANS_TO_DATE ORDER BY TO_NUMBER(REGEXP_SUBSTR(HOUR,'\d+$'))  ) as RN
    FROM  mstr_clickstream                                
    GROUP BY CUSTOMER_ID, TRANS_TO_DATE, REGEXP_SUBSTR(HOUR,'\d+$')
)
ORDER BY CUSTOMER_ID, TRANS_TO_DATE

1 Ответ

0 голосов
/ 06 февраля 2020

Следуя вашему логику c, чтобы получить последний VISIT_flag, то есть последний "визит", произошедший в течение дня, вы должны заказать (в пределах DENSE_RANK) по убыванию. Хотя по убыванию решается проблема получения последнего посещения, вы не можете рассчитать среднее число посещений клиента, потому что VISIT_flag всегда будет равен 1. Поэтому, чтобы обойти эту проблему, вы должны объявить второй DENSE_RANK с тем же разделом и в порядке возрастания. для количественной оценки посещений за день и расчета вашего среднего. Таким образом, производный запрос

SELECT customer_id,AVG(quanitify) FROM (
SELECT  
customer_id,
trans_to_date ,
DENSE_RANK() OVER( PARTITION BY CUSTOMER_ID, TRANS_TO_DATE ORDER BY HOUR DESC, RN DESC, rownum)  VISIT_flag,
DENSE_RANK() OVER( PARTITION BY CUSTOMER_ID, TRANS_TO_DATE ORDER BY HOUR ASC, RN ASC, rownum)  quanitify FROM  (
SELECT  
    CUSTOMER_ID,
    TRANS_TO_DATE,
    TO_NUMBER(REGEXP_SUBSTR(HOUR,'\d+$')) HOUR,
    ROW_NUMBER() OVER( PARTITION BY CUSTOMER_ID, TRANS_TO_DATE ORDER BY TO_NUMBER(REGEXP_SUBSTR(HOUR,'\d+$'))  ) as RN
FROM  mstr_clickstream                                
GROUP BY CUSTOMER_ID, TRANS_TO_DATE, REGEXP_SUBSTR(HOUR,'\d+$') )) WHERE VISIT_flag = 1 GROUP BY customer_id

Теперь, если честно, вышеуказанный запрос может быть реализован более простым способом без использования DENSE_RANK. Приведенный выше запрос имеет смысл, только если вы удалите GROUP BY customer_id из внешнего запроса и вычисления AVG и хотите получить информацию о последнем посещении. В любом случае ниже вы можете найти более простой способ

SELECT CUSTOMER_ID,AVG(cnt) avg_visits FROM (
SELECT CUSTOMER_ID, TRANS_TO_DATE, count(*) cnt FROM (
    SELECT  
        CUSTOMER_ID,
        TRANS_TO_DATE,
        TO_NUMBER(REGEXP_SUBSTR(HOUR,'\d+$')) HOUR,
        ROW_NUMBER() OVER( PARTITION BY CUSTOMER_ID, TRANS_TO_DATE ORDER BY TO_NUMBER(REGEXP_SUBSTR(HOUR,'\d+$'))  ) as RN
    FROM  mstr_clickstream                                
    GROUP BY CUSTOMER_ID, TRANS_TO_DATE, REGEXP_SUBSTR(HOUR,'\d+$'))
GROUP BY CUSTOMER_ID, TRANS_TO_DATE) GROUP BY CUSTOMER_ID

PS. Я всегда включаю rownnum в порядке заказа по порядку, чтобы предотвратить исключительные случаи (которые всегда существуют в базе данных: D) наличия то же время транзакции. Это создаст две записи с одним и тем же density_rank и может вызвать проблему в приложении, которое использует данные запроса.

...