【问题标题】:Single-Row Subquery Returns More Than One Row - Looking For Explination/Solution单行子查询返回多于一行 - 寻找解释/解决方案
【发布时间】:2019-04-03 18:27:50
【问题描述】:

在这里发长文...振作起来...

我创建了以下 4 个每天按顺序运行的查询。创建这些是为了让我的公司能够扫描进出服务的工具,而不是手动输入日期。显示后,调度无法调度使用该工具的作业。只要一个字段为空(SERVICE_DATE_IN),这些功能就可以正常运行并且没有任何问题:

查询 1:扫描出的工具

UPDATE PMEQMT P
   SET SERVICE_DATE_OUT = (SELECT MAX(TL.TRANS_DATE)
                        FROM TRANSLOG TL
                        WHERE P.EQNO = TL.ITEMNO AND
                              TL.LOC_DESC = 'E-OUT OF SERVICE' AND
                              TL.TRANS_DATE >= SYSDATE - 1 AND
                              TL.TRANS_IN_OUT = 'IN'
                       )
WHERE P.CLASS = 'TL' AND
      P.SERVICE_DATE_OUT IS NULL

查询 2:扫描到的工具

UPDATE PMEQMT P
   SET SERVICE_DATE_IN = (SELECT MAX(TL.TRANS_DATE)
                        FROM TRANSLOG TL
                        WHERE P.EQNO = TL.ITEMNO AND 
                              TL.LOC_DESC = 'E-IN SERVICE' AND
                              TL.TRANS_DATE >= SYSDATE - 1 AND
                              TL.TRANS_IN_OUT = 'IN'
                       )
WHERE P.CLASS = 'TL' AND
      P.SERVICE_DATE_IN IS NULL

查询3:擦除服务日期以防未清除

UPDATE PMEQMT
SET SERVICE_DATE_IN = NULL
WHERE SERVICE_DATE_OUT IS NULL AND
  SERVICE_DATE_IN IS NOT NULL AND
  CLASS = 'TL'

查询 4:工具又回来了,出/入日期都为空

UPDATE PMEQMT
SET SERVICE_DATE_OUT = NULL,
SERVICE_DATE_IN = NULL 
WHERE SERVICE_DATE_OUT IS NOT NULL AND
  SERVICE_DATE_IN IS NOT NULL AND
  CLASS = 'TL'

工程部门要求能够手动输入SERVICE_DATE_IN 日期。所以我想出了以下查询:

查询 1:与上面的查询 1 相同

查询 2:这是我的问题查询。目前我收到错误:

ORA-01427: 单行子查询返回多于一行

此查询在我测试时有效,并且仅将一个 P.EQNO(项目)移动到 TL.LOC_DESC(位置)。然后我开始测试将其他P.EQNO(项目)移动到不同的位置,然后开始收到错误。

有人能解释一下这里发生了什么吗?如果您感觉特别好,请帮我修改查询以解决错误?

UPDATE PMEQMT P
   SET SERVICE_DATE_IN =
   CASE 
   WHEN SERVICE_DATE_IN IS NULL THEN (SELECT MAX(TL.TRANS_DATE)
                        FROM TRANSLOG TL
                        WHERE P.EQNO = TL.ITEMNO AND 
                              TL.LOC_DESC = 'E-IN SERVICE' AND
                              TL.TRANS_DATE >= SYSDATE - 1 AND
                              TL.TRANS_IN_OUT = 'IN'
                       )
   WHEN (TRUNC(SERVICE_DATE_IN)) <= (TRUNC(SYSDATE)) THEN (SELECT ((TRUNC(SYSDATE))+1)
                        FROM TRANSLOG TL
                        WHERE P.EQNO = TL.ITEMNO AND
                        TL.LOC_DESC = 'E-OUT OF SERVICE'
                       )
   WHEN (TRUNC(SERVICE_DATE_IN)) > (TRUNC(SYSDATE)) THEN (SELECT SERVICE_DATE_IN 
                        FROM TRANSLOG TL
                        WHERE P.EQNO = TL.ITEMNO AND
                        TL.LOC_DESC = 'E-OUT OF SERVICE'
                       )
   END
WHERE CLASS = 'TL'

问题 3:没有问题

UPDATE PMEQMT P 
SET P.SERVICE_DATE_OUT = NULL, P.SERVICE_DATE_IN = NULL 
WHERE EXISTS (SELECT 1 FROM TRANSLOG TL WHERE TL.ITEMNO = P.EQNO AND TL.LOC_DESC = 'E-IN SERVICE')

如果您发现我的代码有任何问题或有办法改进它,我会保持警惕!

--------编辑-------------

感谢@GMB,我有一个正确的工作查询。我现在遇到了两个相同的 WHEN 条件的问题。

UPDATE PMEQMT P 
SET SERVICE_DATE_IN = CASE 
WHEN SERVICE_DATE_IN IS NULL 
    THEN (
        SELECT MAX(TL.TRANS_DATE)
        FROM TRANSLOG TL
        WHERE 
            P.EQNO = TL.ITEMNO
            AND TL.LOC_DESC = 'E-IN SERVICE' 
            AND TL.TRANS_DATE >= SYSDATE - 1 
            AND TL.TRANS_IN_OUT = 'IN'
    )
