【问题标题】:Invalid number in Oracle SQL CaseOracle SQL 案例中的无效数字
【发布时间】:2019-02-18 01:30:05
【问题描述】:

嗨,我遇到了一个 SQL 案例的问题,问题是我试图运行一个包含 7 个不同列的案例,这些列可以有不同类型的数据(字符串、日期、数字),具体取决于 id。

这意味着在某些 id 下,列中的行将是字符串,而在其他 id 下,列中的行将是数字。

我意识到这不是结构化数据库的传统用法,但这个特定的表服务于特定的目的,而这种方法在过去被认为是有用的。

当列确实有数字时,案例应该只选择“then”。但是,当我运行它时,我得到一个无效的号码 ORA-01722。因为其中之一,行将包含一个字符串 og 日期。

我意识到这是正确的,因为 oracle 在执行之前会评估 sql,并且不会按顺序执行,因此即使它实际上必须在给定 ID 下的列上进行计算,也会在这些列上给出错误。

我试图执行的代码如下,“then”之前的硬编码 1 和 2 将根据 ctrl_id(唯一 id)而改变,它将是我们只查看和 list_val 列/行的保护一个数字

WITH sampledata1 AS
 (SELECT '1' ctrl_id, '23' list_val1, 'Textfield' list_val2
    FROM dual),
sampledata2 AS
 (SELECT '2' ctrl_id, 'Textfield' list_val1, '45' list_val2
    FROM dual),
sampledata3 AS
 (SELECT *
    FROM sampledata1
  UNION
  SELECT *
    FROM sampledata2)
SELECT CASE
          WHEN ctrl_id = 1 THEN
           AVG(list_val1)
           over(PARTITION BY qd.ctrl_id ORDER BY qd.ctrl_id ASC)
          WHEN ctrl_id = 2 THEN
           AVG(list_val2)
           over(PARTITION BY qd.ctrl_id ORDER BY qd.ctrl_id ASC)
        END AS avg_val
  FROM sampledata3 qd

任何关于我如何使这项工作的建议。解决方法或不同的方法?

提前致谢。

--------- 下面的解决方案

我使用了下面发布的一些建议和解决方案,并让这段代码正常工作。我会尝试用系统来实现它。谢谢大家的帮助,你让我很头疼。

 WITH sampledata1
     AS (SELECT '1' ctrl_id, '23' list_val1, 'Textfield' list_val2 FROM DUAL),
     sampledata2
     AS (SELECT '2' ctrl_id, 'Textfield' list_val1, '45' list_val2 FROM DUAL),
     sampledata3
     AS (SELECT * FROM sampledata1
         UNION
         SELECT * FROM sampledata2)
 select ctrl_id,
 avg(CASE WHEN TRIM(TRANSLATE(list_val1, ' +-.0123456789', ' ')) is null 
 then list_val1 else null end) over(PARTITION BY qd.ctrl_id ORDER BY qd.ctrl_id ASC) list_val1,
    avg(CASE WHEN TRIM(TRANSLATE(list_val2, ' +-.0123456789', ' ')) is null 
 then list_val2 else null end) over(PARTITION BY qd.ctrl_id ORDER BY qd.ctrl_id ASC) list_val2
       
            from   sampledata3 qd

【问题讨论】:

  • 样本数据和期望的结果真的很有帮助。
  • 请提供一个minimal reproducible example,包括您的表的 DDL 语句(尤其是因为您有多种数据类型)和一些说明问题的示例数据以及您对该示例数据的预期输出。此外,请提供完整的查询,因为您只有一个 sn-p 并且 de 别名似乎未定义,因此无法复制您的问题。
  • 对不起,我添加了一个示例代码。
  • 我已将代码替换为具有完全相同问题的示例代码,并给出相同的错误,它可在任何 oracle 数据库上运行。如果存在“双重”功能,也许还有其他人。
  • @EclecticFish 聚合函数,如 AVG 不适用于 VARCHAR 数据类型,NUMBERINTEGER 在使用此类函数时是必须的。

标签: sql oracle case


【解决方案1】:

aggregate function 之类的 AVG 不适用于 VARCHAR 数据类型,NUMBERINTEGER 在使用此类函数时是必须的。

我已将查询修改为使用数字而不是字符串,

WITH sampledata1
     AS (SELECT '1' ctrl_id, '23' list_val1, '43' list_val2 FROM DUAL),
     sampledata2
     AS (SELECT '2' ctrl_id, '34' list_val1, '45' list_val2 FROM DUAL),
     sampledata3
     AS (SELECT * FROM sampledata1
         UNION
         SELECT * FROM sampledata2)
