【问题标题】:divide one record into multiple ones将一条记录分成多条
【发布时间】:2016-04-23 02:16:12
【问题描述】:

我需要一个查询来改变这个:

col1 col2 col3
1    2    abc
3    4    cd
4    5    null

到这里

col1 col2 col3
1    2    a
1    2    b
1    2    c
3    4    c
3    4    d
4    5    NULL

谢谢。

【问题讨论】:

  • 能否将(3, 4, 'de') 和(4, 5, null) 加到样本数据中,并调整结果?
  • 请发布您的试用查询
  • 感谢您的回复,但我不确定我是否完全理解这个问题。您能否进一步澄清一下?
  • @JoeTaras 我还在想办法……所以我现在没有什么要分享的:)
  • 如果你将我建议的两行添加到你的问题的样本数据中,并调整预期的结果,每个人都会更容易理解你想要什么。

标签: sql sql-server tsql


【解决方案1】:

这样试试

编辑流水号的较短语法

EDIT2 JamieD77 的评论将TOP 包含在数字的创建中

CREATE FUNCTION dbo.SingleChars(@SomeText NVARCHAR(MAX))
RETURNS TABLE
AS
RETURN
WITH nr10 AS
(
    SELECT * FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS tbl(A)
)
,RunningNumbers AS
(
    SELECT TOP (ISNULL(LEN(@SomeText),0)) ROW_NUMBER() OVER(ORDER BY (SELECT(NULL))) AS Nmbr FROM nr10,nr10 AS a,nr10 AS b,nr10 AS c,nr10 AS d,nr10 AS e,nr10 AS f,nr10 AS g
)
SELECT SUBSTRING(@SomeText,Nmbr,1) AS TheCharacter
      ,ASCII(SUBSTRING(@SomeText,Nmbr,1)) AS ASCII_Code
FROM RunningNumbers;

测试

SELECT * FROM dbo.SingleChars('This is a test');

结果

T   84
h   104
i   105
s   115
    32
i   105
s   115
    32
a   97
    32
t   116
e   101
s   115
t   116

现在你的问题

DECLARE @tbl TABLE(col1 INT, col2 INT, col3 VARCHAR(100));
INSERT INTO @tbl VALUES(1,2,'abc'),(3,4,'cd'),(4,5,NULL);

SELECT col1,col2,sc.TheCharacter
FROM @tbl
OUTER APPLY dbo.SingleChars(col3) AS sc;

结果

1   2   a
1   2   b
1   2   c
3   4   c
3   4   d
4   5   NULL

【讨论】:

  • 不错! col3 的长度有限制吗?
  • 这个SELECT * FROM dbo.SingleChars(REPLICATE('1234567890',1000)); 几乎立即生成 8000 行 :-) 所以是的,限制是 VARCHAR 的 8000 个字符的限制...
  • (已编辑,是“我的意思是字符串值长度,如果 col3 包含 abcdefghijklmnopqrstuvwxyz 会起作用吗?”)太好了!
  • @jarlh,是的,为什么不呢?它甚至可以处理诸如换行之类的不可见字符... RunningNumber-tally 通过动态TOP 语句减少到“真实”数量
  • 我首先被 WITH nr10 AS ... (1)... 的东西弄糊涂了。
【解决方案2】:

在 MSSQL 中,您可以使用 recursive CTE。每一步只需要一个左字母:

WITH T1 as 
(
  SELECT col1,col2,LEFT(col3,1) as col4, SUBSTRING(col3,2,10000) as col3 
         FROM Table1
  UNION ALL
  SELECT col1,col2,LEFT(col3,1) as col4, SUBSTRING(col3,2,10000) as col3 
         FROM T1 WHERE Col3 <> ''
)

SELECT col1,col2,col4 FROM T1 ORDER BY col1,col2;

还有一个查询:

WITH T1 as 
(
  SELECT col1,col2,LEFT(col3,1) as col4, col3, 2 as nextPoint  
         FROM Table1
  UNION ALL
  SELECT col1,col2,SUBSTRING(col3,nextPoint,1) as col4, col3, 
         nextPoint+1 as nextPoint  
         FROM T1 WHERE LEN(col3)>=nextPoint
)
SELECT col1,col2,col4 FROM T1 ORDER BY col1,col2;

【讨论】:

  • 我也喜欢你的。出于好奇,我用 30.000 行检查了这个。您的 rec CTE 在大约 4 秒内解决了挑战(这已经相当快了),我的方法大约需要 2 秒。但无论如何值得一票
  • @Shnugo:谢谢(也+1)。你能不能也试试第二个查询。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-06
  • 2012-08-16
  • 2017-02-24
  • 2019-02-18
  • 2022-10-14
  • 1970-01-01
相关资源
最近更新 更多