将表连接到自身而不重复

时间:2017-01-31 07:56:25

标签: sql postgresql join

我有一个交易表,如:

id |  incoming | value |      created_at
--------------------------------------------
1  |     t     | 1.88  | 2016-09-23 11:01:02
2  |     t     | 1.55  | 2016-09-23 11:02:02
3  |     t     | 0.73  | 2016-09-23 11:03:02
4  |     t     | 2.30  | 2016-09-23 11:04:02
5  |     t     | 0.82  | 2016-09-23 11:05:02
6  |     t     | 1.01  | 2016-09-23 11:06:02
7  |     t     | 2.33  | 2016-09-23 11:07:02
8  |     f     | 7.00  | 2016-09-23 11:08:02
9  |     f     | 1.20  | 2016-09-23 11:09:02
10 |     f     | 0.74  | 2016-09-23 11:10:02
11 |     f     | 1.53  | 2016-09-23 11:11:02

我能用一个查询得到这样的表而没有任何额外的数据库功能:

 true_value | false_value |      true_date       |     false_date
 ----------------------------------------------------------------------
   1.88     |    7.00     | 2016-09-23 11:01:02  | 2016-09-23 11:08:02
   1.55     |    1.20     | 2016-09-23 11:02:02  | 2016-09-23 11:09:02
   0.73     |    0.74     | 2016-09-23 11:03:02  | 2016-09-23 11:10:02
   2.30     |    1.53     | 2016-09-23 11:04:02  | 2016-09-23 11:11:02
   0.82     |    NULL     | 2016-09-23 11:05:02  |         NULL
   1.01     |    NULL     | 2016-09-23 11:06:02  |         NULL
   2.33     |    NULL     | 2016-09-23 11:07:02  |         NULL

就像在incoming = TRUEincoming = FALSE的{​​{1}}之间联系表一样,但每个incoming = TRUE行只有一行incoming = FALSE行没有重复

2 个答案:

答案 0 :(得分:1)

您可以将行号分配给由id列排序的真假传入记录,然后加入这些行号。这将根据您的预期输出匹配真假记录。为了便于阅读,我在这里使用公用表表达式,并尽量减少执行此操作所需的代码量。

WITH cte AS (
    SELECT id, incoming, value, created_at,
           ROW_NUMBER() OVER (PARTITION BY incoming ORDER BY id) rn
    FROM transaction
)
SELECT t1.value AS true_value,
       t2.value AS false_value,
       t1.created_at AS true_date,
       t2.created_at AS false_date
FROM cte t1
LEFT JOIN cte t2
    ON t1.rn = t2.rn AND
       t2.incoming = 'f'
WHERE t1.incoming = 't'
ORDER BY t1.id;

在这里演示:

Rextester

答案 1 :(得分:0)

上一篇文章是正确的,虽然不完全,因为它缺少对true / false的过滤器。这是一个包含两个CTE的示例,一个用于真值,另一个用于伪值,然后合并。

with
  i as (select incoming, value, created_at, row_number() over (order by id asc) as RowNum from TRans where incoming = 't'),
  o as (select incoming, value, created_at, row_number() over (order by id asc) as RowNum from TRans where incoming = 'f')
select i.value as true_value, o.value as false_value, i.created_at as true_date, o.created_at as false_Date
  from i
  left outer join o on i.RowNum = o.RowNum