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

Inserting extra rows into a result set based on the data length of a text column

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

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 table 的结构相同,但现在有 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

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

您可以使用 Tally Table to split strings into chunks 50 个字符。

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 |