【问题标题】:SQL: Return Expressions from SQL CASE statementSQL:从 SQL CASE 语句返回表达式
【发布时间】:2014-02-04 10:51:46
【问题描述】:

在此先感谢,我使用的是 oracle 10g。在 SQL case 语句中,我们传递值并根据值检查大小写并返回字符串。但我不想返回字符串,而是返回一个表达式。这是否可以使用 oracle SQL 查询 CASE 语句返回表达式?我执行以下操作,oracle 生成错误ORA-00905:Missing Keyword

SELECT ECL_CONTROL,
  CASE 
    WHEN ECL_CONTROL = 'N' THEN ('##0') = ('##0')
    WHEN ECL_CONTROL = 'Y' THEN (NVL(IL.ECL, 'X') = NVL(IM.ECL, 'X'))
  END
FROM ITEM_CONTROL WHERE ITEM_NO =  '2N2907A' 

但以下运行成功:

SELECT ECL_CONTROL,
  CASE 
    WHEN ECL_CONTROL = 'N' THEN 'test'
    WHEN ECL_CONTROL = 'Y' THEN 'demo'
  END
FROM ITEM_CONTROL WHERE ITEM_NO =  '2N2907A'

我想使用这个查询作为内部查询和外部查询的返回和表达式。我的查询如下:

SELECT  LSM.ACTIVE_FLAG, LSM.ITEM_NO, IL.ECL, LSM.SERIAL_NO, IL.WAREHOUSE, IL.BIN, LSM.TOOL_STATUS_CODE,
LLG.NEXT_CAL_DATE, IM.PRODUCT_GROUP
FROM LS_SERIAL_MASTER LSM, LS_LIFE_LOG LLG, ITEM_LOCATION IL, ITEM_MASTER IM
WHERE   IL.PLANT = IM.PLANT AND IL.ITEM_NO = IM.ITEM_NO 
AND IM.PLANT = LSM.PLANT AND IM.ITEM_NO = LSM.ITEM_NO AND NVL(IM.PRODUCT_GROUP, 'X') =    NVL('PUMP', 'X')
AND LSM.PLANT = LLG.PLANT AND LSM.ITEM_NO = LLG.ITEM_NO AND LSM.SERIAL_NO = LLG.SERIAL_NO
AND LSM.LIFE_TRANS_ID = LLG.TRANS_ID AND LLG.SERIAL_NO = IL.SERIAL_NO
AND (SELECT ECL_CONTROL,
  CASE ECL_CONTROL
    WHEN ECL_CONTROL = 'N' THEN ('##0' = '##0')
    WHEN ECL_CONTROL = 'Y' THEN (NVL(IL.ECL, 'X') = NVL(IM.ECL, 'X'))
  END AS ECL_CONTROL_TXT
  FROM ITEM_CONTROL WHERE ITEM_NO =  '2N2907A')
AND LLG.MAINT_LMT_ID IN('T', 'U')
AND LLG.NEXT_CAL_DATE BETWEEN TO_DATE('02/1/2014', 'MM/DD/YYYY') AND TO_DATE('02/11/2014', 'MM/DD/YYYY').

我的实际任务是从内部查询返回一个表达式并在外部查询中使用。

【问题讨论】:

  • 原因是,THEN 子句用于返回一个值,而不是用于比较值。在THEN 子句中返回的值不能使用任何运算符
  • 不,这是不可能的。您试图将表达式作为没有意义的结果集的一部分返回;你会怎么处理结果?你真的想返回##0 还是NVL(IL.ECL, 'X') 的值,这样就可以了?
  • ECL_CONTROL 列包含标志值'Y'或'N',如果值为'Y'我想返回NVL(IL.ECL, 'X') = NVL(IM.ECL, 'X') 如果值为'N'则返回值为('##0') = ('##0') .此查询充当内部查询,在内部查询中,这些返回语句返回 where 条件的表达式。
  • ILIM 是别名或外部查询表。如果标志是'N'所以,我们只需要外部查询Y中的true表达式,那么我需要添加另一个表达式。

标签: sql database oracle10g case


【解决方案1】:

不,您展示的内容是不可能的。在select 中有一个表达式真的没有意义。你可以have an expression evaluated instead of using a fixed string:

SELECT ECL_CONTROL,
  CASE 
    WHEN ECL_CONTROL = 'N' THEN '##0'
    WHEN ECL_CONTROL = 'Y' THEN NVL(IL.ECL, 'X')
  END
FROM ITEM_CONTROL WHERE ITEM_NO =  '2N2907A' 

但是你不能返回实际的表达式。在您显示的代码中,第一个表达式总是会评估为 true 无论如何(并且布尔值也不存在于普通 SQL 中),所以我认为这可能是您的实际意图,您对如何分配感到困惑表达式值。你还没有显示ILIM 的来源,所以很难说清楚你想要什么。

您可以在where 子句中直接使用case

SELECT ...
FROM IM, IL, ITEM_CONTROL -- joined in some way
WHERE CASE 
    WHEN ECL_CONTROL = 'N' THEN '##0'
    WHEN ECL_CONTROL = 'Y' THEN NVL(IL.ECL, 'X')
  END = CASE 
    WHEN ECL_CONTROL = 'N' THEN '##0'
    WHEN ECL_CONTROL = 'Y' THEN NVL(IM.ECL, 'X')
  END

