【问题标题】:SQL Server CASE WHEN without using CASE WHENSQL Server CASE WHEN 不使用 CASE WHEN
【发布时间】:2009-11-05 18:03:12
【问题描述】:

有没有办法重写使用 CASE WHEN 结构的 Transact SQL 语句来执行相同的操作而不使用 CASE WHEN?

我正在使用具有内置查询设计器和自己的伪 SQL 的产品。它对我可以与 SQL Server 和 Oracle 一起使用的内容有限制。所以我有这个专栏,当底层数据库是 Oracle 时,使用 DECODE(支持)。但是,我需要让它与 SQL Server 一起工作,并且不支持 CASE WHEN。

我要转换的语句类似于

Decode (StatusColumn,  'Value 1',
Decode(Sign(Now()-TargetDateColumn)),1,'Past
Due', 'Outstanding'),  'Value 2',
Decode(Sign(Now()-TargetDateColumn)),1,'Past
Due', 'Outstanding'),  'Value 3',
Decode(Sign(Now()-TargetDateColumn)),1,'Past
Due', 'Outstanding'),  'Value 4')

我有一组有限的 T-SQL 选项可供使用,CASE WHEN 不是一个选项。我确实有 IsNull 和 Coalesce,但我不确定他们是否会帮助我解决这个问题。

不用担心日期计算,这些都解决了。

我在这里搜索了 CASE WHEN 问题,但无济于事。

谢谢!

更新:

我意识到我应该详细说明限制的原因,因为这是开发人员的资源,并且会被假定为开发产品。不是。

我正在使用具有内置查询设计器和自己的伪 SQL 的企业软件产品。它对我可以与 SQL Server 和 Oracle 一起使用的内容有限制。基本上,所有不破坏内置查询引擎解析的东西都是游戏。这意味着所有批准的函数和表达式,加上所有数据抽象(对应于数据库中的物理表的内部对象和使用产品创建的其他查询),加上 Oracle SQL 或 Transact SQL 中没有显式破坏解析的所有内容.

CASE WHEN 对我不起作用的原因是它破坏了查询引擎对伪 SQL 的解析。

最终,我想尝试:

  1. 仅使用产品的查询 设计通过的 SQL 解析或
  2. 使用一些额外的资源 SQL Server 数据库和 查询设计器来完成它。

根据我得到的几个很好的答案,这是迄今为止对我有用的方法。

Jason DeFontes 建议我可以使用数据库视图来执行 CASE WHEN 规则,这属于上面的 #2。它对我有用,因为视图足够动态,我不必对其进行维护(与richartallent 的真值表方法相反,我认为它接近 Jason 的方法)。 Pascal 关于创建函数的建议也是如此,但可能会破坏解析。

所以我创建了一个数据库视图,它使用 CASE WHEN 进行所有转换,并将其添加到查询的 SQL 中,将其与现有 SQL 结合起来,它工作得很好。我意识到我可能会增加数据库引擎的开销,因为它必须检索相同的数据集两次(一次用于视图,一次用于查询),但这是几乎不成问题的情况之一。

鉴于这种“使用视图来混淆它”的设计对我来说很有效,我想知道什么是更有效的方法:

  • 在 CASE WHEN 中使用选择;
  • 使用 CTE(同样,richardtallent);
  • 使用联合所有 (HLGEM);
  • 使用子查询 (MisterZimbu);

我仍然会检查 Aramis wyler 的建议,因为它可能属于上述 #1。

目前,Jason 的回答已被接受。考虑到我在视图中使用了 CASE WHEN,也许问题的标题最终选择不当。我提高了每个人的建议,在这个过程中有所帮助。我不知道这是否会影响您的声誉,但我认为这是一件好事。

再次,我要感谢大家的帮助,并恳请您对您认为不合适的问题进行编辑(这是我的第一个问题,英语是我的第二语言)。

【问题讨论】:

  • 我很好奇.. 为什么你没有使用 Case When 的选项?贵公司有这样的政策吗?!!?除非您有外部强制限制,否则 SQL Server 肯定支持 Case When。
  • 可以,但查询工具可能不支持,将选择结果限制为表达式和函数调用。
  • 这是我们正在开发的产品的限制。正如我所提到的,该产品有一个查询设计器和一个查询引擎以及它自己的 SQL,可以“翻译”/“足够”到 Oracle 或 SQL Server。我怀疑支持 decode 因为它是一个函数,无论我是否被告知 Case-When 不是一个函数,而是一个表达式。由于伪 SQL 定义,我认为 Case-When 会破坏查询引擎的解析。
  • 在不确切知道您的第三方查询生成器的功能的情况下,我不相信您的问题可以得到解答。如果您指定[指定您正在使用的第三方工具,那么也许有该产品经验的人可能会为您提供帮助。
  • 我想检查是否有使用子查询或联合之类的方法或它们的组合。感谢您的帮助。

标签: sql-server tsql case-when


【解决方案1】:

你有工会吗?也许您可以在 where 子句中为每个条件编写一个查询条件,并将它们联合在一起。

【讨论】:

  • +1 好主意(好吧,除了烧掉伪SQL工具)
  • 我试试看。我想你的答案就是我的目标:通过使用基本 SQL 而不是函数来处理这个问题。我将把这个问题留待更多时间,看看是否可以提出其他建议。如果没有,那么我会接受你的回答。谢谢。
  • 我对此表示赞同,但 UNION 确实有两个缺点:(1) 多次运行良好(MSSQL 不会很好地优化这个),以及 (2) 重复代码。可以通过将通用部分移至 CTE 来缓解其中的一些问题,但如果您想避免 CASE,CTE 甚至更加特定于平台。
  • Richard,我同意,但有时您会被要求使用的工具所限制。 union all 在性能上会比 union 更好(因为我们知道不同的查询不会有共同的值),但它可能可用也可能不可用。
  • @richardtallent:我不知道我是否可以将它直接用于我们的查询设计器/引擎,但我将尝试采用不同的方法,这受到 Jason DeFontes 的启发建议。
【解决方案2】:

您能否将 CASE/WHEN 逻辑移动到视图中,然后让工具查询该视图?

【讨论】:

  • 你知道吗?也许我可以!我正在完成其他一些任务,但会尽快开始尝试这些建议。到目前为止,这似乎是一个。查询设计器是有限的,但我可以传递一些东西(不是 CASE-WHEN,但它会破坏解析)。我确实可以尝试这种方法。
【解决方案3】:

您可以编写自定义子查询吗?如果您甚至无法访问 CASE WHEN,则可能不会,但这也可能有效:

select
    ...,
    coalesce(c1.value, c2.value, c3.value, ..., <default value>)
from MyTable
left join (select <result 1> as value) c1 on <first condition>
left join (select <result 2> as value) c2 on <second condition>
left join (select <result 3> as value) c3 on <third condition>

【讨论】:

  • 我也会尝试这个,因为它可能是查询引擎限制的延伸,但它很容易理解并且更接近我想要做的事情。谢谢!
【解决方案4】:

编写一个使用 CASE WHEN 执行计算的函数。

【讨论】:

  • 我现在不能。如果可能的话,我想尝试通过使用我在查询设计器/引擎中可用的东西来解决这个问题。在问这个问题之前,我想了很多,因为我知道它可能会比问题本身吸引更多的注意力。最终,我认为它可能对处于相同情况的其他人有价值。或者至少对类似评估的效率有一些思考。
【解决方案5】:

这很丑陋,并且取决于您拥有的值的数量,它可能不可行。但严格来说,我认为这样的内容可以作为上述查询段的翻译:

从表名中选择“PastDue”,其中 Now() > TargetDateColumn and (StatusColumn = 'Value 1' or StatusColumn = 'Value 2' or StatusColumn = 'Value 3') union select 'Outstanding' where Now()

【讨论】:

    【解决方案6】:

    我不确定我是否理解您的代码,但这应该会让您对不同的方法有所了解。

    首先,创建一个表:

    CREATE TABLE StatusLookup(
       value nvarchar(255),
       datesign shortint,
       result varchar(255));
    

    现在,用真值表填充它(这里显然有很多重复的逻辑,也许这应该是两个真值表,它们之间有一个 CROSS JOIN):

    INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 1', -1, 'Outstanding')
    INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 1', 0, 'Outstanding')
    INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 1', 1, 'Past Due')
    INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 2', -1, 'Outstanding')
    INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 2', 0, 'Outstanding')
    INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 2', 1, 'Past Due')
    INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 3', -1, 'Outstanding')
    INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 3', 0, 'Outstanding')
    INSERT INTO StatusLookup(value, datesign, result) VALUES ('Value 3', 1, 'Past Due')
    

    最后,加入并提供默认答案:

    SELECT mytable.*, COALESCE(statuslookup.result, 'Value 4')
    FROM
        mytable LEFT JOIN statuslookup ON
            statuslookup.value = StatusColumn
            AND statuslookup.datesign = Sign(Now()-TargetDateColumn)
    

    这种方法的一个关键优势是它将业务逻辑放在数据表中,而不是代码中,这通常更易于维护和扩展。

    【讨论】:

    • 您的建议可能会奏效,因为我可以使用查询引擎中的 COALESCE。我偏爱真值表,因为我不想管理它(并不是说这不是一个好主意,因为我以前使用过它,但它增加了一个额外的管理层,这对我不起作用特定情况),但可以做到。谢谢。
    猜你喜欢
    • 2016-07-08
    • 2011-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多