簡體   English   中英

如何根據計算字段連接兩個表?

[英]How to join two tables based on a calculated field?

我有兩個 SQL 查詢 output 同種 output 並且具有相同的分組和順序:

select date_trunc('month', inserted_at)::date as date, count(id) from payment_logs where payment_logs.event_name = 'subscription_created' group by date order by date desc;

在此處輸入圖像描述

select date_trunc('month', inserted_at)::date as date, count(id) from users group by date order by date desc;

在此處輸入圖像描述

我想根據計算的日期字段(即月份)加入這兩個結果,並得到一個包含 3 列的結果:日期、count_users 和 count_payment_logs。

我怎樣才能做到這一點? 謝謝。

像這樣的東西

select plog.date as odata, usr.cntusr, plog.cntlog 
from (
    select date_trunc('month', inserted_at)::date as date, count(id) cntlog
    from payment_logs 
    where payment_logs.event_name = 'subscription_created' 
    group by date order by date desc
) plog
join (
    select date_trunc('month', inserted_at)::date as date, count(id) cntusr
    from users 
    group by date 
) usr on plog.data = usr.data
order by odata desc

接受的答案沒有錯,但我想展示一個替代方案並添加一些顏色。 除了子查詢之外,您還可以使用公用表表達式 (CTE),它提高了可讀性,同時還具有一些其他功能。 以下是使用 CTE 的示例:

with payments as (
  select
    date_trunc('month', inserted_at)::date as date,
    count(id) as payment_count
  from payment_logs
  where
    event_name = 'subscription_created'
  group by date
),
users as (
  select
    date_trunc('month', inserted_at)::date as date,
    count(id) as user_count
  from users
  group by date
)
select
  p.date, p.payment_count, u.user_count
from
  payments p
  join users u on
    p.date = u.date
order by
  p.date desc

在我看來,抽象更簡潔,使代碼更容易遵循(並因此維護)。

其他注意事項:

order by很昂貴,您可以在每個子查詢/CTE 中避免它,因為無論如何它都是在最后完成的。 不管你在主查詢中做什么,子查詢中的查詢都會被破壞,所以完全省略它們。 您的結果不會有所不同,並且您的查詢將更有效率。

在此示例中,您可能沒有任何缺失的月份,但有可能......特別是如果您將此概念擴展到未來的查詢。 在這種情況下,您可能需要考慮完全外部聯接而不是內部聯接(您有月份出現在可能不在付款中的用戶中,反之亦然):

select
  coalesce (p.date, u.date) as date,
  p.payment_count, u.user_count
from
  payments p
  full outer join users u on
    p.date = u.date
order by
  1 desc

CTE 與子查詢相比的另一個好處是您可以重用它們。 在這個例子中,我想模仿完全外連接的概念,但有一個額外的轉折——我在查詢中按月從另一個表中獲取數據。 CTE 讓我可以根據需要多次將 CTE 用於“支付”和“用戶”。 在這里,我在 all_dates CTE 和主查詢中再次使用它們。 通過創建“all_dates”,我現在可以使用左連接並避免連接中出現奇怪的合並(沒有錯,只是丑陋)。

with payments as (
  -- same as above
),
users as (
  -- same as above
),
all_dates as (
  select date from payments  -- referred to payments here
  union
  select date from users
)
select
  a.date, ac.days_in_month, p.payment_count, u.user_count
from
  all_dates a
  join accounting_calendar ac on
    a.date = ac.accounting_month
  left join payments p on -- referred to it here again, same CTE
    a.date = p.date
  left join users u on
    a.date = u.date
order by
  p.date desc

關鍵是您可以重用 CTE。

最后一個優點是您可以聲明 CTE 已物化或未物化(默認)。 物化 CTE 本質上將預處理和存儲結果,在某些情況下可能具有更好的性能。 另一方面,非物化 on 將模仿標准子查詢,這很好,因為您可以將 where 子句條件從查詢外部傳遞到查詢內部。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM