SQL Server CASE WHEN不使用CASE WHEN

时间:2009-11-05 18:03:12

标签: sql-server tsql case-when

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

我正在使用具有内置查询设计器和自己的伪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,但我不确定他们是否会帮我这个。

不要打扰日期计算,这些都已经解决了。

我在这里搜索了案例,但无济于事。

谢谢!

更新

我意识到我应该提供有关限制原因的更多细节,因为这是开发人员的资源,并且可以假设这是一个开发产品。事实并非如此。

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

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

最终,我想尝试:

  1. 仅使用产品的查询 设计师通过的SQL 解析OR
  2. 使用一些额外的资源 SQL Server数据库和 查询设计师完成它。
  3. 根据我得到的几个好答案,到目前为止,这是我的方法。

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

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

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

    • 使用CASE WHEN时选择;
    • 使用CTE(再次,richardtallent);
    • 使用Union All(HLGEM);
    • 使用子查询(MisterZimbu);

    我仍然会检查Aramis wyler的建议,因为它可能会落入上面的#1。

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

    再一次,我想感谢大家的帮助,并请你好好修改一下你不合适的问题(这是我的第一个问题,英语是我的第二语言)。

6 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分: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>

答案 2 :(得分:3)

您可以将CASE / WHEN逻辑移动到视图中,然后让工具查询视图吗?

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

从tablename中选择'PastDue',其中Now()&gt; TargetDateColumn和(StatusColumn ='Value 1'或StatusColumn ='Value 2'或StatusColumn ='Value 3')   union选择'Outstanding',其中Now()&lt; TargetDateColumn和(StatusColumn ='Value 1'或StatusColumn ='Value 2'或StatusColumn ='Value 3')   union选择'Value 4',其中NOT(StatusColumn ='Value 1'或StatusColumn ='Value 2'或StatusColumn ='Value 3')

答案 5 :(得分:1)

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

首先,创建一个表:

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)

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