【问题标题】:Output records with null values even if not present即使不存在也输出具有空值的记录
【发布时间】:2022-01-08 16:25:53
【问题描述】:

我在 Oracle 中有一个如下表

gen_id serial_code is_verified
1 fmcg Y
1 smcg Y
1 xmcg N
2 smcg Y
2 fmcg Y
2 2mcg Y
3 smcg Y
3 amcg Y

现在我想要 max gen_id 的输出,在这种情况下为 3,serial_code 'smcg' 和 'fmcg' 我可以通过查询轻松获得输出,但我希望它采用如下格式。

gen_id serial_code is_verified
3 smcg Y
3 fmcg not_present

我怎样才能做到这一点?任何帮助深表感谢。 提前致谢

【问题讨论】:

  • 为什么fmcg 应该在gen_id=3 的结果集中返回?背后的逻辑是什么?

标签: sql oracle plsql


【解决方案1】:

您可以为此使用PARTITIONed OUTER JOIN

来自 Oracle 12:

SELECT t.gen_id,
       s.serial_code,
       COALESCE(t.is_verified, 'not_present') AS is_verified
FROM   (SELECT 'smcg' AS serial_code FROM DUAL UNION ALL
        SELECT 'fmcg' FROM DUAL) s
       LEFT OUTER JOIN (
         SELECT *
         FROM   table_name
         ORDER BY gen_id DESC
         FETCH FIRST ROW WITH TIES
       ) t
       PARTITION BY (gen_id)
       ON (s.serial_code = t.serial_code)

在 Oracle 11 中,您可以使用:

SELECT t.gen_id,
       s.serial_code,
       COALESCE(t.is_verified, 'not_present') AS is_verified
FROM   (SELECT 'smcg' AS serial_code FROM DUAL UNION ALL
        SELECT 'fmcg' FROM DUAL) s
       LEFT OUTER JOIN (
         SELECT gen_id, serial_code, is_verified
         FROM   (
           SELECT t.*,
                  RANK() OVER (ORDER BY gen_id DESC) AS rnk
           FROM   table_name t
         )
         WHERE  rnk = 1
       ) t
       PARTITION BY (gen_id)
       ON (s.serial_code = t.serial_code)

其中,对于样本数据:

CREATE TABLE table_name (gen_id, serial_code, is_verified) AS
SELECT 1, 'fmcg', 'Y' FROM DUAL UNION ALL
SELECT 1, 'smcg', 'Y' FROM DUAL UNION ALL
SELECT 1, 'xmcg', 'N' FROM DUAL UNION ALL
SELECT 2, 'smcg', 'Y' FROM DUAL UNION ALL
SELECT 2, 'fmcg', 'Y' FROM DUAL UNION ALL
SELECT 2, '2mcg', 'Y' FROM DUAL UNION ALL
SELECT 3, 'smcg', 'Y' FROM DUAL UNION ALL
SELECT 3, 'amcg', 'Y' FROM DUAL;

两个输出:

   PARTITION BY (gen_id)
   ON (s.serial_code = t.serial_code)
GEN_ID SERIAL_CODE IS_VERIFIED
3 fmcg not_present
3 smcg Y

Oracle 18 dbfiddle here - Oracle 11 dbfiddle here

【讨论】:

  • 这很好用..谢谢!!!!
【解决方案2】:

这样做了,但看起来不太漂亮。在代码中读取 cmets。

SQL> WITH
  2     test (gen_id, serial_code, is_verified)
  3     AS
  4     -- sample data
  5        (SELECT 1, 'fmcg', 'Y' FROM DUAL
  6         UNION ALL
  7         SELECT 1, 'smcg', 'Y' FROM DUAL
  8         UNION ALL
  9         SELECT 1, 'xmcg', 'N' FROM DUAL
 10         UNION ALL
 11         SELECT 3, 'smcg', 'Y' FROM DUAL
 12         UNION ALL
 13         SELECT 3, 'amcg', 'Y' FROM DUAL),

 14     maxgen (gen_id)
 15     AS
 16     -- MAX gen_id value; will be used later
 17     (SELECT MAX (gen_id) FROM test),
 18     temp
 19     AS
 20        -- compose NOT_PRESENT rows that don't exist in original (TEST) table
 21        (SELECT t.gen_id, c.serial_code, 'not_present' is_verified
 22           FROM test t
 23                CROSS JOIN (SELECT DISTINCT serial_code
 24                              FROM test) c
 25                JOIN maxgen m
 26                   ON     m.gen_id = t.gen_id
 27                      AND (t.gen_id, c.serial_code) NOT IN
 28                             (SELECT gen_id, serial_code FROM test))
 29  -- finally: union existing rows (from TEST) with NOT_PRESENT ones (from TEMP)
 30  SELECT a.gen_id, a.serial_code, a.is_verified
 31    FROM test a JOIN maxgen m ON m.gen_id = a.gen_id
 32   WHERE serial_code IN ('smcg', 'fmcg')
 33  UNION
 34  SELECT x.gen_id, x.serial_code, x.is_verified
 35    FROM temp x
 36   WHERE x.serial_code IN ('smcg', 'fmcg');

    GEN_ID SERIAL_CODE  IS_VERIFIED
---------- ------------ -----------
         3 fmcg         not_present
         3 smcg         Y

SQL>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-16
    • 2011-08-20
    • 2018-08-14
    • 1970-01-01
    • 2012-07-12
    • 1970-01-01
    相关资源
    最近更新 更多