虽然这可能更清楚:

WHERE ECL_CONTROL = 'N' OR NVL(IL.ECL, 'X') = NVL(IM.ECL, 'X')

从您添加的更大查询中:

SELECT LSM.ACTIVE_FLAG, LSM.ITEM_NO, IL.ECL, LSM.SERIAL_NO, IL.WAREHOUSE,
  IL.BIN, LSM.TOOL_STATUS_CODE, LLG.NEXT_CAL_DATE, IM.PRODUCT_GROUP
FROM LS_SERIAL_MASTER LSM, LS_LIFE_LOG LLG, ITEM_LOCATION IL, ITEM_MASTER IM
WHERE IL.PLANT = IM.PLANT AND IL.ITEM_NO = IM.ITEM_NO 
AND IM.PLANT = LSM.PLANT AND IM.ITEM_NO = LSM.ITEM_NO
AND NVL(IM.PRODUCT_GROUP, 'X') = NVL('PUMP', 'X')
AND LSM.PLANT = LLG.PLANT AND LSM.ITEM_NO = LLG.ITEM_NO
AND LSM.SERIAL_NO = LLG.SERIAL_NO
AND LSM.LIFE_TRANS_ID = LLG.TRANS_ID AND LLG.SERIAL_NO = IL.SERIAL_NO
AND LLG.MAINT_LMT_ID IN('T', 'U')
AND LLG.NEXT_CAL_DATE BETWEEN TO_DATE('02/1/2014', 'MM/DD/YYYY')
  AND TO_DATE('02/11/2014', 'MM/DD/YYYY')
AND ((SELECT ECL_CONTROL FROM ITEM_CONTROL WHERE ITEM_NO = '2N2907A') = 'N'
  OR NVL(IL.ECL, 'X') = NVL(IM.ECL, 'X'))

...虽然由于子查询正在寻找单行 - 具有固定的item_no 与您在其他表中引用的具有相同名称的其他列相关 - 您可以只在主查询中包含该表.

无论如何。顺便说一句,使用显式连接会更清楚;而是超出了问题的范围,但接受您的评论,即item_no 实际上是相关的,例如:

SELECT LSM.ACTIVE_FLAG, LSM.ITEM_NO, IL.ECL, LSM.SERIAL_NO, IL.WAREHOUSE,
  IL.BIN, LSM.TOOL_STATUS_CODE, LLG.NEXT_CAL_DATE, IM.PRODUCT_GROUP
FROM LS_LIFE_LOG LLG
JOIN LS_SERIAL_MASTER LSM ON LSM.PLANT = LLG.PLANT
  AND LSM.ITEM_NO = LLG.ITEM_NO
  AND LSM.SERIAL_NO = LLG.SERIAL_NO
  AND LSM.LIFE_TRANS_ID = LLG.TRANS_ID
JOIN ITEM_CONTROL IC ON IC.ITEM_NO = LSM.ITEM_NO
JOIN ITEM_MASTER IM ON IM.PLANT = LSM.PLANT
  AND IM.ITEM_NO = IC.ITEM_NO
JOIN ITEM_LOCATION IL ON IL.PLANT = IM.PLANT
  AND IL.ITEM_NO = IM.ITEM_NO
  AND IL.SERIAL_NO = LLG.SERIAL_NO
  AND (IC.ECL_CONTROL = 'N' OR NVL(IL.ECL, 'X') = NVL(IM.ECL, 'X'))
WHERE LLG.MAINT_LMT_ID IN ('T', 'U')
AND LLG.NEXT_CAL_DATE BETWEEN TO_DATE('02/1/2014', 'MM/DD/YYYY')
  AND TO_DATE('02/11/2014', 'MM/DD/YYYY')
AND NVL(IM.PRODUCT_GROUP, 'X') = NVL('PUMP', 'X')

NVL('PUMP', 'X') 虽然没有意义 - NVL() 在固定值附近毫无意义。也许你的意思不是AND NVL(IM.PRODUCT_GROUP, 'X') = NVL('PUMP', 'X'),而是AND (IM.PRODUCT_GROUP IS NULL OR IM.PRODUCT_GROUP = 'PUMP')

【讨论】:

  • 抱歉 ILIM 混淆了,实际上这些是外部查询表的别名。
  • @HarmeetSingh - 你的问题的答案是“不”;如果您需要帮助实现更广泛的目标,您需要在问题中提供更多上下文,展示如何使用该表达式。尽管我认为我所展示的内容可能会为您指明正确的方向。 case 在这里可能不是正确的工具。但如果没有我猜测的其余查询的上下文。
  • 好的,@Alex Poole,我描述了我的问题。
  • 感谢您给我解决方案,但我的ITEM_NO 不是固定的,它来自外部查询,当我们使用((SELECT ECL_CONTROL FROM ITEM_CONTROL WHERE ITEM_NO = '2N2907A') = 'N' OR NVL(IL.ECL, 'X') = NVL(IM.ECL, 'X')) 时,它包含两个表达式,.但我只需要一个表达式取决于外部查询中的YN 值,因为如果值为N,则不需要此表达式。再次感谢亚历克斯。
  • 嘿@Alex 谢谢你,但我想确认一下,在 oracle 10g sql 中,OR 运算符是短路的?
猜你喜欢
  • 2021-12-27
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 2012-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多