【问题标题】:Removing delimiters from a single column of a csv file without opening the file从 csv 文件的单个列中删除分隔符而不打开文件
【发布时间】:2017-02-05 14:20:37
【问题描述】:

我有以下csv文件的内容

以下是 CSV 文件的内容:

Date_Added|this_flag|Name|DOB|SSN|ID

2015 年 5 月 1 日|Y|叮当声|heimerscmidt|19901002|123456789|3

May 1st, 2015|N|Jingleheimerscmidt|19901002|123456789|3
May 5th, 2015|Y|Jon|19901001|012345678|1
May 1st, 2015|N|Jon|19901002|012345678|1
May 1st, 2015|Y|Jacob|19901001|234567890|2
May 5th, 2015|N|Jingleheimerscmidt|19901001|123456789|3
May 1st, 2015|Y|Jingleheimerscmidt|19901001|123456789|3

正如您在粗体和斜体内容中看到的那样,除了管道运算符分隔的列之外,内容中还有一个管道运算符。我想在不打开 csv 文件的情况下从文本中删除该管道运算符。有没有办法通过编写代码或任何其他方法来解决这个问题

【问题讨论】:

  • 不打开文件?您的意思是无需在文本编辑器中打开手动操作?必须打开文件才能读取其内容。您可以将其作为单个 VARCHAR 值引入并根据您自己的规则切割字符串....例如将每列拆分为多行并确定何时存在太多行然后将行连接回并转回表格格式
  • 如果您可以控制 csv 文件的生成,您可以添加文本限定符,例如引号,以便提取应用程序(或您自己的数据清理代码)不会将文本中的管道与分隔符混淆
  • 无论如何,您必须打开文件才能更改它 - 通过代码或手动。
  • @Matt 是的。无需手动打开。在串联时,是的,我想到了使用 instr 和 substr 的组合。对此有何建议?
  • @Missy 你能否详细说明如何通过代码打开它并获得所需的结果

标签: sql oracle csv informatica-powercenter


【解决方案1】:

好的,我知道你标记了 oracle,所以也许你自己或其他 Oracle 专家可以从 sql-server 迁移这个解决方案。我知道 oracle 能够完成这些操作。

通常我会说您想要一种快速/花哨的拆分字符串的方式,但在这种情况下,您需要保持分隔符之间字符串的序数位置。所以我想到了一种方法可以做到这一点。

1) 首先将 CSV 作为所有 1 列导入临时表。现在,如果您的 CRLF 也在 Name 列中找到,这将是一个问题....但我们会假设这不是因为您没有指定它。

2) 在该表上构建一个 row_number 以用作假主键,并确定何时存在超出应有的分隔符。

3) 使用递归 cte 将字符串溢出到行中,并保持子字符串在原始字符串中的序号位置,以便以后连接。

4) 通过 MergePositions 更改 OrdinalPostion 并基于它生成 DENSE_RANK() 来确定要分组的行

5) 条件聚合使用OrdinalGroup作为列号,然后使用串联的方法将所有OrdginalGroup 3行组合起来。

DECLARE @CSV as TABLE (LumpedColumns NVARCHAR(MAX))
INSERT INTO @CSV VALUES
('May 1st, 2015|Y|Jingle|he|imerscmidt|19901002|123456789|3')
,('May 1st, 2015|N|Jingleheimerscmidt|19901002|123456789|3')
,('May 5th, 2015|Y|Jon|19901001|012345678|1')
,('May 1st, 2015|N|Jon|19901002|012345678|1')
,('May 1st, 2015|Y|Jacob|19901001|234567890|2')
,('May 5th, 2015|N|Jingleheimerscmidt|19901001|123456789|3')
,('May 1st, 2015|Y|Jingleheimerscmidt|19901001|123456789|3')

;WITH cteFakePrimaryKey AS (
    SELECT
       LumpedColumns
       ,CASE WHEN LEN(LumpedColumns) - LEN(REPLACE(LumpedColumns,'|','')) > 5 THEN
          LEN(LumpedColumns) - LEN(REPLACE(LumpedColumns,'|','')) - 5 ELSE 0 END as MergeXPositions
       ,ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as PK
    FROM
       @CSV
)


, cteRecursive AS (
    SELECT
       PK
       ,LumpedColumns
       ,MergeXPositions
       ,LEFT(LumpedColumns,CHARINDEX('|',LumpedColumns)-1) as ColValue
       ,RIGHT(LumpedColumns,LEN(LumpedColumns) - CHARINDEX('|',LumpedColumns)) as Remaining
       ,1 As OrdinalPosition
    FROM
       cteFakePrimaryKey

    UNION ALL

    SELECT
       PK
       ,LumpedColumns
       ,MergeXPositions
       ,LEFT(Remaining,CHARINDEX('|',Remaining)-1)
       ,RIGHT(Remaining,LEN(Remaining) - CHARINDEX('|',Remaining))
       ,OrdinalPosition + 1
    FROM
       cteRecursive
    WHERE
       Remaining IS NOT NULL AND CHARINDEX('|',Remaining) > 0

    UNION ALL

    SELECT 
       PK
       ,LumpedColumns
       ,MergeXPositions
       ,Remaining
       ,NULL
       ,OrdinalPosition + 1
    FROM
       cteRecursive
    WHERE Remaining IS NOT NULL AND CHARINDEX('|',Remaining) = 0
)

, cteOrdinalGroup AS (
    SELECT
       PK
       ,LumpedColumns
       ,ColValue
       ,OrdinalPosition
       ,DENSE_RANK() OVER (PARTITION BY PK ORDER BY
          CASE
             WHEN OrdinalPosition < 3 THEN OrdinalPosition
             WHEN OrdinalPosition > (3 + MergeXPositions) THEN OrdinalPosition
          ELSE 3 END ) as OrdinalGRoup

    FROM
       cteRecursive
)

SELECT
    PK
    ,LumpedColumns
    ,MAX(CASE WHEN OrdinalGRoup = 1 THEN ColValue END) as Date_Added
    ,MAX(CASE WHEN OrdinalGRoup = 2 THEN ColValue END) as this_flag
    ,STUFF(
        (SELECT '|' + ColValue
        FROM
            cteOrdinalGroup g2
        WHERE
             g1.PK = g2.PK
             AND g2.OrdinalGroup = 3
        ORDER BY
          g2.OrdinalPosition
        FOR XML PATH(''))
        ,1,1,'') as name
    ,MAX(CASE WHEN OrdinalGRoup = 4 THEN ColValue END) as DOB
    ,MAX(CASE WHEN OrdinalGRoup = 5 THEN ColValue END) as SSN
    ,MAX(CASE WHEN OrdinalGRoup = 6 THEN ColValue END) as ID
FROM
    cteOrdinalGroup g1
GROUP BY
    PK
    ,LumpedColumns
ORDER BY
    PK

【讨论】:

    【解决方案2】:

    如果这只是您需要处理的一种情况并且您不想修改文件并且需要在 Informatica 中执行此操作,则可以将此 Source QualifierInput Type 会话属性从 File 更改为Command 并使用 sed 进行替换,例如:

    cat $$FileName | sed -e 's/Jingle|heimerscmidt/Jingleheimerscmidt/g'
    

    这不是一个很好的解决方案,因此它不是一个通用的解决方案。但也许这会做,或者至少会给你一些想法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-16
      • 1970-01-01
      • 2019-05-15
      • 2018-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多