2012-03-27 3 views
2

У меня есть следующая таблица:SQL: получить последнюю (ООН) subscribeaction из таблицы

ID (int) 
EMAIL (varchar(50)) 
CAMPAIGNID (int) 
isSubscribe (bit) 
isActionByUser (bit) 

Эта таблица хранит все подписываться и отписываться действия по кампании для пользователя. Эти действия могут выполняться самим пользователем (isActionByUser = true) или администратором (isActionByUser = false).

Мне нужно получить последнее действие, чтобы определить, подписан ли пользователь или отменили подписку. Но имея в виду, что когда пользователь выполнил действие отписки от кампании, он будет иметь приоритет для других действий подписки администратором.

Я нашел nice solution, чтобы получить самую последнюю запись, сгруппированную по EMAIL и CAMPAIGNID. Но я не могу понять, как я включаю требование, чтобы isActionByUser = true, имеет абсолютный приоритет над записями с isActionByUser = false. Кроме того: когда административный стол выполняет действие отмены подписки, он будет иметь приоритет над записью с помощью (isSubscribe = true и isActionByUser).

Пример данных:

ID EMAIL CAMPAIGNID ISSUBSCRIBE ISACTIONBYUSER 
----------------------------------------------------------- 
1  [email protected] 1    1    0 
2  [email protected] 1    1    0 
3  [email protected] 1    1    0 
4  [email protected] 1    0    1 
5  [email protected] 1    1    0 
6  [email protected] 1    1    1 
7  [email protected] 1    0    0 

Ожидаемый результат будет:

ID EMAIL CAMPAIGNID ISSUBSCRIBE ISACTIONBYUSER 
----------------------------------------------------------- 
2  [email protected] 1    1    0 
4  [email protected] 1    0    1 
7  [email protected] 1    0    0 

С помощью следующего запроса

select cs1.* 
from 
    [TABLE] cs1 
    left join 
    [TABLE] cs2 
    on 
    cs1.EM_EMAIL = cs2.EM_EMAIL 
    and 
    cs1.EM_CAMPAIGNID = cs2.EM_CAMPAIGNID 
    and 
    cs1.id < cs2.id 
where cs2.id is null 

I»м, имеющий следующий результат:

ID EMAIL CAMPAIGNID ISSUBSCRIBE ISACTIONBYUSER 
----------------------------------------------------------- 
2  [email protected] 1    1    0 
5  [email protected] 1    1    0 
7  [email protected] 1    0    0 

Другой подход:

SELECT * 
FROM [TABLE] cs 
WHERE id in 
    (
    SELECT top 1 id 
    FROM [TABLE] ss 
    WHERE 
     cs.EMAIL = ss.EMAIL 
     and 
     cs.CAMPAIGNID = ss.CAMPAIGNID 
     and ISSUBSCRIBE = (
      select top 1 min(convert(int, ISSUBSCRIBE)) 
      FROM [TABLE] sss 
      WHERE 
       cs.EMAIL = sss.EMAIL 
       and 
       cs.CAMPAIGNID = sss.CAMPAIGNID 
      ) 
     and ISACTIONBYUSER= (
      select top 1 max(convert(int, ISACTIONBYUSER)) 
      FROM [TABLE] ssss 
      WHERE 
       cs.EMAIL = ssss.EMAIL 
       and 
       cs.CAMPAIGNID = ssss.CAMPAIGNID 
      ) 
     ) 

Это даст следующий результат:

ID EMAIL CAMPAIGNID ISSUBSCRIBE ISACTIONBYUSER 
----------------------------------------------------------- 
2  [email protected] 1    1    0 
4  [email protected] 1    0    1 
6  [email protected] 1    1    1 

Что тоже не правильно. И я боюсь, что с этим подходом будет большой rpoblem.

Итак, любые идеи, как я могу это решить?

+0

вам нужен идентификатор строки, где данные поступают от делать? –

+0

Кроме того, когда «когда административный офис выполняет действие отписки, он будет иметь приоритет над записью с (isSubscribe = true и isActionByUser)», вы имеете в виду, что если администратор не отменил подписку на пользователя, этот пользователь не может подписаться? –

+0

@TimLehner Мне нужны все данные. Планируйте, чтобы сделать вид, который я могу ссылаться в .NET Entity Framework. – JurgenStillaert

ответ

2

Попробуйте это: [Обновление для обработки отписки и подписавшиеся пользователи]

