Специальное левое соединение - PullRequest
0 голосов
/ 04 июня 2019

У меня есть следующий псевдо-запрос SQL (Impala), так как он не будет компилироваться таким образом. Интересная часть - последняя, ​​где я хочу делать именно то, что вы можете прочитать.

Я хочу сделать LEFT JOIN, но в случае отсутствия соответствующего ProductId, я хочу использовать конкретный ProductId (который имеет значение NULL и предположим, что есть только один, но гарантирует его с помощью LIMIT 1) и выполнить соединение, подобное JOIN поэтому вышеприведенные условия в CASE-WHEN будут работать правильно.

Таким образом, в основном вопрос заключается в том, есть ли способ преобразовать этот синтаксически некорректный запрос в один правильный?

Я пробовал разные вещи, например, ISNULL () и WITH, но поскольку подзапрос, который вы видите в части ELSE, должен использовать 2 таблицы для правильной работы, он не может быть скомпилирован в любом случае, на мой взгляд, он будет работать.

SELECT 
    cd.CycleDataId AS CycleDataId,
    CASE   
        WHEN cd.CycleTime >= op.IdealValue AND cd.CycleTime <= op.MaxValue THEN NVL(dcl.ProductionLossTypeId, -1)
        WHEN cd.CycleTime >= op.IdealValue AND cd.CycleTime >= op.MaxValue THEN dcl.ProductionLossTypeId
    END AS Verdikt,
    CASE   
        WHEN cd.CycleTime >= op.IdealValue AND cd.CycleTime <= op.MaxValue THEN NVL(dcl.Time, cd.CycleTime - op.IdealValue)
        WHEN cd.CycleTime >= op.IdealValue AND cd.CycleTime >= op.MaxValue THEN dcl.Time  
    END AS Time
FROM CycleData cd
LEFT JOIN DistributedCycleLosses dcl ON dcl.CycleDataId = cd.CycleDataId
CASE   
WHEN IF EXISTS(SELECT * FROM Operation_parameter WHERE ProductId = cd.ProductId AND cd.Timestamp_ BETWEEN ValidFrom AND ValidTo) THEN LEFT JOIN Operation_parameter op ON op.ProductId = cd.ProductId AND cd.Timestamp_ BETWEEN op.ValidFrom AND op.ValidTo
ELSE (SELECT * FROM Operation_parameter WHERE ProductId IS NULL AND cd.Timestamp_ BETWEEN ValidFrom AND ValidTo LIMIT 1) AS op
END;

Ответы [ 2 ]

1 голос
/ 04 июня 2019

В основном используется значение по умолчанию.Я думаю, что это то, что вы хотите:

SELECT cd.CycleDataId AS CycleDataId,
        (CASE WHEN cd.CycleTime >= COALESCE(op.IdealValue, opnull.IdealValue) AND 
                   cd.CycleTime <= COALESCE(op.MaxValue, opnull.MaxValue) 
              THEN COALESCE(dcl.ProductionLossTypeId, -1)
              WHEN cd.CycleTime >= COALESCE(op.IdealValue, opnull.IdealValue) AND
                   COALESCE(op.MaxValue, opnull.MaxValue)
              THEN dcl.ProductionLossTypeId
         END) AS Verdikt,
        (CASE WHEN cd.CycleTime >= COALESCE(op.IdealValue, opnull.IdealValue) AND
                   cd.CycleTime <= COALESCE(op.MaxValue, opnull.MaxValue)
              THEN cd.CycleTime >= COALESCE(dcl.Time, cd.CycleTime - COALESCE(op.IdealValue, opnull.IdealValue))
              WHEN cd.CycleTime >= COALESCE(op.IdealValue, opnull.IdealValue) AND
                   cd.CycleTime >= COALESCE(op.MaxValue, opnull.MaxValue)
              THEN dcl.Time  
         END) AS Time
FROM CycleData cd LEFT JOIN 
     DistributedCycleLosses dcl
     ON dcl.CycleDataId = cd.CycleDataId LEFT JOIN
     Operation_parameter op
     ON op.ProductId = cd.ProductId AND
        cd.Timestamp_ BETWEEN op.ValidFrom AND op.ValidTo LEFT JOIN
     Operation_parameter opnull
     ON op.ProductId IS NULL AND  -- no previous match
        opnull.ProductID IS NULL AND
        cd.Timestamp_ BETWEEN opnull.ValidFrom AND opnull.ValidTo ;

Обратите внимание, что все ссылки на op заменены на COALESCE() выражений.

Вы можете изменить это для обработки нескольких строк для сопоставления NULL значений, если это действительно необходимо.Я думаю, что более важной частью логики являются LEFT JOIN s.

0 голосов
/ 04 июня 2019

это немного сложно установить значение по умолчанию для всей сущности, но для списка полей это может быть реализовано так:

SELECT 
    cd.CycleDataId AS CycleDataId, ISNull(op.[parameterName],'default parameter value') as [parameterName]
    CASE   
        WHEN cd.CycleTime >= op.IdealValue AND cd.CycleTime <= op.MaxValue THEN NVL(dcl.ProductionLossTypeId, -1)
        WHEN cd.CycleTime >= op.IdealValue AND cd.CycleTime >= op.MaxValue THEN dcl.ProductionLossTypeId
    END AS Verdikt,
    CASE   
        WHEN cd.CycleTime >= op.IdealValue AND cd.CycleTime <= op.MaxValue THEN NVL(dcl.Time, cd.CycleTime - op.IdealValue)
        WHEN cd.CycleTime >= op.IdealValue AND cd.CycleTime >= op.MaxValue THEN dcl.Time  
    END AS Time
FROM CycleData cd
LEFT JOIN DistributedCycleLosses dcl ON dcl.CycleDataId = cd.CycleDataId,
LEFT JOIN Operation_parameter op ON op.ProductId = cd.ProductId AND cd.Timestamp_ BETWEEN op.ValidFrom AND op.ValidTo
...