【问题标题】:I need help converting T-SQL query to Oracle supported query我需要帮助将 T-SQL 查询转换为 Oracle 支持的查询
【发布时间】:2016-04-27 15:48:14
【问题描述】:

我正在 SQL Server 中执行此查询,它工作正常,但是当我尝试在 Oracle 中执行它时,它没有给出相同的结果。

您可以在我附上的照片中看到一位客户的数据,他的代码为 1、2、4、8,他应该得到 0.70 的价值,因为他有代码 1,2,4,然后他应该得到代码 8得到 0.75,所以乘法后它应该返回 0.52 作为值。我在 Oracle 中通过用 nvl 替换 is null 进行了尝试,但它返回 1 而不是 0.52。请帮助我将此查询转换为 Oracle 支持的查询,该查询将返回相同的结果。

这是我的查询

 SELECT [id] ,[name],r = isnull(nullif(
    max(CASE WHEN [code]  IN (1,2,4) then 0.70 else 0 end)
  ,0),1)
* isnull(nullif(
   min(CASE WHEN [code]  IN (1,2) then 0 else 1 end) 
    * max(CASE WHEN [code]  IN (4) then 0.20 else 0 end)
  ,0),1)
* isnull(nullif(
    max(CASE WHEN [code] IN (8) then 0.75 else 0 end)
  ,0),1)
  FROM  (values (1, 'ali',4)
        ,(1, 'ali',1)
        ,(1, 'ali',8)
        ,(1, 'ali',2)
        ,(2, 'sunny',1)
     ,(4, 'arslan',4)) as t(id, name,code)
  GROUP BY id, name;

【问题讨论】:

  • 为了理智,请重写这个查询,不要使用古老的连接语法。使用正确的 LEFT、INNER 或 CROSS JOINS,以适合您的应用程序。您在上面使用的连接是非常糟糕的做法。
  • 如果你说 MAX(CASE WHEN RM_LIVE.CRWSPECFUNC.IDCRWSPECFUNC IN (31,723) THEN 0.75 ELSE 1 END) 你会得到 1 而不是 0.75.. 你确定你已经在 sql 中计算出来了吗?似乎你所有的 ELSE 都应该是 0 而不是 1
  • @Rich Benner 忘记连接等,我所要做的就是通过将所有值与这些代码相乘来根据他们获得的代码给我的客户一些分数。假设如果有人得到代码 1、2、4 和 31,那么他应该得到 0.70 对应 1、2、4 和 0.75 对应代码 31,所以他的总价值将是 0.52。
  • @AlexK。让我编辑我的问题。我将发布一个没有任何屏幕截图的简单查询。
  • Rich 对您的加入是正确的。你在这里做的是非常糟糕的做法,把你的查询变成了一些难以理解的东西,只是没有给我任何学习和修复它的意愿。

标签: sql sql-server oracle tsql


【解决方案1】:

既然现在你要乘分数,首先我们需要决定,如果没有匹配的代码,分数是多少。我想,它应该是0。 接下来,我们应该将所有可能的代码分成独立的组,即结果不依赖于其他组成员。在这里,它们是 (1,2,4) 和 (8)。并为每个组定义规则。 所以

SELECT [id] ,[name],r = 
  -- At least one of values needed to get score > 0
  MAX(CASE WHEN code IN (1,2,4, 8) THEN 1.0  ELSE 0.0 END) *
  -- Now rules for every independent set of codes. Rule should return score if matched or 1.0 if not matched
  -- (1,2,4)
  coalesce(MAX(CASE WHEN [code] IN (1,2,4) THEN 0.70 END), 1.0 ) *
  -- (8) 
  coalesce(MAX(CASE WHEN [code] IN (8) THEN 0.75 END), 1.0)
  -- more ?
  FROM  (values (1, 'ali',4)
        ,(1, 'ali',1)
        ,(1, 'ali',8)
        ,(1, 'ali',2)
        ,(2, 'sunny',1)
     ,(4, 'arslan',4)) as t(id, name,code)
  GROUP BY id, name;

【讨论】:

  • [id] 这样的标识符在Oracle 中无效。
  • 是的,只需去掉 [] 括号。由于标识符不包含特殊符号,因此您也可以在 MS SQL 中删除括号。
【解决方案2】:

查询中有一些SQL Server的东西不是标准的SQL:

  1. [] 围绕列名 - 删除它们;您在这里不需要它们(否则您将使用标准 SQL 引号“”)
  2. r = expression - 别名。将此更改为标准 SQL expression AS r
  3. ISNULL(expression, value) - 将其更改为标准 SQL COALESCE(expression, value) 或 Oracle 的 NVL(expression, value)
  4. NULLIF(expression, value) - 这个你可以保留; Oracle 也支持它
  5. values (), (), ... - 替换为 SELECT FROM DUAL UNION ALL 子查询

你得到:

select 
  id,
  name, 
  coalesce(nullif( max(case when code in (1,2,4) then 0.70 else 0 end), 0), 1) *
  coalesce(nullif( min(case when code in (1,2) then 0 else 1 end) *
                   max(case when code in (4) then 0.20 else 0 end) , 0), 1) *
  coalesce(nullif( max(case when code in (8) then 0.75 else 0 end), 0), 1) as r
from 
(
  select 1 as id, 'ali' as name, 4 as code from dual
  union all
  select 1 as id, 'ali' as name, 8 as code from dual
  union all
  select 1 as id, 'ali' as name, 2 as code from dual
  union all
  select 2 as id, 'sunny' as name, 1 as code from dual
  union all
  select 4 as id, 'arslan' as name, 4 as code from dual
)
group by id, name;

然而,计算过于复杂:

coalesce(nullif( max(case when code in (1,2,4) then 0.70 else 0 end), 0), 1)

表示如果至少有一个匹配则 0.70 else 0 转为 null 转为 1。所以它与

相同
min(case when code in (1,2,4) then 0.70 else 1 end)

所以如果我没记错的话,整个计算变成:

case when max(case when code in (1,2) then 1 end) = 1 
  then 0.7 else max(case when code = 4 then 0.14 else 1 end) end *
min(case when code = 8 then 0.75 else 1 end) as r

case when max(case when code in (1,2) then 1 end) = 1 then 0.7 
     when max(case when code = 4 then 1 end) = 1 then 0.14 
     else 1 
end *
min(case when code = 8 then 0.75 else 1 end) as r

嗯,有很多方法可以写这个。

【讨论】:

    【解决方案3】:

    下面的代码应该会给你你期望的答案;

    CREATE TABLE #TestData (ID int, Name varchar(10), Code int)
    INSERT INTO #TestData (ID, Name, Code)
    VALUES
    (1,'ali',4)
    ,(1,'ali',1)
    ,(1,'ali',8)
    ,(1,'ali',2)
    ,(2,'sunny',1)
    ,(4,'arslan',4)
    
    SELECT DISTINCT
         a.id
        ,a.Name
        ,COALESCE(b.HasCode1, b.HasCode2, b.HasCode4,1) * COALESCE(b.HasCode8,1) Result
    
    FROM (SELECT ID, Name FROM #TestData GROUP BY ID, Name) a
    LEFT JOIN
    (
    SELECT
    ID
    ,Name
    ,SUM(CASE WHEN CODE = 1 THEN 0.7 END) HasCode1
    ,SUM(CASE WHEN CODE = 2 THEN 0.7 END) HasCode2
    ,SUM(CASE WHEN CODE = 4 THEN 0.7 END) HasCode4
    ,SUM(CASE WHEN CODE = 8 THEN 0.75 END) HasCode8
    FROM #TestData
    GROUP BY
    ID
    ,Name
    ) b
    ON a.ID = b.ID
    AND a.Name = b.Name
    
    DROP TABLE #TestData
    

    【讨论】:

      【解决方案4】:

      如果我了解您的需求(即,对于每种情况,id/name 组合需要指定所有代码),那么这可能会满足您的需求。但是,如果您在 2 位小数的答案之后,您可能希望在 val 列上添加某种 trunc/floor/round 函数:

      with t as (select 1 id, 'ali' name, 4 code from dual union all
                 select 1 id, 'ali' name, 1 code from dual union all
                 select 1 id, 'ali' name, 8 code from dual union all
                 select 1 id, 'ali' name, 2 code from dual union all
                 select 2 id, 'ali' name, 4 code from dual union all
                 select 2 id, 'ali' name, 8 code from dual union all
                 select 3 id, 'bob' name, 1 code from dual union all
                 select 3 id, 'bob' name, 2 code from dual union all
                 select 3 id, 'bob' name, 8 code from dual),
         res as (select id,
                        name,
                        case when count(distinct case when code in (1, 2, 4) then code end) = 3 then 0.7 
                             when count(distinct case when code in (1, 2) then code end) = 2 then 0.5
                             else 1
                        end case_1_2_and_poss_4,
                        case when count(distinct case when code = 8 then code end) = 1 then 0.75 else 1 end case_8
                 from   t
                 group by id, name)
      select id,
             name,
             case_1_2_and_poss_4 * case_8 val
      from   res;
      
              ID NAME        VAL
      ---------- ---- ----------
               1 ali       0.525
               2 ali        0.75
               3 bob       0.375
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-10-23
        • 1970-01-01
        • 1970-01-01
        • 2020-07-28
        • 1970-01-01
        • 2021-12-18
        • 1970-01-01
        相关资源
        最近更新 更多