WHEN 
    TRUNC(SERVICE_DATE_IN) <= TRUNC(SYSDATE) 
    AND EXISTS (        
        SELECT 1
        FROM TRANSLOG TL
        WHERE 
            P.EQNO = TL.ITEMNO 
            AND TL.LOC_DESC = 'E-OUT OF SERVICE'
    )
    THEN TRUNC(SYSDATE) +1        
WHEN TRUNC(SERVICE_DATE_IN) > TRUNC(SYSDATE) 
    THEN (
        SELECT MAX(SERVICE_DATE_IN)
        FROM TRANSLOG TL
        WHERE 
            P.EQNO = TL.ITEMNO
            AND TL.LOC_DESC = 'E-OUT OF SERVICE'
    )
WHEN TRUNC(SERVICE_DATE_IN) > TRUNC(SYSDATE)
    THEN (
          SELECT MAX(TL.TRANS_DATE)
          FROM TRANSLOG TL
          WHERE 
            P.EQNO = TL.ITEMNO
            AND TL.LOC_DESC = 'E-IN SERVICE' 
            AND TL.TRANS_DATE >= SYSDATE - 1 
            AND TL.TRANS_IN_OUT = 'IN'
    )
  END
WHERE CLASS = 'TL'

我正在测试的记录保留了 MAX(SERVICE_DATE_IN) 数据。我在这里有哪些选择?我打算做一个嵌套的 CASE 但我会遇到同样的问题。我可以做一个单独的查询,在这个查询之后运行,它只查看最后一组条件。我只是想知道是否可以在同一个查询中进行。它实际上取决于 TL.LOC_DESC 值。

【问题讨论】:

    标签: sql oracle sql-update subquery case


    【解决方案1】:

    您需要某种逻辑来将子查询返回的记录数限制为一条。

    在第一个子查询(这是您的第一个版本的查询的一部分)中,这是通过使用不带 GROUP BY 子句的聚合来提供的:

    SET SERVICE_DATE_IN = (
        SELECT MAX(TL.TRANS_DATE)
        FROM TRANSLOG TL
        WHERE 
            P.EQNO = TL.ITEMNO
            AND TL.LOC_DESC = 'E-IN SERVICE'
            AND TL.TRANS_DATE >= SYSDATE - 1
            AND TL.TRANS_IN_OUT = 'IN'
    )
    

    返回值基本上是TRUNC(SYSDATE) +1 的第二个子查询可以移动到CASE 语句的相关WHEN 部分内的NOT EXISTS 条件。

    第三个子查询可以使用聚合来修复。

    考虑:

    UPDATE PMEQMT P 
    SET SERVICE_DATE_IN = CASE 
        WHEN SERVICE_DATE_IN IS NULL 
            THEN (
                SELECT MAX(TL.TRANS_DATE)
                FROM TRANSLOG TL
                WHERE 
                    P.EQNO = TL.ITEMNO
                    AND TL.LOC_DESC = 'E-IN SERVICE' 
                    AND TL.TRANS_DATE >= SYSDATE - 1 
                    AND TL.TRANS_IN_OUT = 'IN'
            )
        WHEN 
            TRUNC(SERVICE_DATE_IN) <= TRUNC(SYSDATE) 
            AND EXISTS (        
                SELECT 1
                FROM TRANSLOG TL
                WHERE 
                    P.EQNO = TL.ITEMNO 
                    AND TL.LOC_DESC = 'E-OUT OF SERVICE'
            )
            THEN TRUNC(SYSDATE) +1        
        WHEN TRUNC(SERVICE_DATE_IN) > TRUNC(SYSDATE 
            THEN (
                SELECT MAX(SERVICE_DATE_IN)
                FROM TRANSLOG TL
                WHERE 
                    P.EQNO = TL.ITEMNO
                    AND TL.LOC_DESC = 'E-OUT OF SERVICE'
            )
       END
    WHERE CLASS = 'TL'
    

    【讨论】:

    • 这个成功了!谢谢!因此,当此查询运行时,它会流经 PMEQMT 表的所有记录,并且当记录满足 when 条件时,它会根据该条件进行更新,然后继续运行直到所有 PMEQMT 记录都运行?在运行上述查询后,我注意到我还有一个 CASE 条件。问题是新的 CASE 条件具有相同的 WHEN 条件。
    【解决方案2】:

    您的问题查询中的最后一个案例(如下所示)是否返回多行?它不应该。如果这一行返回多于一行,则查询将失败。

    SELECT SERVICE_DATE_IN 
                            FROM TRANSLOG TL
                            WHERE P.EQNO = TL.ITEMNO AND
                            TL.LOC_DESC = 'E-OUT OF SERVICE'
    

    【讨论】:

    • 那将是罪魁祸首! Oracle SQL 是否有“跳过”或“无操作”功能?
    猜你喜欢
    • 2016-02-16
    • 2014-08-14
    • 2023-01-23
    • 1970-01-01
    • 2015-03-26
    • 1970-01-01
    • 1970-01-01
    • 2017-11-02
    • 1970-01-01
    相关资源
    最近更新 更多