【问题标题】:Is there a simple(r) way to REPLACE a character across all columns in one table in SQL Server?是否有一种简单的(r)方法可以在 SQL Server 的一个表中的所有列中替换一个字符?
【发布时间】:2023-03-28 23:21:02
【问题描述】:

这里可以回答大约 10 个不同的子问题,但主要问题在标题中。 TLDR 版本:我有一个如下例所示的表格,我想替换整个表格中的所有双引号。有没有简单的方法可以做到这一点?

我使用光标的解决方案似乎相当简单。我知道 SQL Server 社区中有一些 CURSOR 仇恨(运行时不好?)。 CURSOR 在什么时候(num 行和/或 num 列)会发臭?

创建可重现的示例表

    DROP TABLE IF EXISTS #example;
    CREATE TABLE #example (
       NumCol  INT
      ,CharCol  NVARCHAR(20)
      ,DateCol  NVARCHAR(100)
      );
      
    INSERT INTO #example VALUES
    (1, '"commas, terrible"',  '"2021-01-01 20:15:57,2021:04-08 19:40:50"'),
    (2, '"loadsrc,.txt"', '2020-01-01 00:00:05'),
    (3, '".txt,from.csv"','1/8/2021 10:14')

目前,我确定的解决方案是:

  1. 手动更新每一列UPDATE X SET CharCol = REPLACE(CharCol, '"','')。超过 2 列的 IMO 非常烦人。
  2. 使用 CURSOR 进行更新(类似于 SQL Server- SQL Replace on all columns in all tables across an entire DB 上看起来很烦人的复杂解决方案

使用 CURSOR 替换字符

这与所有与游标相关的脚本有点复杂,但在其他方面似乎运行良好。

-- declare variable to store colnames, cursor to filter through list, string for dynamic sql code
DECLARE  @colname   VARCHAR(10)
        ,@sql       VARCHAR(MAX)
        ,@namecursor CURSOR;

-- run cursor and set colnames and update table
SET @namecursor = CURSOR FOR SELECT ColName FROM #colnames
OPEN @namecursor;  
FETCH NEXT FROM @namecursor INTO @colname;  

WHILE (@@FETCH_STATUS <> -1)  -- alt: WHILE @@FETCH_STATUS = 0
    BEGIN;  
        SET @sql = 'UPDATE #example SET '+@colname+' = REPLACE('+@colname+', ''"'','''')'
        EXEC(@sql); -- parentheses VERY important: EXEC(sql-as-string) NOT EXEC storedprocedure
        FETCH NEXT FROM @namecursor INTO @colname;  
    END;  
 
    CLOSE @namecursor;  
    DEALLOCATE @namecursor;  
    GO  

-- see results
SELECT * FROM #example

子问题:虽然我在其他地方的数据库中看到过它,但对于这个特定的示例,我在 Excel 中打开一个 .csv 文件并将其导出为制表符分隔。有没有办法在没有双引号的情况下更改要导出的设置?如果我没记错的话,BULK INSERT 没有办法处理这个问题,也没有办法处理导入带有额外逗号的 csv 文件。

是的,我会假装我很好,日期列中有一个日期时间列表(需要 varchar 数据类型)。

【问题讨论】:

  • 不,你几乎明白了。有时编程只是非常烦人......你可以做一些事情,比如将表转储到外部存储并使用其他东西来解析它。或者将整个表格转换为 JSON 或 XML 并替换单个字符串中的字符,然后将其带回您的表格中。但这些更令人讨厌。或者投资于有助于自动化任务的 IDE 工具。
  • 您的 SQL Server 版本是多少?

标签: sql-server tsql replace data-cleaning


【解决方案1】:

为什么不直接动态构建 SQL?

大概这是您要做的一次性任务,因此只需为您的表格运行以下内容,粘贴到 SSMS 中并运行。但如果不是,您可以构建一个自动化流程来执行它 - 当然更好的是在插入数据时正确清理!

select 
'update <table> set ' +
String_Agg(QuoteName(COLUMN_NAME) + '=Replace(' + QuoteName(column_name) + ',''"'','''')',',')
from INFORMATION_SCHEMA.COLUMNS
where table_name='<table>' and TABLE_SCHEMA='<schema>' and data_type in ('varchar','nvarchar')

example DB<>Fiddle

【讨论】:

    【解决方案2】:

    您可以尝试这种方法,速度不快,但易于输入(或生成)。

    SELECT NumCol = y.value('(NumCol/text())[1]','int')
          ,CharCol = y.value('(CharCol/text())[1]','nvarchar(100)')
          ,DateCol = y.value('(DateCol/text())[1]','nvarchar(100)')
    FROM #example e
    CROSS APPLY(SELECT e.* FOR XML PATH('')) A(x)
    CROSS APPLY(SELECT CAST(REPLACE(A.x,'"','') AS XML)) B(y);
    

    简而言之:

    • 第一个 APPLY 会将所有列转换为 无根 XML。
    • 如果不使用,TYPE,这将是nvarchar(max) 隐式类型
    • 第二个APPLY 将首先替换整个文本(实际上是一行)中的任何" 并将其转换为XML。
    • SELECT 使用 .value 从 XML 中获取 type-safe 值。

    更新:只需在 FROM 之前添加 INTO dbo.SomeNotExistingTableName 即可使用此数据创建一个新表。这看起来比更新现有表更好(也可能是#-table)。我认为这是一个 staging 环境...

    祝你好运,混乱的数据总是让人头疼:-)

    【讨论】:

      猜你喜欢
      • 2023-02-26
      • 2010-10-07
      • 2016-01-19
      • 1970-01-01
      • 1970-01-01
      • 2021-09-30
      • 2016-06-05
      • 2013-07-29
      • 1970-01-01
      相关资源
      最近更新 更多