【问题标题】:How to Convert VARCHAR to a number using CASE?如何使用 CASE 将 VARCHAR 转换为数字?
【发布时间】:2017-09-24 02:20:33
【问题描述】:

我正在尝试在下面的查询(这将是另一个更大查询的子查询)中将 VARCHAR 转换为可以测量为 0 的值 - 不确定要使用什么值。我收到错误"operand data type is invalid in the sum operator" 这是我第一次遇到这种情况。最终目标是说“当值为'L'时返回0,否则返回1”另外DEL_INDICATORPO_ITEM表中的一个字段,但我在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')

【问题讨论】:

  • sum 是一个聚合,使用它你必须使用 group by 子句,或者让我们知道,sum 在这里对你没用?
  • 感谢您的回复 - 我将添加群组,因为这很有意义并感谢您的帮助

标签: sql sql-server casting type-conversion varchar


【解决方案1】:

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

使用group byhaving 子句只返回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(派生表也可以)和sum() over()聚合窗口函数:

;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

根据您打算如何将其用作“另一个更大查询的子查询”,您可能需要考虑使用 exists()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)
  )

【讨论】:

  • 感谢您的想法和意见。我已经更新了原始代码,因为这确实是更大查询的一部分。我使用 NOT EXISTS 并使用 GROUP by 进行了建议的更改。我仍然收到消息:将 varchar 值“DEL_INDICATOR_CALC”转换为数据类型 int 时,Msg 245, Level 16, State 1, Line 1 Conversion failed。希望看到完整的查询可能会有所帮助
  • 还有一个不同的问题 - SQL Server 现在正在对 P 下引用的所有列实例进行重新标记 - 即 P.PO_NUMBER - 不确定原因
  • 另一件事 - DEL_INDICATOR 中的值是“L”、“S”或“” - 空白 - 不确定这是否会影响转换/转换?
  • @user3496218 停止使用字符串文字作为别名,将它们括在方括号中。您不能对字符串文字求和,例如'del_indicator_calc',重复您尝试引用的表达式,如我的回答中所示。此外,您使用的 not exists() 没有相关参考。请查看我的回答并重试。
  • 感谢您的建议 - 非常感谢!我已经编辑了上面的代码以在 CASE 语句中执行 SUM 和 CAST - 这对我来说似乎是合乎逻辑的,但我现在得到 SUM 不是一个可识别的函数错误 - 假设这与我的订购有关但不熟悉。还添加了相关参考 - 但我很长时间没有使用存在/不存在语句,希望这是正确的。
【解决方案2】:

1) 在尝试对值求和之前,您需要将 VARCHAR 转换为数字。 2) 如果您只想对 1 列执行聚合,则需要 GROUP BY 子句。 3) 您不能在 WHERE 子句中引用表达式别名,您需要改用 HAVING 子句。 4) 您不想使用 FLOAT 数据类型,除非您知道与使用“近似”数字数据类型相关的问题。根据 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;

【讨论】:

  • 感谢您的回复。该示例返回结果:Msg 207, Level 16, State 1, Line 13 列名“DEL_INDICATOR_CALC”无效。消息 207,级别 16,状态 1,第 5 行无效的列名称“DEL_INDICATOR_CALC”。
  • 该列名直接取自您的原始代码...只需在视图中将名称替换为正确的名称即可。另外,我假设(可能是错误的)您的默认架构是 dbo...如果我不正确,请将 dbo 替换为正确的架构。
  • 再次感谢 - 现在收到 TRY_CONVERT 不是公认的内置函数的错误 - 这与系统有关吗?
  • @user3496218 - SQL Server 2012 中引入了 TRY_CONVERT(和 TRY_CAST)。如果您使用的是 2008R2 或更早版本,它对您不起作用……这就是为什么您应该始终让人们当您提出问题时,知道您使用的是什么版本。
  • 我在 SQL Server 2016 上
猜你喜欢
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
  • 1970-01-01
  • 2013-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多