【问题标题】:How do I select a SQL dataset where values in the first row are the column names?如何选择第一行中的值为列名的 SQL 数据集?
【发布时间】:2024-01-19 08:33:01
【问题描述】:

我的数据如下所示:

ID RowType Col_1       Col_2     Col_3       ... Col_n
1  HDR     FirstName   LastName  Birthdate
2  DTL     Steve       Bramblet  1989-01-01
3  DTL     Bob         Marley    1967-03-12
4  DTL     Mickey      Mouse     1921-04-25

我想返回一个如下所示的表或数据集:

ID    FirstName    LastName    Birthdate
2     Steve        Bramblet    1989-01-01
3     Bob          Marley      1967-03-12
4     Mickey       Mouse       1921-04-25

其中 n = 255(因此有 255 个 Col_ 字段的限制)

***编辑:HDR 行中的数据是任意的,因此我仅使用 FirstName、LastName、Birthdate 作为示例。这就是为什么我认为它需要是动态 SQL,因为我想要结束的列名将根据 HDR 行中的值而变化。谢谢! ***

如果有一个纯粹的 SQL 解决方案,那就是我所追求的。它将进入 ETL 流程 (SSIS),因此如果一切都失败了,我可以使用脚本任务。

即使我可以返回单行,这也是一个解决方案。我在想可能有这样的动态 sql 解决方案:

select Col_1 as FirstName, Col_2 as LastName, Col_3 as Birthdate

【问题讨论】:

  • SSIS 数据流需要在设计时设置一个常量列。换句话说,您不能定义列名/类型/计数可以更改的单个数据流。您是否试图获得可以处理一组动态输入和输出的单一数据流?

标签: sql sql-server ssis etl dynamic-sql


【解决方案1】:

不确定您的第一个数据 sn-p 是否已经在 oracle 表中,但它在 CSV 文件中,那么您可以在加载过程中选择跳过标题。

如果数据已经在表中,那么您可以使用UNION 来获得所需的结果

Select * from table name where rowtype=‘HRD’
union
select * from table name where rowtype=‘DTL’

如果您需要名字等作为列标题,那么您无需执行任何操作。根据您的要求设计目标表列。

【讨论】:

    【解决方案2】:

    抱歉,发布了一个答案,但我完全误解了您在源表中将所需的列标题作为 data

    一个简单的解决方案(尽管它需要更多 IO)是将表数据转储到没有标题的平面文件中,然后将其读回,但这次告诉 SSIS 第一行有标题,并忽略 @987654322 @ 柱子。确保在将数据写入中间文件之前正确排序!

    要转储到没有标题的文件,您必须将ColumnNamesInFirstDataRow 设置为false。在属性窗口中设置它,而不是通过编辑连接。更多信息this thread

    如果你有很多数据,这显然是非常低效的。

    【讨论】:

      【解决方案3】:

      使用row_number 尝试以下操作。这是demo

      with cte as
      (
        select
          *,
          row_number() over (order by id) as rn
        from myTable
      )
      
      select
          ID,
          Col_1 as FirstName,
          Col_2 as LastName,
          Col_3 as Birthdate
      from cte
      where rn > 1
      

      输出:

      | id  | firstname | lastname | birthdate  |
      | --- | --------- | -------- | ---------- |
      | 2   | Steve     | Bramblet | 1989-01-01 |
      | 3   | Bob       | Marley   | 1967-03-12 |
      | 4   | Mickey    | Mouse    | 1921-04-25 |
      

      【讨论】:

      • 感谢@zealous,但你看到我的编辑了吗?数据只是示例,我需要名称为 HDR 行中的值的列,而不是具体的名字、姓氏和出生日期。我希望我解释正确......
      【解决方案4】:

      哦,好吧。有一个纯 SSIS 方法,假设源是一个 SQL 表。在这里,相当粗略。

      1. 创建一个类型为 Object 的变量 oColSet,以及 255 个类型为 String 且名称为 sColName_1、sColName_2 ... sColName_255 的变量。

      2. 使用select top(1) Col_1, Col_2, ... Col_255 from Src where RowType = 'HDR' 之类的查询创建 SQL 任务,在结果集选项卡上设置任务属性 ResultSet = Full Result Set - 将 Result Name 设置为 0 和 变量名oColSet

      3. 添加 ForEach 循环枚举器,将其设置为 ForEach ADO EnumeratorADO 对象源变量 - 设置为 oColSet枚举模式 = 第一个表中的行。然后,在 Variable Mappings 选项卡上 - 定义为这样的示例 (Variable - Index) - sColName_1 - 0, sColName_2 - 1, ... sColName_255 - 254。

      4. 创建一个类型为String变量表达式的变量sSQLQuery

        "SELECT Col_1 AS ["+@[User::sColName_1]+"], 
            Col_2 AS ["+@[User::sColName_2]+"], 
            ...
            Col_255 AS ["+@[User::sColName_255]+"]
         FROM Src WHERE RowType='DTL'" 
        
      5. 在 ForEach 循环中 - 添加您的数据流,在 OLEDB 源中 - 将 数据访问模式 设置为 来自变量的 SQL 命令 并提供变量名称 User::sSQLQuery。在数据流本身上 - 设置 DelayValidation=true

      此设计的主要思想 - 检索所有列名并将其存储在临时变量中(步骤 2)。然后步骤 3 进行解析并将所有结果放入相应的变量中,第 1 列(第 0 列) - 放入 sColName_1 等。步骤 4 将 SQL 命令定义为表达式,每次读取变量时都会对其进行评估。最后,在 ForEach 循环中(解析完成的地方)——你执行你的数据流。

      SSIS 的限制 - 数据类型和列名在运行时应与设计时相同。如果您需要进一步将数据集存储到 SQL 中,请告诉我,以便我调整建议的解决方案。

      【讨论】:

        最近更新 更多