SELECT CASE
          WHEN ctrl_id = 1
          THEN
             AVG (list_val1)
                OVER (PARTITION BY qd.ctrl_id ORDER BY qd.ctrl_id ASC)
          WHEN ctrl_id = 2
          THEN
             AVG (list_val2)
                OVER (PARTITION BY qd.ctrl_id ORDER BY qd.ctrl_id ASC)
       END
          AS avg_val
  FROM sampledata3 qd

输出是

  AVG_VAL
----------
        23
        45

编辑 1

也许您可以执行以下操作来首先确定行返回 NUMERIC 还是 NON-NUMERIC。

根据您的要求进行更改。

WITH sampledata1
     AS (SELECT '1' ctrl_id, '23' list_val1, 'Textfield' list_val2 FROM DUAL),
     sampledata2
     AS (SELECT '2' ctrl_id, 'Textfield' list_val1, '45' list_val2 FROM DUAL),
     sampledata3
     AS (SELECT * FROM sampledata1
         UNION
         SELECT * FROM sampledata2),
     sampledata4
     AS (SELECT LENGTH (TRIM (TRANSLATE (ctrl_id, ' +-.0123456789', ' ')))
                   ctrl_id,
                LENGTH (TRIM (TRANSLATE (list_val1, ' +-.0123456789', ' ')))
                   list_val1,
                LENGTH (TRIM (TRANSLATE (list_val2, ' +-.0123456789', ' ')))
                   list_val2
           FROM sampledata3 qd                   --           group by ctrl_id
                              )
(  SELECT CASE WHEN ctrl_id IS NULL THEN AVG (ctrl_id) ELSE 0 END ctrl_id,
          CASE WHEN list_val1 IS NULL THEN AVG (list_val1) ELSE 0 END list_val1,
          CASE WHEN list_val2 IS NULL THEN AVG (list_val2) ELSE 0 END list_val2
     FROM sampledata4
 GROUP BY ctrl_id, list_val1, list_val2)

【讨论】:

  • 这个版本几乎可以工作,但它只显示了文本字段的长度 (9),但是这与其他一些答案相结合解决了我的问题。非常感谢您的时间:)。我会将解决方案添加到我原来的问题中。
  • @EclecticFish 很高兴知道问题已解决。
【解决方案2】:

不确定您为什么要使用该分析功能。对于您的基本问题,这将起作用:

SELECT AVG(CASE
              WHEN ctrl_id = 1 THEN list_val1
              WHEN ctrl_id = 2 THEN list_val2
            END) AS avg_val
FROM sampledata3 qd

【讨论】:

    【解决方案3】:

    您正在尝试获取 list_val1 的平均总和,但是 list_val1 来自 sampledata2 查询返回 VARCHAR 值。

    您不应该对非数字值使用 AVG。

    WITH sampledata1 AS
     (SELECT '1' ctrl_id, '23' list_val1, '10' list_val2
        FROM dual),
    sampledata2 AS
     (SELECT '2' ctrl_id, '45' list_vall, '90' list_val2
        FROM dual),
    sampledata3 AS
     (SELECT *
        FROM sampledata1
      UNION
      SELECT *
        FROM sampledata2)
    SELECT CASE
              WHEN ctrl_id = 1 THEN
               AVG(list_val1)
               over(PARTITION BY qd.ctrl_id ORDER BY qd.ctrl_id ASC)
              WHEN ctrl_id = 2 THEN
               AVG(list_val2)
               over(PARTITION BY qd.ctrl_id ORDER BY qd.ctrl_id ASC)
            END AS avg_val
      FROM sampledata3 qd
    

    【讨论】:

      【解决方案4】:

      您可以尝试过滤掉带有非数字符号的值,例如

      AVG(CASE WHEN TRIM(TRANSLATE(list_val1, ' +-.0123456789', ' ')) is null then list_val1 else null end) OVER (...)
      

      注意!不幸的是,像 '+12-.3' 这样的字符串也会被识别为数字,在这种情况下,您将得到相同的 ora-01722

      【讨论】:

      • 将此用于佐证另一个答案并使代码正常工作。非常感谢您的回答:)
      猜你喜欢
      • 1970-01-01
      • 2013-01-02
      • 2018-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-26
      • 1970-01-01
      相关资源
      最近更新 更多