【问题标题】:Oracle SQL replace a return column with a null valueOracle SQL 用空值替换返回列
【发布时间】:2016-04-11 07:12:55
【问题描述】:

我想修改以下查询,以便它从 S_ID 所指的表(称为 STORES)中获取相应 NAME 列的值,而不是 ORDER.S_ID 列。

但是,在某些情况下,S_ID 为空,在这种情况下没有对应的名称列。在这种情况下,ORDER 和 ORDERLIST 表中仍有我想要 COUNT(*)-ed 并因此由查询显示的记录,因此结果集的第二列为空

SELECT 
COUNT(*), ORDER.S_ID 
FROM 
ORDER, ORDERLIST 
WHERE 
ORDERLIST.O_ID = ORDER.ID AND 
ORDER.DATE = '13-APR.  -09 19.42.05,259000000' 
GROUP BY S_ID;

样本数据:

订单表

ID  DATE                            S_ID
----------------------------------------              
1   11-APR.  -09 19.41.39,187000000 null
2   12-APR.  -09 19.42.05,259000000 null
3   13-APR.  -09 19.42.41,688000000 null
11  16-APR.  -09 22.06.11,169000000 3

ORDERLIST 表

O_ID    B_ID    PRICE
---------------------
3       6       7999
2       2       2000
2       6       7999
1       5       5000
1       1       1000
11      4       4000
11      6       7999

STORES 表

ID  NAME
----------
1   Store1
2   Store2
3   Store3

如果用户查询 S_ID 值不为空的日期,我希望看到返回的内容:(此特定情况是查询日期 16-APR.-09 22.06.11,169000000 时)

COUNT(*) STORENAME
2        Store3

如果它为空,我想要返回的内容: (查询日期 13-APR.-09 19.42.41,688000000)

COUNT(*) STORENAME
1        null

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    正如 Gordon 所说,您需要一个外连接,并且使用正确的连接语法要好得多 - 尤其是外连接,但无论您的导师使用什么,始终如此。

    由于您是从订单开始,并且可能有匹配的商店,因此您需要将 stores 表的连接作为外连接:

    SELECT o.s_id, s.name, count(*)
    FROM "ORDER" o
    JOIN orderlist ol ON ol.o_id = o.id
    LEFT JOIN stores s ON s.id = o.s_id
    --WHERE o."DATE" = TO_TIMESTAMP('13-APR.  -09 19.42.05,259000000', 'DD-MON".  "-RR HH24.MI.SS,FF9')
    GROUP BY o.s_id, s.name;
    
          S_ID NAME     COUNT(*)
    ---------- ------ ----------
                               5
             3 Store3          2
    

    由于“订单”和“日期”是保留字,我不得不为它们使用带引号的标识符,但它们可能不是真实姓名。如果可以避免使用带引号的标识符,请不要使用它们。我使用表别名来减轻痛苦。 “日期”也是时间戳而不是日期,因为您有小数秒,这使得名称更加混乱。

    我已经注释掉了日期/时间戳限制,因为它与您的任何示例数据都不匹配,如果更改为 4 月 12 日,仍然只匹配一个,这对于演示不是很有帮助。您的 NLS_TIMESTAMP_FORMAT 是......不寻常,但这是一个单独的问题。为了比较,使用时间戳文字更简单:

    WHERE o."DATE" = TIMESTAMP '2009-04-12 19:42:05.259000000'
    

    请注意,与您的 NLS_TIMESTAMP_FORMAT 不同,冒号和句点作为秒值的小数部分分隔符。


    如果您的导师真的坚持使用旧的、特定于 Oracle 的连接语法,那么您可以将其安排为:

    SELECT o.s_id, s.name, count(*)
    FROM "ORDER" o, orderlist ol, stores s
    WHERE ol.o_id = o.id
    AND s.id (+) = o.s_id
    --AND o."DATE" = TIMESTAMP '2009-04-12 19:42:05.259000000'
    GROUP BY o.s_id, s.name;
    

    ...但是要弄清楚发生了什么要困难得多,而且在连接条件中犯错误要容易得多(或完全遗漏一个)。请使用正确的 ANSI 连接语法...

    【讨论】:

    • 谢谢,您的解决方案完美无瑕,正是我所需要的!如果我没记错的话,SQL 开发人员以从用户操作系统中提取的格式显示时间戳,并且是本地化的。我的显示方式与我粘贴的一样 shrug
    • @aurellb 如果您想在 SQL Developer 中更改日期格式,请转到 Tools > Preferences... 然后展开 Database > NLSoptions 并更改其中的日期或时间戳格式(类似于 YYYY-MM-DD HH24:MI:SS日期或YYYY-MM-DD HH24:MI:SSXFF 时间戳)。
    • 您可以在首选项中覆盖它(有一个 NLS 部分),或使用alter session。纯粹出于好奇,哪个语言环境会产生这种情况?我猜是法语,除了我认为是Avr. 而不是Apr.。月份缩写中的空格也可以通过更改默认格式来隐藏。
    • 这是匈牙利语言环境
    【解决方案2】:

    使用left join。事实上,总是使用显式的join 语法。 从不from 子句中使用逗号:

    SELECT s.id, s.name, count(ol.o_id)
    FROM stores s left join
         order o
         on s.id = o.s_id left join
         orderlist ol
         on ol.o_id = o.id and
            o.DATE = '13-APR.  -09 19.42.05,259000000' 
    GROUP BY s.id, s.name;
    

    from 子句中逗号的使用已经过时了大约二十年。您还应该了解外连接。

    【讨论】:

    • 您忘记关闭第一个 count() 的括号 :o 谢谢您的建议,我马上试试!可悲的是,他们教给我们这种过时的语法(我还是个学生)
    • 此查询在 SQL Developer 中执行时出错,声称第一个 count() 子句的参数数量无效。
    猜你喜欢
    • 1970-01-01
    • 2022-11-17
    • 2012-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-21
    相关资源
    最近更新 更多