如何在 PostgreSQL 中将列扩展为单独的时间步长

How to expand columns into individual timesteps in PostgreSQL

我有 table 个代表时间序列的列。数据类型并不重要,但 timestep2 之后的任何内容都可能是 NULL.

| id | timestep1 | timestep2 | timestep3 | timestep4 |
|----|-----------|-----------|-----------|-----------|
| a  | foo1      | bar1      | baz1      | qux1      |
| b  | foo2      | bar2      | baz2      | NULL      |

我正在尝试检索更适合table 的数据视图以进行建模。我的建模用例要求我在每一步将每个时间序列(行)分解成代表它们各自“状态”的行。即:

| id | timestep1 | timestep2 | timestep3 | timestep4 |
|----|-----------|-----------|-----------|-----------|
| a  | foo1      | NULL      | NULL      | NULL      |
| a  | foo1      | bar1      | NULL      | NULL      |
| a  | foo1      | bar1      | baz1      | NULL      |
| a  | foo1      | bar1      | baz1      | qux1      |
| b  | foo2      | NULL      | NULL      | NULL      |
| b  | foo2      | bar2      | NULL      | NULL      |
| b  | foo2      | bar2      | baz2      | NULL      |

如何在 PostgreSQL 中完成此操作?

使用UNION.

select id, timestep1, timestep2, timestep3, timestep4
from my_table

union

select id, timestep1, timestep2, timestep3, null
from my_table

union

select id, timestep1, timestep2, null, null
from my_table

union

select id, timestep1, null, null, null
from my_table

order by 
    id, 
    timestep2 nulls first, 
    timestep3 nulls first, 
    timestep4 nulls first

有一个更紧凑的解决方案,在处理更多时间步时可能更方便:

select distinct
    id, 
    timestep1, 
    case when i > 1 then timestep2 end as timestep2, 
    case when i > 2 then timestep3 end as timestep3, 
    case when i > 3 then timestep4 end as timestep4 
from my_table
cross join generate_series(1, 4) as i
order by 
    id, 
    timestep2 nulls first, 
    timestep3 nulls first, 
    timestep4 nulls first

Db<>fiddle.

中测试