如何使用 CASE 将 VARCHAR 转换为数字?

How to Convert VARCHAR to a number using CASE?

我正在尝试在下面的查询(这将是另一个更大的查询的子查询)中将 VARCHAR 转换为可以测量为 <0 或 >0 的值 - 不确定要转换成什么值采用。我收到错误 "operand data type is invalid in the sum operator" 这是我第一次遇到这种情况。最终目的是说"when the value is 'L' then return 0, else return 1"另外DEL_INDICATORPO_ITEM中的一个字段table但是我在SELECT中省略了。

这是更新后的代码:

 SELECT    G.order_no AS 'GPS_ORDER_#', 
          G.order_status AS 'GPS_ORDER_STATUS', 
          G.cst_order_no AS 'GPS_CUSTOMER_PO_#',
          H.PO_NUMBER AS 'SAP_PO_#',
          P.PO_ITEM_NUMBER, 
          P.DEL_INDICATOR 

FROM   

          (SELECT    order_no, 
                     order_status, 
                     cst_order_no

           FROM      asagdwpdx_prod.dbo.SimoxOrder1

           UNION ALL

           SELECT    order_no, 
                     order_status, 
                     cst_order_no

           FROM      asagdwpdx_prod.dbo.SimoxOrder2

           UNION ALL 

           SELECT    order_no, 
                     order_status, 
                     cst_order_no

           FROM      asagdwpdx_prod.dbo.SimoxOrder3) G 

JOIN      PDX_SAP_USER.dbo.VW_PO_HEADER H ON G.order_no = H.AHAG_NUMBER

JOIN      PDX_SAP_USER.dbo.VW_PO_ITEM P ON H.PO_NUMBER = P.PO_NUMBER 

WHERE     G.order_status = '10'

AND       NOT EXISTS  ( 
                                SELECT P1.PO_NUMBER,
                                       P1.PO_ITEM_NUMBER, 
                                       SUM(CASE 
                                            WHEN CAST(P1.DEL_INDICATOR AS INT) = 'L' 
                                            THEN '0'
                                            ELSE '1'
                                       END AS [SUM_DEL]) AS [SUM]

                                FROM   PDX_SAP_USER.dbo.VW_PO_ITEM P1

                                WHERE  P1.PO_NUMBER = H.PO_NUMBER

                                GROUP BY P1.PO_NUMBER,
                                         P1.PO_ITEM_NUMBER,
                                         CASE 
                                            WHEN P1.DEL_INDICATOR = 'L' 
                                            THEN '0'
                                            ELSE '1'
                                       END

                                HAVING SUM  (CASE 
                                            WHEN CAST(P1.DEL_INDICATOR AS INT) = 'L' 
                                            THEN '0'
                                            ELSE '1'
                                       END)  > '0')

1) 在尝试对值求和之前,您需要将 VARCHAR 转换为数字。 2) 如果你只想对 1 列执行聚合,你需要一个 GROUP BY 子句。 3) 您不能在 WHERE 子句中引用表达式别名,您需要使用 HAVING 子句代替。 4) 你不想使用 FLOAT 数据类型,除非你知道与使用 "approximate" 数字数据类型相关的问题。根据 DEL_INDICATOR_CALC 中的数据,考虑使用 INT、DECIMAL 或 NUMERIC。

考虑到这一点,看看下面的方法对你有何作用...

SELECT
    vpi.PO_NUMBER,
    vpi.PO_ITEM_NUMBER,
    CASE WHEN vpi.DEL_INDICATOR = 'L' THEN '0' ELSE '1' END AS 'DEL_INDICATOR_CALC',
    SUM(TRY_CONVERT(INT, vpi.DEL_INDICATOR_CALC)) AS 'PO_TYPE'
FROM
    dbo.VW_PO_ITEM vpi
GROUP BY
    vpi.PO_NUMBER,
    vpi.PO_ITEM_NUMBER,
    CASE WHEN vpi.DEL_INDICATOR = 'L' THEN 0 ELSE 1 END
HAVING 
    SUM(TRY_CONVERT(INT, vpi.DEL_INDICATOR_CALC)) = 1;

我认为您没有充分描述您想要的结果,但这里有两个选项可能会让您走上正确的道路:

group byhaving 子句一起使用仅 return po_type > 0:

select 
    po_number
  , po_item_number
  , po_type = sum(case when del_indicator = 'L' then 0 else 1 end)
from vw_po_item
group by 
    po_number
  , po_item_number
having sum(case when del_indicator = 'L' then 1 else 0 end) > 0

common table expression(派生的 table 也同样有效)与 sum() over() 聚合 window 函数一起使用:

;with cte as (
  select 
      po_number
    , po_item_number
    , del_indicator_calc = case when del_indicator = 'L' then 0 else 1 end
    , po_type = sum(case when del_indicator = 'L' then 0 else 1 end)
        over (partition by po_number, po_item_number)
  from vw_po_item
)
select *
from cte
where po_type > 0

根据您打算如何将其用作 "subquery of another larger query",您可能需要考虑使用 exists() or not exists() 子句:

select ...
from ...
where ...
   /* only return records that have an item with del_indicator = 'L' */
  and exists (
    select 1 
    from po_item i
    where i.po_number = t.po_number -- `t` being an alias for a table in your `from` clause
      -- if you are using the subquery per item instead of just `po_number`
      and i.po_item_number = t.po_item_number  

      and del_indicator = 'L'
    )

使用示例not exists()

select 
    G.order_no        as [gps_order_#]
  , G.order_status    as [gps_order_status]
  , G.cst_order_no    as [gps_customer_po_#]
  , H.po_number       as [sap_po_#]
  , P.po_item_number
  , P.del_indicator
from (
  select order_no, order_status, cst_order_no 
  from asagdwpdx_prod.dbo.SimoxOrder1
  union all
  select order_no, order_status, cst_order_no 
  from asagdwpdx_prod.dbo.SimoxOrder2
  union all
  select order_no, order_status, cst_order_no 
  from asagdwpdx_prod.dbo.SimoxOrder3
  ) G
  inner join pdx_sap_user.dbo.vw_po_header H
    on G.order_no = H.ahag_number
  inner join pdx_sap_user.dbo.vw_po_item P
    on H.po_number = P.po_number
where G.order_status = '10'
   and not exists (
    select 1
    from pdx_sap_user.dbo.vw_po_item i
    where i.po_number = H.po_number
      and (i.del_indicator <> 'L' or i.del_indicator is null)
  )