【问题标题】:Special LEFT JOIN特殊的 LEFT JOIN
【发布时间】:2019-06-04 08:32:41
【问题描述】:

我有以下 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;

【问题讨论】:

  • 请不要发布无效代码作为描述,它没有任何意义。特别是“如果条件则加入”。用文字来解释。给出为相关部分运行的代码。请在代码问题中提供minimal reproducible example--cut & paste & runnable code;具有期望和实际输出的示例输入(包括逐字错误消息);标签和明确的规范和解释。这包括您可以提供的最少代码,即您显示的代码可以通过您显示的代码扩展为不正常。 (调试基础。)

标签: sql join left-join impala


【解决方案1】:

这基本上是使用默认值。我认为这可以满足您的要求:

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 JOINs。

【讨论】:

  • 比使用 subquery 要好得多。一个小缺点是一个字段 op.IdealValue、opnull.IdealValue 有两个值
  • 我使用您的确切代码得到了这个错误,但设法修复它!我不得不将 NVL-s 保留在已经使用过的地方。谢谢! AnalysisException:操作数 'coalesce(op.MaxValue, opnull.MaxValue)' 部分谓词 'cd.CycleTime >= coalesce(op.IdealValue, opnull.IdealValue) AND coalesce(op.MaxValue, opnull.MaxValue)' 应该返回类型 ' BOOLEAN' 但返回类型 'INT'。
【解决方案2】:

为整个实体设置默认值有点棘手,但对于字段列表,它可能会像这样实现:

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

【讨论】:

  • 是的,但这不是我要找的。我尝试了 IsNull(op.IdealValue, SELECT IdealValue FROM Operation_parameter WHERE ProductId IS NULL AND cd.Timestamp_ BETWEEN ValidFrom AND ValidTo LIMIT 1) 和类似的东西,但无论哪种方式 cd 都没有定义,我必须做同样的 LEFT JOIN 并返回原始问题,或者如果我使用另一个表省略了该部分,我会收到一条错误消息,指出 IsNull() 不能包含子查询作为参数。我什至尝试在 IsNull() 内部不使用子查询,但在外部使用 WITh 子句并引用它,但仍然存在相同的 JOIN 问题。
  • ISNull(op.IdealValue ,(SELECT op2.IdealValue FROM Operation_parameter as op2 WHERE ProductId IS NULL AND cd.Timestamp_ BETWEEN op2.ValidFrom AND op2.ValidTo LIMIT 1)) as IdealValue - 这个子查询应该可以工作您可以在其中使用 cd 表中的值
  • AnalysisException: 第 30 行中的语法错误:undefined: ...e >= ISNull(op.IdealValue,SELECT op2.IdealValue FROM O... ^ 遇到:SELECT Expected: CASE, CAST, DEFAULT , EXISTS, FALSE, IF, INTERVAL, LEFT, NOT, NULL, REPLACE, RIGHT, TRUNCATE, TRUE, IDENTIFIER 引起:异常:语法错误
  • 我现在对子查询进行了一些调整。它还需要在 select 附近加上圆括号
猜你喜欢
  • 1970-01-01
  • 2010-09-29
  • 1970-01-01
  • 2015-07-14
  • 2011-10-13
  • 1970-01-01
  • 2014-08-10
  • 2017-02-06
相关资源
最近更新 更多