SQL Server CASE WHEN 不使用 CASE WHEN

发布于 2024-08-10 08:43:52 字数 1910 浏览 5 评论 0原文

有没有办法重写使用 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 的方法很接近)。帕斯卡创建函数的建议将遵循相同的思路,但可能会破坏解析。

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

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

  • 使用带有 CASE WHEN 的 select;
  • 使用 CTE(再次,richardtallent);
  • 使用 Union All (HLGEM);
  • 使用子查询 (MisterZimbu);

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

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

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

Is there a way to rewrite a Transact SQL statement that uses a CASE WHEN structure to do the same without using the CASE WHEN?

I'm using a product that has a built-in query designer and its own pseudo-SQL. It has limitations on what I can use with SQL Server and Oracle. So I have this column that, when the underlying database is Oracle, uses DECODE (which is supported). However, I need to make it work with SQL Server and CASE WHEN is not supported.

The statement I'm trying to convert is something like

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')

I have a limited set of T-SQL options to use and CASE WHEN is not an option. I do have IsNull and Coalesce, but I'm not sure if they will help me with this one.

Don't bother with the date calculations, those are solved.

I searched the CASE WHEN questions here, to no avail.

Thanks!

Update:

I realize that I should have given more details on the reason for the limitations, as this is a developer's resource and it would be assumed that this is a development product. It is not.

I'm using an enterprise software product that has a built-in query designer and its own pseudo-SQL. It has limitations on what I can use with SQL Server and Oracle. Basically, everything that doesn't break the parsing of the built-in query engine is game. That means all the sanctioned functions and expressions, plus all the data abstractions (internal objects that correspond to a physical table in a database and other queries created with the product), plus everything from Oracle SQL or Transact SQL that does not explicitly break the parsing.

The reason why CASE WHEN doesn't work for me is that it breaks the parsing of the pseudo-SQL by the query engine.

Ultimately, I would like to try to:

  1. Use only the product's query
    designer the SQL that passes the
    parsing OR
  2. Use a few extra resources from
    the SQL Server database and the
    query designer to get it done.

Based on the several good answers that I got, here's the approach that worked out for me, so far.

Jason DeFontes suggested that I could use a database view to perform the CASE WHEN rules and that falls into #2 above. It works for me because a view is dynamic enough that I don't have to do maintenance on it (as opposed to richartallent's truth tables approach, which I believe are close to Jason's approach). Pascal's suggestion of creating a function would go along the same lines, but probably break the parse.

So I created a database view that does all the transformation with CASE WHEN and I added it to my query's SQL, joined it with the existing SQL and it worked just fine. I realize that I'm probably adding an overhead to the database engine, as it will have to retrieve the same data set twice (one for the view and one for the query), but it's one of those cases where it's hardly an issue.

Given that this "use a view to obfuscate it" design works for me, I wonder what would be the more efficient approach:

  • Using a select with CASE WHEN;
  • Using CTE (again, richardtallent);
  • Using Union All (HLGEM);
  • Using Subqueries (MisterZimbu);

I will still check Aramis wyler's suggestion, as it could probably fall into #1 above.

For now, Jason's answer was accepted. Considering that I used CASE WHEN in the view, perhaps the title for the question ended up being is ill-chosen. I upped everybody that suggested something that helped in the process. I don't know if that makes a difference in your reputation or not, but I thought it was the nice thing to do.

Again, I want to thank you all for your help and ask you kindly to edit anything on the question that you fell is not appropriate (it's my first question and English is my second language).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

零崎曲识 2024-08-17 08:43:52

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

Do you have union all available? Perhaps you could write a query for each of the conditions with the condition of the case inthe where clause and union them together.

他是夢罘是命 2024-08-17 08:43:52

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

Can you move the CASE/WHEN logic into a view, then have the tool query the view?

眸中客 2024-08-17 08:43:52

你能编写自定义子查询吗?如果您甚至无法访问 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>

Can you write custom subqueries? Probably not if you don't even have access to CASE WHEN, but this would probably work too:

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>
孤蝉 2024-08-17 08:43:52

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

Write a function which performs the computation using CASE WHEN.

寄居人 2024-08-17 08:43:52

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

从表名中选择“PastDue”,其中 Now() > TargetDateColumn 和(StatusColumn = '值 1' 或 StatusColumn = '值 2' 或 StatusColumn = '值 3')
union select 'Outstanding' 其中 Now() < TargetDateColumn 和(StatusColumn = '值 1' 或 StatusColumn = '值 2' 或 StatusColumn = '值 3')
union select '值 4',其中 NOT(StatusColumn = '值 1' 或 StatusColumn = '值 2' 或 StatusColumn = '值 3')

It's ugly and depending on the number of values you have it may not be viable. But strictly speaking, I think something like this would work as a translation from the above query segment:

select 'PastDue' from tablename where Now() > TargetDateColumn and (StatusColumn = 'Value 1' or StatusColumn = 'Value 2' or StatusColumn = 'Value 3')
union select 'Outstanding' where Now() < TargetDateColumn and (StatusColumn = 'Value 1' or StatusColumn = 'Value 2' or StatusColumn = 'Value 3')
union select 'Value 4' where NOT (StatusColumn = 'Value 1' or StatusColumn = 'Value 2' or StatusColumn = 'Value 3')

王权女流氓 2024-08-17 08:43:52

我不太确定我理解你的代码,但这应该会给你一个不同方法的想法。

首先,创建一个表:

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

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

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)

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

I'm not exactly sure I understand your code, but this should give you an idea for a different approach.

First, create a table:

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

Now, populate it with a truth table (lots of repeated logic in here apparently, maybe this should be two truth tables with a CROSS JOIN between them):

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')

Finally, join and provide a default answer:

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

One key advantage to this approach is it puts the business logic in data tables, not code, which is often more maintainable and extensible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文