Сколько клиентов перешло с продукта A на продукт B? - PullRequest
0 голосов
/ 05 апреля 2019

У меня есть таблица «ежедневных изменений», в которой записывается, когда клиент «повышает» или «понижает» свой уровень членства. Допустим, в таблице поле 1 - это идентификатор клиента, поле 2 - тип членства, а поле 3 - дата изменения. Клиенты 123 и ABC имеют по две строки в таблице. Значения в поле 1 (ID) одинаковы, но значения в поле 2 (TYPE) и 3 (DATE) различны. Я хотел бы написать SQL-запрос, чтобы сообщить мне, сколько клиентов «повысило» статус членства 1 до типа членства 2, сколько клиентов «понизило» статус членства 2 до типа членства 1 в любой заданный период времени.

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

SELECT *
FROM member_detail_daily_changes_new
WHERE customer IN (
    SELECT customer
    FROM member_detail_daily_changes_new
    GROUP BY customer
    HAVING COUNT(distinct member_type_cd) > 1)

Я хотел бы увидеть отчет о завершении, который говорит мне:

для 2018 финансового года, X, XXX клиенты перешли от типа участника 1 к типу участника 2 и X, XXX клиенты перешли от типа участника 2 к типу участника 1

Ответы [ 3 ]

1 голос
/ 05 апреля 2019

Похоже, пришло время использовать аналитическую функцию LEAD (), чтобы посмотреть в будущее для данного клиента member_Type; сравните его с текущей записью, а затем оцените, будет ли это повышение или понижение, а затем суммируйте результаты. DEMO

CTE AS (SELECT case when lead(Member_Type_Code) over (partition by Customer order by date asc) > member_Type_Code then 1 else 0 end as Upgrade
             , case when lead(Member_Type_Code) over (partition by Customer order by date asc) < member_Type_Code then 1 else 0 end as DownGrade
FROM member_detail_daily_changes_new
WHERE Date between '20190101' and '20190201')

SELECT sum(Upgrade) upgrades, sum(downgrade) downgrades
FROM  CTE

Давать нам: используя мои данные образца

+----+----------+------------+
|    | upgrades | downgrades |
+----+----------+------------+
|  1 |        3 |          2 |
+----+----------+------------+

Я не уверен, что SQL Express на Rex Tester просто не поддерживает sum () для самого аналитика, поэтому мне пришлось добавить CTE или это правило также и в версиях, отличных от SQL Express.

Некоторые другие заметки:

  • Я позволил системе неявно приводить даты в предложении where
  • Я предполагаю, что сам member_Type_Code сообщает мне, является ли это обновлением или понижением, которое в долгосрочной перспективе, вероятно, не подходит. Скажем, мы добавляем тип членства 3, и он идет между 1 и 2 ... и что теперь ... Так что, может быть, нам нужно десятичное число вне Member_Type_Code, чтобы мы могли обрабатывать будущие членства, а также, если это повышение / понижение или боковая версия .. .
  • Я предположил, что все улучшения / понижения подсчитываются, и пользователь может быть подсчитан несколько раз, если членство изменилось так часто за желаемый период времени.
  • Я предполагаю, что обновление / понижение не может произойти в тот же день / время. В противном случае сортировка по свинцу может работать неправильно. (но если это поле с отметкой времени, у нас не должно быть проблем)

Так как это работает?

Мы используем общее табличное выражение (CTE) для генерации желаемых оценок понижения / обновления для каждого клиента. Это можно сделать и в производной таблице, но я считаю, что CTE легче читать; и затем мы подведем итоги.

Lead(Member_Type_Code) over (partition by customer order by date asc) делает следующее

Он организует данные по клиенту, а затем сортирует их по дате в порядке возрастания.

Таким образом, мы получаем все те же записи клиентов в последующих строках, упорядоченных по дате. После этого поле (поле) начинается с записи 1 и просматривает запись 2 для того же клиента и возвращает Member_Type_Code записи 2 в записи 1. Затем мы можем сравнить эти коды типов и определить, произошло ли обновление или понижение. Затем мы можем суммировать результаты сравнения и предоставить желаемые итоги.

А теперь у нас длинное объяснение очень маленького запроса: P

0 голосов
/ 05 апреля 2019

С условным агрегированием после самостоятельного присоединения к таблице:

select 
  2018 fiscal, 
  sum(case when m.member_type_cd > t.member_type_cd then 1 else 0 end) upgrades, 
  sum(case when m.member_type_cd < t.member_type_cd then 1 else 0 end) downgrades 
from member_detail_daily_changes_new m inner join member_detail_daily_changes_new t
on 
  t.customer = m.customer 
  and 
  t.changedate = (
    select max(changedate) from member_detail_daily_changes_new
    where customer = m.customer and changedate < m.changedate
  )
where year(m.changedate) = 2018 

Это будет работать, даже если существует более 2 типов уровня членства.

0 голосов
/ 05 апреля 2019

Вы хотите использовать lag() для этого, но вы должны быть осторожны с фильтрацией даты.Итак, я думаю, вы хотите:

SELECT prev_membership_type, membership_type,
       COUNT(*) as num_changes,
       COUNT(DISTINCT member) as num_members
FROM (SELECT mddc.*,
             LAG(mddc.membership_type) OVER (PARTITION BY mddc.customer_id ORDER BY mddc.date) as prev_membership_type
      FROM member_detail_daily_changes_new mddc
     ) mddc
WHERE prev_membership_type <> membership_type AND
      date >= '2018-01-01' AND
      date < '2019-01-01'
GROUP BY membership_type, prev_membership_type;

Примечания:

  • Фильтрация на date должна произойти после вычисления lag().
  • При этом учитывается, что члены могут иметь определенный тип в 2017 году, а затем перейти на новый тип в 2018.
  • Фильтрация даты совместима с индексами.
  • Двазначения рассчитаны.Одним из них является общее количество изменений.Другой подсчитывает каждого члена только один раз для каждого типа изменений.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...