根据文本列的数据长度将额外的行插入结果集

时间:2015-12-02 22:57:56

标签: sql-server sql-server-2005

由于我的报告工具(Rave报告)中的错误导致包含超过X个字符的文本列出错,我需要将结果集中的某些行分成额外的行。 假设我有一个名为“

”的交易表
CREATE TABLE Trans
    (id int, type int, description varchar(55), memo text)
;

INSERT INTO Trans
    (id, type, description, memo)
VALUES
    (1, 1,  'blah', 'hi there'),
    (2, 100, 'foobar', 'yawn'),
    (3, 700, 'emailmessage', 'This some long text that needs to broken into chunks. This some long text that needs to broken into chunks. This some long text that needs to broken into chunks. '),
    (4, 1,   'blah blah blah', 'some other text')
;

看看第三行,它有大约160个字符,让我们说我想要将第3行分成4行,每行包含一个不超过50个字符长的备忘录。查询的最终结果与Trans表的结构相同,但现在有7行。 ID列应重新编号以反映额外的行。我需要它用于SQL Server 2005。

当然额外的行每个都会以正确的顺序具有不同的长备忘录块,但是其他列值将是原始行中值的副本

我知道我可以用光标来做,但我正在寻找更好的方法。

此示例的结果集和50个字符的块大小应如下所示:

id    type  description     memo
----- ----- --------------- -------------------------------------------------
1     1     blah            hi there
2     100   foobar          foobar
3     700   emailmessage    This some long text that needs to broken into chu
4     700   emailmessage    nks. This some long text that needs to broken int
5     700   emailmessage    o chunks. This some long text that needs to broke
6     700   emailmessage    n into chunks.
7     1     blah blah blah  some other text

使块长度成为我可以改变的变量。 提前谢谢。

1 个答案:

答案 0 :(得分:1)

您可以使用50个字符的Tally Tablesplit strings into chunks

SQL Fiddle

DECLARE @Width INT;
SELECT @Width = 50;

WITH E1(N) AS (
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), 
E4(N) AS (SELECT 1 FROM E2 a, E2 b), 
Tally(N) AS (
    SELECT TOP(SELECT MAX(LEN(CAST(memo AS VARCHAR(MAX)))) FROM Trans) 
        ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) 
    FROM E4
)
SELECT
    id = ROW_NUMBER() OVER(ORDER BY tr.id, t.N),
    tr.type,
    tr.description,
    memo = SUBSTRING(CAST(tr.memo AS VARCHAR(MAX)), (t.N-1) * @Width+1, @Width)
FROM Trans tr
CROSS JOIN Tally t
WHERE
    t.N BETWEEN 1 AND LEN(CAST(tr.memo AS VARCHAR(MAX)))/@Width+1
ORDER BY tr.id, t.N
;

此外,您可能希望使用VARCHAR(MAX)而不是TEXT作为TEXT has been deprecated since SQL SEVER 2005.,并且某些字符串操作不适用于TEXT数据类型。

结果:

| id | type |    description |                                               memo |
|----|------|----------------|----------------------------------------------------|
|  1 |    1 |           blah |                                           hi there |
|  2 |  100 |         foobar |                                               yawn |
|  3 |  700 |   emailmessage | This some long text that needs to broken into chun |
|  4 |  700 |   emailmessage | ks. This some long text that needs to broken into  |
|  5 |  700 |   emailmessage | chunks. This some long text that needs to broken i |
|  6 |  700 |   emailmessage |                                       nto chunks.  |
|  7 |    1 | blah blah blah |                                    some other text |