将 oracle table 行展平为具有多列的单行
flattening oracle table rows to a single row with multiple columns
我有一个审核 table 维护用户状态,当它发生变化时。
table 如下所示。
USER_ENTL_ID USER_STATUS CREATED_Date
1 S 10/20/2017
1 C 10/21/2017
1 W 10/22/2017
1 SP 10/23/2017
2 S 10/24/2017
2 C 10/25/2017
每个用户可能不会转换到应用程序中的每个状态,这没关系。我想要做的是捕获每个用户更改时的日期和状态,并将其放在一行中。
所以我希望输出如下所示。
id S_status s_created c_status c_created W_status w_created sp_STATUS SP_CREATED
1 S 10/20/2017 C 10/21/2017 W 10/22/2017 SP 10/23/2017
2 S 10/24/2017 C 10/25/2017
我一直在阅读 pivot 和 unpivot and decode,但我不确定这在 oracle 中是否可行。如果是,有人可以指导我走正确的道路吗?
类似下面的内容可能更容易理解:
WITH cteID AS (SELECT DISTINCT USER_ENTL_ID AS ID FROM AUDIT_TABLE),
cteS AS (SELECT USER_ENTL_ID AS ID,
'S' AS S_STATUS,
MIN(CREATED_DATE) AS S_CREATED
FROM AUDIT_TABLE
WHERE STATUS = 'S'
GROUP BY USER_ENTL_ID),
cteC AS (SELECT USER_ENTL_ID AS ID,
'C' AS C_STATUS,
MIN(CREATED_DATE) AS C_CREATED
FROM AUDIT_TABLE
WHERE STATUS = 'C'
GROUP BY USER_ENTL_ID),
cteSP AS (SELECT USER_ENTL_ID AS ID,
'SP' AS SP_STATUS,
MIN(CREATED_DATE) AS SP_CREATED
FROM AUDIT_TABLE
WHERE STATUS = 'SP'
GROUP BY USER_ENTL_ID),
cteW AS (SELECT USER_ENTL_ID AS ID,
'W' AS W_STATUS,
MIN(CREATED_DATE) AS W_CREATED
FROM AUDIT_TABLE
WHERE STATUS = 'W'
GROUP BY USER_ENTL_ID)
SELECT i.ID,
s.S_STATUS,
s.S_CREATED,
c.C_STATUS,
c.C_CREATED,
sp.SP_STATUS,
sp.SP_CREATED,
w.W_STATUS,
w.W_CREATED
FROM cteID i
LEFT OUTER JOIN cteS s
ON s.ID = i.ID
LEFT OUTER JOIN cteC c
ON c.ID = i.ID
LEFT OUTER JOIN cteSP sp
ON sp.ID = i.ID
LEFT OUTER JOIN cteW w
ON w.ID = i.ID
祝你好运。
使用 "conditional aggregates" 是一种传统且仍然有效的处理此类需求的方法:
PostgreSQL 9.6 架构设置:
CREATE TABLE AUDIT_TABLE
(USER_ENTL_ID int, USER_STATUS varchar(2), CREATED_DATE timestamp)
;
INSERT INTO AUDIT_TABLE
(USER_ENTL_ID, USER_STATUS, CREATED_DATE)
VALUES
(1, 'S', '2017-10-20 00:00:00'),
(1, 'C', '2017-10-21 00:00:00'),
(1, 'W', '2017-10-22 00:00:00'),
(1, 'SP', '2017-10-23 00:00:00'),
(2, 'S', '2017-10-24 00:00:00'),
(2, 'C', '2017-10-25 00:00:00')
;
查询 1:
nb,在此使用 MIN 或 MAX 可能很重要,具体取决于您的数据,但我在每个输出位置的数据中只有一个值,因此可以使用任一函数。
SELECT
USER_ENTL_ID
, MAX(CASE WHEN USER_STATUS = 'S' THEN USER_STATUS END) s_status
, MIN(CASE WHEN USER_STATUS = 'S' THEN CREATED_DATE END) s_created
, MAX(CASE WHEN USER_STATUS = 'C' THEN USER_STATUS END) c_status
, MIN(CASE WHEN USER_STATUS = 'C' THEN CREATED_DATE END) c_created
, MAX(CASE WHEN USER_STATUS = 'W' THEN USER_STATUS END) w_status
, MIN(CASE WHEN USER_STATUS = 'W' THEN CREATED_DATE END) w_created
, MAX(CASE WHEN USER_STATUS = 'SP' THEN USER_STATUS END) sp_status
, MIN(CASE WHEN USER_STATUS = 'SP' THEN CREATED_DATE END) sp_created
FROM AUDIT_TABLE
GROUP BY
USER_ENTL_ID
| user_entl_id | s_status | s_created | c_status | c_created | w_status | w_created | sp_status | sp_created |
|--------------|----------|----------------------|----------|----------------------|----------|----------------------|-----------|----------------------|
| 1 | S | 2017-10-20T00:00:00Z | C | 2017-10-21T00:00:00Z | W | 2017-10-22T00:00:00Z | SP | 2017-10-23T00:00:00Z |
| 2 | S | 2017-10-24T00:00:00Z | C | 2017-10-25T00:00:00Z | (null) | (null) | (null) | (null) |
已添加
进一步解释:如果您删除 MIN 或 MAX 函数并删除分组依据,这就是您得到的结果:
+--------------+----------+----------------------+----------+----------------------+----------+----------------------+-----------+----------------------+
| user_entl_id | s_status | s_created | c_status | c_created | w_status | w_created | sp_status | sp_created |
+--------------+----------+----------------------+----------+----------------------+----------+----------------------+-----------+----------------------+
| 1 | S | 2017-10-20T00:00:00Z | (null) | (null) | (null) | (null) | (null) | (null) |
| 1 | (null) | (null) | C | 2017-10-21T00:00:00Z | (null) | (null) | (null) | (null) |
| 1 | (null) | (null) | (null) | (null) | W | 2017-10-22T00:00:00Z | (null) | (null) |
| 1 | (null) | (null) | (null) | (null) | (null) | (null) | SP | 2017-10-23T00:00:00Z |
| 2 | S | 2017-10-24T00:00:00Z | (null) | (null) | (null) | (null) | (null) | (null) |
| 2 | (null) | (null) | C | 2017-10-25T00:00:00Z | (null) | (null) | (null) | (null) |
+--------------+----------+----------------------+----------+----------------------+----------+----------------------+-----------+----------------------+
如果你研究一下,你会发现对于我们关心的数据,每行只有一个值(每个 USER_ENTL_ID)但它们分布在几行。所以 MIN/MAX 函数和 GROUP BY "flatten" 结果,所以我们最终得到了想要的结果。 QED
只需使用PIVOT
:
Oracle 11g R2 架构设置:
CREATE TABLE AUDIT_TABLE (USER_ENTL_ID, USER_STATUS, CREATED_DATE) AS
SELECT 1, 'S', TIMESTAMP '2017-10-20 00:00:00' FROM DUAL UNION ALL
SELECT 1, 'C', TIMESTAMP '2017-10-21 00:00:00' FROM DUAL UNION ALL
SELECT 1, 'W', TIMESTAMP '2017-10-22 00:00:00' FROM DUAL UNION ALL
SELECT 1, 'SP', TIMESTAMP '2017-10-23 00:00:00' FROM DUAL UNION ALL
SELECT 2, 'S', TIMESTAMP '2017-10-24 00:00:00' FROM DUAL UNION ALL
SELECT 2, 'C', TIMESTAMP '2017-10-25 00:00:00' FROM DUAL
查询 1:
SELECT *
FROM AUDIT_TABLE
PIVOT (
MAX( Created_Date ) AS Created,
MAX( User_Status ) AS Status
FOR User_Status IN (
'S' AS S, 'C' AS C, 'W' AS W, 'SP' AS SP
)
)
| USER_ENTL_ID | S_CREATED | S_STATUS | C_CREATED | C_STATUS | W_CREATED | W_STATUS | SP_CREATED | SP_STATUS |
|--------------|-----------------------|----------|-----------------------|----------|-----------------------|----------|-----------------------|-----------|
| 1 | 2017-10-20 00:00:00.0 | S | 2017-10-21 00:00:00.0 | C | 2017-10-22 00:00:00.0 | W | 2017-10-23 00:00:00.0 | SP |
| 2 | 2017-10-24 00:00:00.0 | S | 2017-10-25 00:00:00.0 | C | (null) | (null) | (null) | (null) |
我有一个审核 table 维护用户状态,当它发生变化时。 table 如下所示。
USER_ENTL_ID USER_STATUS CREATED_Date
1 S 10/20/2017
1 C 10/21/2017
1 W 10/22/2017
1 SP 10/23/2017
2 S 10/24/2017
2 C 10/25/2017
每个用户可能不会转换到应用程序中的每个状态,这没关系。我想要做的是捕获每个用户更改时的日期和状态,并将其放在一行中。
所以我希望输出如下所示。
id S_status s_created c_status c_created W_status w_created sp_STATUS SP_CREATED
1 S 10/20/2017 C 10/21/2017 W 10/22/2017 SP 10/23/2017
2 S 10/24/2017 C 10/25/2017
我一直在阅读 pivot 和 unpivot and decode,但我不确定这在 oracle 中是否可行。如果是,有人可以指导我走正确的道路吗?
类似下面的内容可能更容易理解:
WITH cteID AS (SELECT DISTINCT USER_ENTL_ID AS ID FROM AUDIT_TABLE),
cteS AS (SELECT USER_ENTL_ID AS ID,
'S' AS S_STATUS,
MIN(CREATED_DATE) AS S_CREATED
FROM AUDIT_TABLE
WHERE STATUS = 'S'
GROUP BY USER_ENTL_ID),
cteC AS (SELECT USER_ENTL_ID AS ID,
'C' AS C_STATUS,
MIN(CREATED_DATE) AS C_CREATED
FROM AUDIT_TABLE
WHERE STATUS = 'C'
GROUP BY USER_ENTL_ID),
cteSP AS (SELECT USER_ENTL_ID AS ID,
'SP' AS SP_STATUS,
MIN(CREATED_DATE) AS SP_CREATED
FROM AUDIT_TABLE
WHERE STATUS = 'SP'
GROUP BY USER_ENTL_ID),
cteW AS (SELECT USER_ENTL_ID AS ID,
'W' AS W_STATUS,
MIN(CREATED_DATE) AS W_CREATED
FROM AUDIT_TABLE
WHERE STATUS = 'W'
GROUP BY USER_ENTL_ID)
SELECT i.ID,
s.S_STATUS,
s.S_CREATED,
c.C_STATUS,
c.C_CREATED,
sp.SP_STATUS,
sp.SP_CREATED,
w.W_STATUS,
w.W_CREATED
FROM cteID i
LEFT OUTER JOIN cteS s
ON s.ID = i.ID
LEFT OUTER JOIN cteC c
ON c.ID = i.ID
LEFT OUTER JOIN cteSP sp
ON sp.ID = i.ID
LEFT OUTER JOIN cteW w
ON w.ID = i.ID
祝你好运。
使用 "conditional aggregates" 是一种传统且仍然有效的处理此类需求的方法:
PostgreSQL 9.6 架构设置:
CREATE TABLE AUDIT_TABLE
(USER_ENTL_ID int, USER_STATUS varchar(2), CREATED_DATE timestamp)
;
INSERT INTO AUDIT_TABLE
(USER_ENTL_ID, USER_STATUS, CREATED_DATE)
VALUES
(1, 'S', '2017-10-20 00:00:00'),
(1, 'C', '2017-10-21 00:00:00'),
(1, 'W', '2017-10-22 00:00:00'),
(1, 'SP', '2017-10-23 00:00:00'),
(2, 'S', '2017-10-24 00:00:00'),
(2, 'C', '2017-10-25 00:00:00')
;
查询 1:
nb,在此使用 MIN 或 MAX 可能很重要,具体取决于您的数据,但我在每个输出位置的数据中只有一个值,因此可以使用任一函数。
SELECT
USER_ENTL_ID
, MAX(CASE WHEN USER_STATUS = 'S' THEN USER_STATUS END) s_status
, MIN(CASE WHEN USER_STATUS = 'S' THEN CREATED_DATE END) s_created
, MAX(CASE WHEN USER_STATUS = 'C' THEN USER_STATUS END) c_status
, MIN(CASE WHEN USER_STATUS = 'C' THEN CREATED_DATE END) c_created
, MAX(CASE WHEN USER_STATUS = 'W' THEN USER_STATUS END) w_status
, MIN(CASE WHEN USER_STATUS = 'W' THEN CREATED_DATE END) w_created
, MAX(CASE WHEN USER_STATUS = 'SP' THEN USER_STATUS END) sp_status
, MIN(CASE WHEN USER_STATUS = 'SP' THEN CREATED_DATE END) sp_created
FROM AUDIT_TABLE
GROUP BY
USER_ENTL_ID
| user_entl_id | s_status | s_created | c_status | c_created | w_status | w_created | sp_status | sp_created |
|--------------|----------|----------------------|----------|----------------------|----------|----------------------|-----------|----------------------|
| 1 | S | 2017-10-20T00:00:00Z | C | 2017-10-21T00:00:00Z | W | 2017-10-22T00:00:00Z | SP | 2017-10-23T00:00:00Z |
| 2 | S | 2017-10-24T00:00:00Z | C | 2017-10-25T00:00:00Z | (null) | (null) | (null) | (null) |
已添加
进一步解释:如果您删除 MIN 或 MAX 函数并删除分组依据,这就是您得到的结果:
+--------------+----------+----------------------+----------+----------------------+----------+----------------------+-----------+----------------------+
| user_entl_id | s_status | s_created | c_status | c_created | w_status | w_created | sp_status | sp_created |
+--------------+----------+----------------------+----------+----------------------+----------+----------------------+-----------+----------------------+
| 1 | S | 2017-10-20T00:00:00Z | (null) | (null) | (null) | (null) | (null) | (null) |
| 1 | (null) | (null) | C | 2017-10-21T00:00:00Z | (null) | (null) | (null) | (null) |
| 1 | (null) | (null) | (null) | (null) | W | 2017-10-22T00:00:00Z | (null) | (null) |
| 1 | (null) | (null) | (null) | (null) | (null) | (null) | SP | 2017-10-23T00:00:00Z |
| 2 | S | 2017-10-24T00:00:00Z | (null) | (null) | (null) | (null) | (null) | (null) |
| 2 | (null) | (null) | C | 2017-10-25T00:00:00Z | (null) | (null) | (null) | (null) |
+--------------+----------+----------------------+----------+----------------------+----------+----------------------+-----------+----------------------+
如果你研究一下,你会发现对于我们关心的数据,每行只有一个值(每个 USER_ENTL_ID)但它们分布在几行。所以 MIN/MAX 函数和 GROUP BY "flatten" 结果,所以我们最终得到了想要的结果。 QED
只需使用PIVOT
:
Oracle 11g R2 架构设置:
CREATE TABLE AUDIT_TABLE (USER_ENTL_ID, USER_STATUS, CREATED_DATE) AS
SELECT 1, 'S', TIMESTAMP '2017-10-20 00:00:00' FROM DUAL UNION ALL
SELECT 1, 'C', TIMESTAMP '2017-10-21 00:00:00' FROM DUAL UNION ALL
SELECT 1, 'W', TIMESTAMP '2017-10-22 00:00:00' FROM DUAL UNION ALL
SELECT 1, 'SP', TIMESTAMP '2017-10-23 00:00:00' FROM DUAL UNION ALL
SELECT 2, 'S', TIMESTAMP '2017-10-24 00:00:00' FROM DUAL UNION ALL
SELECT 2, 'C', TIMESTAMP '2017-10-25 00:00:00' FROM DUAL
查询 1:
SELECT *
FROM AUDIT_TABLE
PIVOT (
MAX( Created_Date ) AS Created,
MAX( User_Status ) AS Status
FOR User_Status IN (
'S' AS S, 'C' AS C, 'W' AS W, 'SP' AS SP
)
)
| USER_ENTL_ID | S_CREATED | S_STATUS | C_CREATED | C_STATUS | W_CREATED | W_STATUS | SP_CREATED | SP_STATUS |
|--------------|-----------------------|----------|-----------------------|----------|-----------------------|----------|-----------------------|-----------|
| 1 | 2017-10-20 00:00:00.0 | S | 2017-10-21 00:00:00.0 | C | 2017-10-22 00:00:00.0 | W | 2017-10-23 00:00:00.0 | SP |
| 2 | 2017-10-24 00:00:00.0 | S | 2017-10-25 00:00:00.0 | C | (null) | (null) | (null) | (null) |