【问题标题】:Redshift PostgreSQL Distinct ON OperatorRedshift PostgreSQL Distinct ON 运算符
【发布时间】:2016-06-01 09:50:03
【问题描述】:

我有一个要解析的数据集以查看多点触控归因。该数据集由响应营销活动的潜在客户及其营销来源组成。

每个潜在客户都可以响应多个广告系列,我希望将他们的第一个营销来源和最后一个营销来源放在同一个表中。

我在想我可以创建两个表并从两者中使用一个 select 语句。 第一个表将尝试创建一个包含每个人的最新营销来源的表(使用电子邮件作为他们的唯一 ID)。

create table temp.multitouch1 as (
select distinct on (email) email, date, market_source as last_source 
from sf.campaignmember
where date >= '1/1/2016' ORDER BY DATE DESC);

然后我会创建一个包含重复数据删除电子邮件的表格,但这次是针对第一个来源。

create table temp.multitouch2 as (
select distinct on (email) email, date, market_source as first_source 
from sf.campaignmember
where date >= '1/1/2016' ORDER BY DATE ASC);

最后,我想简单地选择电子邮件并将第一个和最后一个市场来源加入到各自的列中。

select a.email, a.last_source, b.first_source, a.date 
from temp.multitouch1 a
left join temp.multitouch b on b.email = a.email

由于 distinct on 不适用于 redshift 的 postgresql 版本,我希望有人有想法以另一种方式解决此问题。

编辑 2/22:有关更多背景信息,我正在与他们回应的人员和活动打交道。每条记录都是一个“活动响应”,每个人都可以有多个来源的多个活动响应。我正在尝试制作一个选择语句,该语句将按人进行重复数据删除,然后分别为他们响应的第一个广告系列/营销来源和他们响应的最后一个广告系列/营销来源提供列。

编辑 2/24:理想的输出是一个有 4 列的表:email、last_source、first_source、date。

第一个和最后一个源列对于只有 1 个活动成员记录的人来说是相同的,而对于拥有超过 1 个活动成员记录的每个人来说都是不同的。

【问题讨论】:

标签: postgresql distinct amazon-redshift distinct-on postgresql-8.0


【解决方案1】:

您可以使用良好的旧左连接分组最大值。

SELECT DISTINCT c1.email, c1.date, c1.market_source
FROM sf.campaignmember c1
  LEFT JOIN sf.campaignmember c2 
    ON c1.email = c2.email AND c1.date > c2.date AND c1.id > c2.id
  LEFT JOIN sf.campaignmember c3
    ON c1.email = c3.email AND c1.date < c3.date AND c1.id > c3.id
WHERE c1.date >= '1/1/2016' AND c2.date >= '1/1/2016'
      AND (c2.email IS NULL OR c3.email IS NULL)

这假设您有一个唯一的 id 列,如果 (date, email) 是唯一的 id 则不需要。

【讨论】:

  • 我不想选择 c2.market_source 然后选择 c3.market_source 而不是只使用 c1.market_source 吗?问题还在于,有些人有多个 market_source 记录,因为他们响应了多个活动,而其他人则没有。
  • @Berra2k 您想从 c1 中选择没有比它们更旧的记录 (c2) 或没有更年轻的记录 (c3) 的记录。如果电子邮件只有一条记录,那么它仍然会被退回。请尝试看看。
【解决方案2】:

我相信你可以像这样在 case 表达式中使用 row_number():

SELECT
      email
    , MIN(first_source) AS first_source
    , MIN(date) first_date
    , MAX(last_source) AS last_source
    , MAX(date) AS last_date
FROM (
      SELECT
            email
          , date
          , CASE
                  WHEN ROW_NUMBER() OVER (PARTITION BY email ORDER BY date ASC) = 1 THEN market_source
                  ELSE NULL
            END AS first_source
          , CASE
                  WHEN ROW_NUMBER() OVER (PARTITION BY email ORDER BY date DESC) = 1 THEN market_source
                  ELSE NULL
            END AS last_source
      FROM sf.campaignmember
      WHERE date >= '2016-01-01'
      ) s
WHERE first_source IS NOT NULL
      OR last_source IS NOT NULL
GROUP BY
      email

在这里测试:SQL Fiddle

PostgreSQL 9.3 架构设置

CREATE TABLE campaignmember
    (email varchar(3), date timestamp, market_source varchar(1))
;

INSERT INTO campaignmember
    (email, date, market_source)
VALUES
    ('a@a', '2016-01-02 00:00:00', 'x'),
    ('a@a', '2016-01-03 00:00:00', 'y'),
    ('a@a', '2016-01-04 00:00:00', 'z'),
    ('b@b', '2016-01-02 00:00:00', 'x')
;

查询 1

SELECT
      email
    , MIN(first_source) AS first_source
    , MIN(date) first_date
    , MAX(last_source) AS last_source
    , MAX(date) AS last_date
FROM (
      SELECT
            email
          , date
          , CASE
                  WHEN ROW_NUMBER() OVER (PARTITION BY email ORDER BY date ASC) = 1 THEN market_source
                  ELSE NULL
            END AS first_source
          , CASE
                  WHEN ROW_NUMBER() OVER (PARTITION BY email ORDER BY date DESC) = 1 THEN market_source
                  ELSE NULL
            END AS last_source
      FROM campaignmember
      WHERE date >= '2016-01-01'
      ) s
WHERE first_source IS NOT NULL
      OR last_source IS NOT NULL
GROUP BY
      email

Results

| email | first_source |                first_date | last_source |                 last_date |
|-------|--------------|---------------------------|-------------|---------------------------|
|   a@a |            x | January, 02 2016 00:00:00 |           z | January, 04 2016 00:00:00 |
|   b@b |            x | January, 02 2016 00:00:00 |           x | January, 02 2016 00:00:00 |

&请求的小扩展,统计联系点的数量。

SELECT
      email
    , MIN(first_source) AS first_source
    , MIN(date) first_date
    , MAX(last_source) AS last_source
    , MAX(date) AS last_date
    , MAX(numof) AS Numberof_Contacts 
FROM (
      SELECT
            email
          , date
          , CASE
                  WHEN ROW_NUMBER() OVER (PARTITION BY email ORDER BY date ASC) = 1 THEN market_source
                  ELSE NULL
            END AS first_source
          , CASE
                  WHEN ROW_NUMBER() OVER (PARTITION BY email ORDER BY date DESC) = 1 THEN market_source
                  ELSE NULL
            END AS last_source
          , COUNT(*) OVER (PARTITION BY email) as numof
      FROM campaignmember
      WHERE date >= '2016-01-01'
      ) s
WHERE first_source IS NOT NULL
      OR last_source IS NOT NULL
GROUP BY
      email

【讨论】:

    猜你喜欢
    • 2014-02-21
    • 2018-11-05
    • 2019-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-05
    • 1970-01-01
    相关资源
    最近更新 更多