Подзапрос с одной строкой возвращает более одной строки - в поисках объяснения / решения - PullRequest
0 голосов
/ 03 апреля 2019

Длинный пост здесь ... Готовьтесь ...

Я создал следующие 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')

Если вы видите какие-либо проблемы с моим кодом или у вас есть способ улучшить его, я открыт для ушей!

-------------------- EDIT -------------------------

Благодаря @GMB у меня правильный рабочий запрос. Сейчас я сталкиваюсь с проблемой, когда у меня два одинаковых условия КОГДА.

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). Какие у меня есть варианты? Я собирался сделать вложенный случай, но я столкнулся с той же проблемой. Я мог бы сделать отдельный запрос, который выполняется после этого, который рассматривает только последний набор условий. Мне просто интересно, если это можно сделать в рамках того же запроса. Это действительно зависит от значения TL.LOC_DESC.

Ответы [ 2 ]

1 голос
/ 04 апреля 2019

Вам нужна какая-то логика, чтобы ограничить количество записей, возвращаемых подзапросом, до одной.

В первом подзапросе (который был частью вашей первой версии запроса) это обеспечивается с помощью агрегации без предложения 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, может быть перемещен в состояние NOT EXISTS в соответствующей части WHEN оператора CASE.

Третий подзапрос можно исправить с помощью агрегации.

Рассмотрим:

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'
0 голосов
/ 03 апреля 2019

Возвращает ли последний случай в вашем проблемном запросе (указанном ниже) более одной строки? Это не должно Если эта строка возвращает более одной строки, запрос не будет выполнен.

SELECT SERVICE_DATE_IN 
                        FROM TRANSLOG TL
                        WHERE P.EQNO = TL.ITEMNO AND
                        TL.LOC_DESC = 'E-OUT OF SERVICE'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...