【问题标题】:Replacing multiple character phrases with an abbreviation list SQL用缩写列表 SQL 替换多个字符短语
【发布时间】:2017-04-17 22:35:31
【问题描述】:

我在下面有一个 SQL 表(注意:用于使其更易于阅读的引号

Table1.Description  
"HOUSING,WRAP RECESSED"  
"HOUSING,ASSEMBLY 2-FEED"  
"LENS,FLUSH SUS"  

Table2.Abbreviations  
ASSY = ASSEMBLY  
FD = FEED  
FLUSH = FL  
HSG = HOUSING  
LENS = LNS    
RECESSED = REC

我想更新,或者类似于替换和创建一个新表(两者都可以),Table1.Description 和 Table2.Abbreviations。它应该是这样的:

Table1.Description  
"HSG,WRAP REC"  
"HSG,ASSY 2-FD"  
"LNS,FL SUS"  

【问题讨论】:

  • 一种方法(不一定是最好的方法)是使用游标遍历 Table1 中的每一行并执行一个过程,使用 Table2 中的数据根据​​需要多次执行字符串替换,直到没有可以更换。
  • 是否有任何重叠替换的可能性,例如“FOOD”变成“FD”,“FOO”变成“FU”?如果是这样,您将需要像 Cappelletti 博士那样的解决方案,在尝试替换之前“标记”输入字符串。如果替换可以递归发生,例如“FOOD WRAP”变成“FD WRP”,“WRP”变成“RP”。你想一直替换下去吗?
  • @HABO,到目前为止所有的方法都是row-by-row。考虑到替换的排序顺序,这没有问题。甚至可以将一个短语替换为其他内容,并在其他替换之后重新替换它。在我的一个项目中,我们使用了一个带有两个参数的函数:一个带有所有替换的 key-value-pair-XML 和一个 NVARCHAR(MAX)。我们将其用于复杂的多级操作,以从模板中创建 CDA 文档。只要您只处理一个文档,它的运行速度就惊人地快...

标签: sql tsql replace


【解决方案1】:

这是另一个使用动态 SQL 和全局搜索和替换的选项。此过程本质上将“标记”字符串以避免冲突。

我应该注意,缩写最好在两个字段中(从、到)。提供的样本中的一对似乎不一致(Long > Short 和 Short to Long)。

Declare @Table1 table (ID int,Description varchar(500));Insert into @Table1 values (1,'HOUSING,WRAP RECESSED'),(2,'HOUSING,ASSEMBLY 2-FEED'),(3,'LENS,FLUSH SUS')
Declare @Table2 table (MapFrom varchar(50),MapTo varchar(50));Insert Into @Table2 values 
('ASSEMBLY','ASSY'),
('FEED'    ,'FD'),
('FLUSH'   ,'FL'),
('HOUSING' ,'HSG'),
('LENS'    ,'LNS'),
('RECESSED','REC')

Declare @SQL varchar(max)=''
Select  @SQL = @SQL+concat(',(',ID,',''||',replace(Description,'''',''''''),'||'')') From @Table1 --Where ID=2
Select  @SQL = Replace(@SQL,MapFrom,MapTo) 
 From   (
         Select MapFrom=' ',MapTo='|| ||'
         Union All
         Select ',','||,||'
         Union All
         Select '-','||-||'
         Union All
         Select MapFrom = '||'+ltrim(rtrim(MapFrom))+'||'
               ,MapTo   = ltrim(rtrim(MapTo))
          From  @Table2
          Union All
          Select '||',''   -- Remove Any Remaining |
         ) A
Select  @SQL = 'Select * From ('+Stuff(@SQL,1,1,'values')+') N(ID,Value)'
Exec(@SQL)

返回

ID  Value
1   HSG,WRAP REC
2   HSG,ASSY 2-FD
3   LNS,FL SUS

【讨论】:

  • 对于任何混淆,我深表歉意,但值中不包含“=”。我只是想说住房的缩写是 HSG 等等。所以它们实际上是两列。这有助于澄清吗?不过谢谢你!如果您有更新,我肯定希望看到更新。感谢您抽出宝贵时间提供帮助!
  • 这两个字段名是什么?
  • @SeanDon 查看更新的答案。在 Table2 中,我现在有 2 个字段 MapFrom 和 MapTo
  • @SeanDon 又添加了一张 - 的地图以捕获 2-FEED 等物品
【解决方案2】:

试试这样:

您的缩写表

CREATE TABLE Abbreviations (LongTerm VARCHAR(100),ShortTerm VARCHAR(10));
INSERT INTO Abbreviations VALUES
 ('ASSEMBLY','ASSY')
,('FEEd','FD')
,('FLUSH','FL')
,('HOUSING','HSG')
,('LENS','LNS')
,('RECESSED','REC');

GO

一个神奇的函数

CREATE FUNCTION dbo.ReplaceAbbreviations(@string VARCHAR(MAX))
RETURNS VARCHAR(MAX) AS
BEGIN
    SELECT @string=REPLACE(@string,LongTerm,ShortTerm)
    FROM Abbreviations;

    RETURN @string;
END
GO

带有您的字符串的表格

CREATE TABLE YourDescription (LongDescription VARCHAR(MAX));
INSERT INTO YourDescription VALUES
 ('HOUSING,WRAP RECESSED')
,('HOUSING,ASSEMBLY 2-FEED')  
,('LENS,FLUSH SUS');
GO

使用函数的简单选择

SELECT LongDescription
      ,dbo.ReplaceAbbreviations(LongDescription) AS ShortDescription
FROM YourDescription;
GO

清理测试场景

DROP TABLE YourDescription;
DROP FUNCTION dbo.ReplaceAbbreviations;
DROP TABLE Abbreviations;

结果

LongDescription            ShortDescription
HOUSING,WRAP RECESSED      HSG,WRAP REC
HOUSING,ASSEMBLY 2-FEED    HSG,ASSY 2-FD
LENS,FLUSH SUS             LNS,FL SUS

【讨论】:

    【解决方案3】:

    一般的策略是遍历每个单词/缩写对,并根据每一对更新 Table1.Description。我使用临时表创建了一个解决方案来说明如何做到这一点:

    CREATE TABLE #table1 (descr VARCHAR(1000))
    CREATE TABLE #abbr (word VARCHAR(1000), abr VARCHAR(1000), processed int)
    
    DECLARE @word VARCHAR(1000)
    DECLARE @abbr VARCHAR(1000)
    
    INSERT INTO #table1
            ( descr )
    VALUES  ( 'HOUSING,WRAP RECESSED'  -- descr - varchar(1000)
    
              ),
              ( 'HOUSING,ASSEMBLY 2-FEED'  -- descr - varchar(1000)
    
              ),
              ( 'LENS,FLUSH SUS'  -- descr - varchar(1000)
    
              )
    
    INSERT INTO #abbr
            ( word, abr, processed )
    VALUES  ( 'ASSEMBLY', -- word - varchar(1000)
              'ASSY'  -- abr - varchar(1000)
              ,0
              ),
              ( 'FEED', -- word - varchar(1000)
              'FD'  -- abr - varchar(1000)
              ,0
              ),
              ( 'FLUSH', -- word - varchar(1000)
              'FL'  -- abr - varchar(1000)
              ,0
              ),
              ( 'HOUSING', -- word - varchar(1000)
              'HSG'  -- abr - varchar(1000)
              ,0
              ),
              ( 'LENS', -- word - varchar(1000)
              'LNS'  -- abr - varchar(1000)
              ,0
              ),
              ( 'RECESSED', -- word - varchar(1000)
              'REC'  -- abr - varchar(1000)
              ,0
              )
    
    
    WHILE EXISTS (SELECT * FROM #abbr WHERE processed = 0)
    BEGIN
        SELECT TOP 1 @word = word, @abbr = abr FROM #abbr WHERE processed = 0
    
        UPDATE #table1
        SET descr = REPLACE(descr,@word,@abbr)
    
        UPDATE #abbr
        SET processed = 1
        WHERE word = @word AND abr = @abbr
    END
    
    SELECT * FROM #table1
    

    【讨论】:

    • 你正走在程序性思维的黑暗中。快点!继续研究基于集合的方法。看看 proc 恶魔,他发明了循环和游标,让我们可怜的数据库人员远离基于集合的解决方案。老实说:我的解决方案是 - 在 magic moment 中也隐藏了一个 RBAR。和诚实2:是的,有一些时刻,WHILE(或CURSOR)是一个不错的选择,但这种情况很少见......
    猜你喜欢
    • 2021-08-02
    • 1970-01-01
    • 2022-01-07
    • 2012-07-18
    • 2019-07-23
    • 2015-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多