【问题标题】:MSSQL Data type conversionMSSQL 数据类型转换
【发布时间】:2017-07-07 04:07:06
【问题描述】:

我有一对数据库(一个 mssql 和一个 oracle),由不同的团队运行。一些数据现在由 mssql 表中的存储过程定期同步。这个存储过程正在调用一个非常大的

MERGE [mssqltable].[Mytable] as s 
USING THEORACLETABLE.BLA as t 
ON t.[R_ID] = s.[R_ID]
WHEN MATCHED THEN UPDATE SET [Field1] = s.[Field1], ..., [Brokenfield] = s.[BrokenField]
WHEN NOT MATCHED BY TARGET THEN
... another big statement

字段 Brokenfield 直到今天还是一个数字,并且可以取值 NULL, 0, 1, .., 24

现在,由于某种原因,Oracle 团队今天引入了一项重大更改,将列的类型更改为字符串,现在列中有值 NULL, "", "ALFA", "BRAVO"...。当然,同步坏了。

在此处修复同步的最简单方法是什么?我(Mysql 团队负责人,前端专家,但不是数据库方面的专家)通常会在这里申请我们的一位数据库专家,但他们现在都病了,今天必须在线修复....

我想到了一个像CONVERT_BROKENFIELD_INT_TO_STRING 这样的存储过程,它基于一些switch-case,可以在那个merge 语句中调用,但不知道该怎么做。

编辑/澄清:
我需要的是一种制作一段 SQL 代码(存储过程)的方法,输入“ALFA”并返回 1、“BRAVO”-> 2 等,并且可以重复使用,以避免在不止一处。

【问题讨论】:

  • 您将需要更改 sql server 数据库中该列的数据类型。它需要是 (n)varchar(SomeSize)。这取决于 Oracle 端的列大小,以确保它可以容纳所有数据。
  • 如果可能的话,我很想避免这种情况。这将需要对位于 mssql 之上的软件进行大规模重构。我今天需要在线修复,而对一家大公司使用的 100000 LOC 软件进行这样的更改只能在至少经过 3 个月的测试的固定发布日期完成。
  • 你不能将像 ALFA 这样的字符串插入数字列。您可以使用 case 表达式包装该列,并在它不是有效数字时插入 NULL。但是您正在做的是从曾经是数字且不再是数字的源中获取数据,并将该值插入到数字列中。值必须是数字,否则会失败。
  • 我知道它们必须是数字才能插入。有没有办法制作一段可重用的 SQL 代码,它将“ALFA”作为参数并返回 1 作为数字。
  • 你应该如何“同步”甚至不是相同数据类型的数据?如果仅在一侧(Oracle 一侧)进行了更改,而另一侧不同意(出于他们的需要,该列必须继续为 NUMBER 列),则无需“同步”,因为两者一开始,组织甚至不同意“同步”数据类型。

标签: sql-server oracle stored-procedures synchronization type-conversion


【解决方案1】:

如果他们使用的名称以字母开头并按顺序排列:

A = 1
B = 2
C = 3
etc.

然后你可以这样做:

MERGE [mssqltable].[Mytable] as s 
USING THEORACLETABLE.BLA as t 
ON t.[R_ID], 1)) - ASCII('A') + 1 = s.[R_ID]
WHEN MATCHED THEN UPDATE SET [Field1] = s.[Field1], ..., [Brokenfield] = s.[BrokenField]
WHEN NOT MATCHED BY TARGET THEN
... another big statement

编辑:但实际上我重新阅读了您的问题,并且您在谈论 [Brokenfield] 是问题列,所以我的解决方案不起作用。

我现在不太明白,因为似乎 MERGE 语句正在用数字更新 oracle 表,所以你肯定需要映射以另一种方式工作,即 1 -> ALFA,2 -> BETA,等等?

【讨论】:

    【解决方案2】:

    如果您不能像@RichardHansell 所描述的那样简化正确值的逻辑,您可以为BrokenField 创建一个正确值的人行横道表。然后,您可以使用带有left join 的公用表表达式或子查询到该人行横道以在merge 中使用。

    create table dbo.BrokenField_Crosswalk (
        BrokenField varchar(32) not null primary key
      , CorrectedValue int
      );
    
    insert into dbo.BrokenField_Crosswalk (BrokenField,CorrectedValue) values
      ('ALFA',  1)
    , ('ALPHA', 1)
    , ('BRAVO', 2)
    ...
    go
    

    您的merge 代码如下所示:

    ;with cte as (
      select o.R_ID
        , o.Field1
        , BrokenField = cast(isnull(c.CorrectedValue,o.BrokenField) as int)
        ....
      from oracle_table.bla as o
        left join dbo.BrokenField_Crosswalk as c
    )
    
    merge into [mssqltable].[Mytable] t
      using cte as s
        on t.[R_ID] = s.[R_ID]
      when matched 
        then update set 
          [Field1] = s.[Field1]
          , ...
          , [Brokenfield] = s.[BrokenField]
      when not matched by target 
        then
    

    【讨论】:

    • @PetrOsipov 乐于助人!也感谢您的反馈!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-20
    • 2021-12-24
    相关资源
    最近更新 更多