【问题标题】:Return a query with datetime existing in both tables返回两个表中都存在日期时间的查询
【发布时间】:2018-01-26 08:32:57
【问题描述】:

我正在尝试返回一个表格,该表格将广告表和网站流量表中的数据连接起来,两者都包含小时级别的数据。但是,在 ads 表中存在的特定日期的时间戳可能不存在于 website 表中。例如,时间戳“2017-09-27 20:00:00+00”存在于网站流量表中,但不存在于广告表中,反之亦然。

我正在使用一个选择 ads 表时间戳的查询,但使用的是左连接。完全外部连接似乎无法解决此问题,很可能是由于选择了广告时间戳而不是网站流量时间戳。

PostgreSQL 有没有办法在一个列中返回两个表的时间戳?

非常感谢。

当前使用的查询如下:

SELECT
    ads.phase AS "phase",
    ads.datetime_utc AS "datetime",
    lower(array_to_string((regexp_split_to_array(ads.placement, '_'))[1:9], '_')) AS "delim_dims",
    a.name AS " name",
    ads.device AS "device",
    sum(ads.impressions) AS "impressions",
    sum(ads.clicks) AS "clicks",
    sum(ads.spend) AS "spend",
    web.sessions AS "sessions",
    web.bounces AS "bounces"
FROM
    ads_data AS ads
INNER JOIN
    lookup.names_lookup AS a ON
    ads.lookup_code = a.lookup_code
LEFT JOIN -- tested with FULL OUTER JOIN, returns same results
    web.website_traffic AS web ON
    ads.datetime_utc = web.datetime_est
    AND
    a.lookup_code = web.lookup_code
    AND
    ads.device = web.device
GROUP BY
    ads.phase,
    datetime,
    delim_dims,
    a.audience_name,
    web.sessions,
    web.bounces,
    device
HAVING
    sum(ads.spend) > 0

【问题讨论】:

  • coalesce(first_ts,next_ts,default_ts) 会有所帮助
  • 感谢合并建议。我测试了它,但它仍然没有返回我正在寻找的记录。
  • 请保持建设性。准确的说法。确切的结果。确切的期望。
  • 请您做一些练习来提供示例数据和所需的输出吗?
  • 我暂时不在,但我几乎可以肯定这与 HAVING 子句有关。

标签: sql postgresql


【解决方案1】:

我对您的措辞感到困惑,因为您的问题标题要求“两个表中都存在一个日期时间”,这表明您只需要 ads_data 和 web.website_traffic 中具有匹配日期时间的行。但是,由于某种原因,您想使用 LEFT JOIN 或 FULL OUTER JOIN,这让我认为您希望其中一列中有日期时间的行。我解释这一点的方式是,您想要一个包含任一表中日期时间的列;如果它恰好是具有匹配时间戳的行,那就太好了;如果一个或另一个表中只有一个时间戳,则返回它。

看起来您的问题是您正在lookup.names_lookup (a) 和ads_data 之间进行INNER JOIN。那么当你加入web.website_traffic时,你的加入条件之一就是a.lookup_code = web.lookup_code。这实质上会将您的 LEFT JOIN 转换为 INNER JOIN,因此您只会获得 ads_data 中数据的结果,而不会出现 web.website_traffic 中有一行但 ads_data 中没有一行的情况。

相反,我将从一个子查询 (CTE) 开始,它是 ads_data 与 web.website_traffic 的完全外连接,以将所有不匹配的行 + 所有匹配的行放在一起,然后使用 lookup.names_lookup 进行内连接。

我注意到的其他一些问题:

  1. ads_data datetime 列的名称指的是 UTC 时间,而 web.website_traffic 列指的是 EST 时间。
  2. 我认为您按会话和反弹进行分组很奇怪,因为它们是数字:我可能会在这些上做一分钟。
  3. 您在 GROUP BY 中引用了“delim_dims”,但由于您在 SELECT 子句中计算了该值,因此您必须在 GROUP BY 中重复计算(最后评估 SELECT 子句)

这里有一些 SQL 可以尝试(忽略潜在的 UTC 与 EST 问题):

WITH alldata AS (
    SELECT
        ads.phase,
        COALESCE(ads.datetime_utc, web.datetime_est) AS "datetime",
        COALESCE(ads.lookup_code, web.lookup_code) AS "lookup_code",
        COALESCE(ads.device, web.device) AS "device",
        ads.placement,
        ads.impressions,
        ads.clicks,
        ads.spend,
        web.sessions,
        web.bounces
    FROM
        ads_data AS ads FULL OUTER JOIN web.website_traffic AS web ON
            ads.datetime_utc = web.datetime_est AND
            ads.lookup_code = web.lookup_code AND
            ads.device = web.device
)
SELECT
    alldata.phase AS "phase",
    alldata.datetime AS "datetime",
    lower(array_to_string((regexp_split_to_array(alldata.placement, '_'))[1:9], '_')) AS "delim_dims",
    a.name AS "name",
    alldata.device AS "device",
    sum(alldata.impressions) AS "impressions",
    sum(alldata.clicks) AS "clicks",
    sum(alldata.spend) AS "spend",
    min(alldata.sessions) AS "sessions",
    min(alldata.bounces) AS "bounces"
FROM
    alldata INNER JOIN lookup.names_lookup AS a ON 
        alldata.lookup_code = a.lookup_code
GROUP BY
    alldata.phase,
    alldata.datetime,
    lower(array_to_string((regexp_split_to_array(alldata.placement, '_'))[1:9], '_')),
    a.audience_name,
    alldata.device
HAVING
    sum(ads.spend) > 0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多