簡體   English   中英

Sql自連接以及不匹配的行

[英]Sql self join along with non matching rows

我有一張這樣的桌子

id | user | name | action | created_at
--------------------------------------------------
1  | 42    | eve | open   | 2020-01-06 06:17:42
2  | 42    | eve | close  | 2020-01-06 06:27:42
3  | 42    | eve | open   | 2020-01-06 06:37:42
4  | 42    | eve | close  | 2020-01-06 06:47:42
5  | 42    | eve | open   | 2020-01-06 06:57:42

我需要得到這張表:

user | name | open | open_created_at     | close | close _created_at 
-----------------------------------------------------------------------
42   | eve  | open | 2020-01-06 06:17:42 | close | 2020-01-06 06:27:42
42   | eve  | open | 2020-01-06 06:37:42 | close | 2020-01-06 06:47:42
42   | eve  | open | 2020-01-06 06:57:42 | null  | null

這是我得到的表:

SELECT t1.user, t1.name, t1.action, t1.created_at, t2.action, t2.created_at 
FROM tabel t1, table t2
WHERE t1.user = t2.user AND t1.action = 'open' AND t2.action = 'close' AND t1.created_at < t2.created_at
GROUP BY t1.id


user | name | open | open_created_at     | close | close _created_at 
-----------------------------------------------------------------------
42   | eve  | open | 2020-01-06 06:17:42 | close | 2020-01-06 06:27:42
42   | eve  | open | 2020-01-06 06:37:42 | close | 2020-01-06 06:47:42

如何在同一列中獲得具有匹配打開/關閉的表以及沒有匹配關閉列的行?

您需要使用LEFT JOIN而不是INNER JOIN ,並且需要將WHERE子句移動到JOIN條件中。 您還應該在t2值周圍添加聚合函數以確保一致的結果:

SELECT t1.user, t1.name, t1.action AS open, t1.created_at AS open_created_at,
       MIN(t2.action) AS close, MIN(t2.created_at) AS close_created_at
FROM log t1
LEFT JOIN log t2 ON t1.user = t2.user AND t2.action = 'close' AND t1.created_at < t2.created_at
WHERE t1.action = 'open'
GROUP BY t1.id, t1.name, t1.action, t1.created_at

輸出:

user    name    open    open_created_at         close   close_created_at
42      eve     open    2020-01-06 06:17:42     close   2020-01-06 06:27:42
42      eve     open    2020-01-06 06:37:42     close   2020-01-06 06:47:42
42      eve     open    2020-01-06 06:57:42     (null)  (null)

SQLFiddle 上的演示

另一種方法是將過程分為 3 個步驟:

  • 收集所有open行並按created_at按升序對它們進行排序。 在此過程中,創建一個變量,例如@rank以按升序為每一行分配排名,如 1,2,3 等等。

  • 收集所有close行並按created_at按升序對它們進行排序。 在此過程中,創建一個變量,例如@rank2 ,以升序為每一行分配排名,如 1,2,3 等等。

  • 現在,根據rank對兩個表進行left join

查詢片段:

select d1.user,d1.name,d1.action as open,d1.open_created_at,d2.action as close,d2.close_created_at
from 
(
  select @rank := @rank + 1 as rank,user,name,action,created_at as open_created_at
  from log,(select  @rank := 0) l1
  where action = 'open'
  order by created_at asc
) d1
left join
(
 select @rank2 := @rank2 + 1 as rank,user,name,action,created_at as close_created_at
  from log,(select  @rank2 := 0) l2
  where action = 'close'
  order by created_at asc

) d2
on d1.rank = d2.rank

數據庫小提琴: https : //www.db-fiddle.com/f/hYHyz45rtuiEXGQPbz3m6z/0

暫無
暫無

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

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