【问题标题】:How to pivot single column table into 2 column table如何将单列表转换为 2 列表
【发布时间】:2020-12-22 17:19:13
【问题描述】:

这是我的问题。我正在输出一个拆分函数,它是一个单列表, 并且需要将输出转置为 2 列。

即假设我使用

SELECT colNum = (((ROW_NUMBER() OVER(ORDER BY(SELECT NULL))) - 1) % 2) + 1
      ,InsertData
FROM fn_split('the quick brown fox jumped over the lazy dog test the quick brown fox jumped over the lazy dog test the quick brown fox jumped over the lazy dog test')`

导致

|colNum|    InsertData                  |
|------|--------------------------------|
|1      |the quick brown fox jumped ove |
|------|--------------------------------|
|2      |r the lazy dog test the quick  |
|------|--------------------------------|
|1      |brown fox jumped over the lazy |
|------|--------------------------------|
|2      | dog test the quick brown fox  |
|------|--------------------------------|
|1      |jumped over the lazy dog test  |
|------|--------------------------------|

我怎么把它变成这个

|-------------------------------|-------------------------------|
|           1                   |               2               |
|-------------------------------|-------------------------------|
|the quick brown fox jumped ove | r the lazy dog test the quick |
|-------------------------------|-------------------------------|
|brown fox jumped over the lazy | dog test the quick brown fox  |
|-------------------------------|-------------------------------|
|jumped over the lazy dog test  |-------------------------------|
|-------------------------------|-------------------------------|

我尝试了所有我知道的方法,但没有任何效果。
我得到了一个支点,但中间有空单元格。
我想我错过了共同因素,但我不确定如何为每个集合生成一个。

【问题讨论】:

  • 什么是fn_split?问题似乎是这样,但我们没有它的代码。
  • “通用”拆分函数将有第二个参数作为分隔符,上面不包含一个。显然它是在分割某些东西的价值,但我不知道是什么,没有 DDL,我们无法复制您的问题。
  • 它是通用的拆分功能。我不能为它发布代码,因为它是我专有的。但总的来说,它接受任何字符串并将其拆分为特定长度的块。实际函数接受第二个参数确定您想要的长度。 FN 仅返回带有拆分字符串的单列。我的选择添加了一个行编号。现在我需要的下一步是获取输出并将其转换为每个连续的行被旋转为 2 列。因此行号在每第三行重置一次。但是有没有办法添加每 2 行重置一次的组号?
  • @Larnu 问题不在于拆分功能。忽略他们问题的那一部分。他们只是想转置数据,以便第 1 列具有 colNum = 1 的值,第 2 列具有 colNum = 2 的值,它们的功能和它的工作原理并不真正相关。
  • 如果它没有返回拆分的序号位置,@ChadBaldwin。以及我为什么要问。

标签: sql-server pivot


【解决方案1】:

假设您的拆分器函数返回序数位置,因为这是一个好的“通用”拆分器所做的,那么您可以使用一点整数数学对其进行分组,并使用模数进行条件聚合:

SELECT MAX(CASE WHEN OrdinalPosition % 2 = 1 THEN InsertData END) AS [1],
       MAX(CASE WHEN OrdinalPosition % 2 = 0 THEN InsertData END) AS [2]
FROM fn_split('the quick brown fox jumped over the lazy dog test the quick brown fox jumped over the lazy dog test the quick brown fox jumped over the lazy dog test') 
GROUP BY (OrdinalPosition - 1) / 2;

db<>fiddle

【讨论】:

  • 不,该函数只返回拆分部分的单个列。从函数中选择时,我会添加行数。也就是说,我已经有了使用上面的 Chad Baldwin 答案的代码。谢谢
  • 这就是为什么我问它是做什么的,@vlad,因为,就像我说的,一个好的“通用”分割函数告诉你序数位置。
【解决方案2】:

编辑:

这是新的解决方案,更适合作为复制粘贴供您使用,因为我使用的表值构造函数类似于您使用 fn_split 函数处理的内容。

WITH cte_fnsplit AS (
    SELECT fn_split.InsertData
        , rn = ROW_NUMBER() OVER (ORDER BY 1/0)
    FROM (
        VALUES ('the quick brown fox jumped ove')
            ,  ('r the lazy dog test the quick ')
            ,  ('brown fox jumped over the lazy')
            ,  (' dog test the quick brown fox ')
            ,  ('jumped over the lazy dog test')
    ) fn_split(InsertData)
)
SELECT x.rn, x.InsertData, x.NextValue
FROM (
    SELECT yt.rn, yt.InsertData
        , NextValue = LEAD(yt.InsertData) OVER (ORDER BY yt.rn)
    FROM cte_fnsplit yt
) x
WHERE x.rn % 2 = 1

在这种情况下,您应该能够用您的 fn_split 函数替换我的表值构造函数并获得您期望的结果。

值得注意的是,通过在fn_split 函数之外生成行号,行可能不会以保证的顺序返回。虽然可能不太可能,但仍有可能发生(类似于STRING_SPLIT()

如果可以的话,我的建议是在fn_split 的输出中添加某种排序列。它可能是您正在构建的表变量中的标识值。或者它可能只是字符串中 sn-p 的起点。这可能是您已经拥有的信息,并且可能不会影响函数的性能。


编辑:这是原来的旧解决方案

因此,要稍微偏离您最初的尝试,您可以尝试类似的方法 这个:

WITH cte_fnsplit AS (
    SELECT fn_split.InsertData
        , rn = ROW_NUMBER() OVER (ORDER BY 1/0)
    FROM (
        VALUES ('the quick brown fox jumped ove')
            ,  ('r the lazy dog test the quick ')
            ,  ('brown fox jumped over the lazy')
            ,  (' dog test the quick brown fox ')
            ,  ('jumped over the lazy dog test')
    ) fn_split(InsertData)
)
SELECT x.rn, x.InsertData, x.NextValue
FROM (
    SELECT yt.rn, yt.InsertData
        , NextValue = LEAD(yt.InsertData) OVER (ORDER BY yt.rn)
    FROM cte_fnsplit yt
) x
WHERE x.rn % 2 = 1

返回:

| colNum | InsertData                     | NextValue                      | 
|--------|--------------------------------|--------------------------------| 
| 1      | the quick brown fox jumped ove | r the lazy dog test the quick  | 
| 3      | brown fox jumped over the lazy |  dog test the quick brown fox  | 
| 5      | jumped over the lazy dog test  | NULL                           | 

解释:

所以我首先使用LEAD() 窗口函数在数据集中查找“下一个值”。这几乎就像在 colNum = colNum + 1 类型的事情中进行自联接。

然后,我把它放在一个子查询中,这样我就可以给LAG() 函数命名为NextValue

然后我过滤结果只给我奇数行。

【讨论】:

  • 如果不是因为权力不限制使用任何 tempdb 结构等,那将是完美的。如果我不能在单选中做到这一点,我将不得不找出另一种方式。我想我会问是否有人比我的想法更好:-)
  • 我只使用 tempdb,因为我需要创建一个包含示例数据的表。可以使用您的拆分功能替换查询本身。给我一点时间来更新它以更好地适应你的情况。
  • 我正在以某种方式使用 CTE,但还不能让它工作
  • @vlad 查看最新更新(可能需要刷新页面),我已更新我的答案以使用 CTE 并通过消除临时表更好地满足您的需求。
  • 乍得,你是最棒的。 CTE 非常适合我需要做的事情。我不知道为什么我和 PIVOT 玩了这么久。昨晚应该试试 CTE
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 2017-01-21
相关资源
最近更新 更多