declare @test table (id int, email varchar(100), CAMPAIGNID int, ISSUBSCRIBE bit, ISACTIONBYUSER bit) 
INSERT INTO @test 
SELECT 1,'[email protected]',1,1,0 UNION 
SELECT 2,'[email protected]',1,1,0 UNION 
SELECT 3,'[email protected]',1,1,0 UNION 
SELECT 4,'[email protected]',1,0,1 UNION 
SELECT 5,'[email protected]',1,1,0 UNION 
SELECT 6,'[email protected]',1,1,1 UNION 
SELECT 7,'[email protected]',1,0,0 UNION 
select 8, '[email protected]', 1, 1, 1 UNION 
select 9, '[email protected]', 1, 0, 1 UNION 
select 10, '[email protected]', 1, 1, 1 


;WITh CTE AS 
(
    select s.*, 
    ROW_NUMBER() OVER (PARTITION BY email,campaignid 
    ORDER BY 
    case 
     when ISSUBSCRIBE = 0 AND ISACTIONBYUSER = 0 THEN 1 
     when ISSUBSCRIBE = 0 AND ISACTIONBYUSER = 1 THEN 1 
     when ISSUBSCRIBE = 1 AND ISACTIONBYUSER = 1 THEN 1 ELSE 2 END, ID DESC) Rn1 
    from @test s 
) 
SELECT * FROM CTE WHERE Rn1 = 1 
order by id 
+0

Это не учетная запись пользователя, а затем подписка на нее позже. –

+0

да, спасибо, что поймал это, я исправил свой запрос, и теперь он должен работать. –

+0

У меня уже есть id desc в их и мой запрос будет учитывать «отмену подписки, а затем подписку на нее позже» –

1

Это некоторый стандарт SQL, которые могли бы получить там, хотя это не самая красивая когда-либо:

Обновлено:

select s.* 
from Subscriptions s 
    join (
     -- Apply the user unsubscribe logic to get the proper ID 
     select case when b.ID is not null and a.ISACTIONBYUSER = 0 then b.ID else a.ID end as ID 
     from (
       -- Latest overall 
       select ID, EMAIL, CAMPAIGNID, 
        (select ISACTIONBYUSER from Subscriptions where ID = z.ID) as ISACTIONBYUSER 
       from (
        select max(ID) as ID, EMAIL, CAMPAIGNID 
        from Subscriptions a 
        group by EMAIL, CAMPAIGNID 
       ) as z 
      ) as a 
      left join (
       -- Latest user unsubscribe 
       select max(ID) as ID, EMAIL, CAMPAIGNID, 1 as ISACTIONBYUSER 
       from Subscriptions 
       where ISSUBSCRIBE = 0 
        and ISACTIONBYUSER = 1 
       group by EMAIL, CAMPAIGNID 
      ) as b on a.EMAIL = b.EMAIL 
       and a.CAMPAIGNID = b.CAMPAIGNID 
    ) as i on s.ID = i.ID 

Я обновил это на счет для этого случая:

insert into Subscriptions select 8, '[email protected]', 1, 1, 1 
insert into Subscriptions select 9, '[email protected]', 1, 0, 1 
insert into Subscriptions select 10, '[email protected]', 1, 1, 1 
+0

Thx, собирается проверить его. – JurgenStillaert

+0

Подождите ... не совсем правильно (даже если он правильно вернет ваши тестовые данные) –

+0

Должно быть хорошо, чтобы пойти сейчас с этим новым футляром –

3

Хорошо, попробуйте выполнить следующие запросы:

SELECT DISTINCT B.* 
FROM YourTable A 
OUTER APPLY (SELECT TOP 1 * 
      FROM YourTable 
      WHERE Email = A.Email AND CampaignId = A.CampaignId 
      ORDER BY CASE WHEN ISSUBSCRIBE = 0 THEN 1 ELSE 2 END, 
      CASE WHEN ISACTIONBYUSER = 1 THEN 1 ELSE 2 END, 
      ID DESC) B 
+0

+1, но эта часть 'CASE WHEN ISSUBSCRIBE = 0 THEN 1 ELSE 2 END', вероятно, должна быть' CASE WHEN ISSUBSCRIBE = 0 И ISACTIONBYUSER = 0 THEN 1 ELSE 2 END'. Этот 'ISSUBSCRIBE = 0' имеет приоритет только тогда, когда его выполнил администратор. Пользователь должен иметь возможность перевернуть его назад и вперед * до тех пор, пока администратор не сделает это. –

+0

@ConradFrix - Ну, я не совсем понял эту часть. На вопрос, который он говорит: «действие отмены подписки, оно будет иметь приоритет над записью с (isSubscribe = true и isActionByUser)», поэтому кажется, что отказ от подписки имеет фактический главный приоритет. Тот факт, что идентификатор 7 должен быть выбран одним из ID 6, кажется, подтверждает, что – Lamak

+0

Это, похоже, возвращает те же результаты первой неудачной попытки OP. –