创建一个SQL CTE以使用varchar(max)自动递增

时间:2013-07-17 21:26:02

标签: sql-server tsql common-table-expression row-number

我有以下CTE:

;WITH combo (id, [program_name]) AS
(
    SELECT
    1
    , CAST('' AS VARCHAR(MAX))
    UNION ALL
    SELECT
        cte.id + 1
        ,(cte.[program_name] + pl.[program_name] + '; ')
    FROM (
        SELECT
        RowNum = ROW_NUMBER() OVER (ORDER BY people_id)
        --people_id
        ,p.[program_name]
        FROM event_log_Rv E
        JOIN PROgrams_view p on p.program_info_id = e.program_providing_service
 where people_id = 'DFA3AFE5-F681-4B1B-89F0-31D04FA6BF7D'
   ) pl
    JOIN combo cte ON pl.RowNum = cte.id
)
SELECT TOP 1 id, [program_name] FROM combo ORDER BY id DESC

当我运行此CTE时,我收到此错误:

  

Msg 530,Level 16,State 1,Line 1
  声明终止。在语句完成之前,最大递归100已经用尽。

people_idprogram_providing_serviceuniqueidentifier数据类型。

如何在列表中添加列出行号的CTE?我最终想做的是让这个CTE显示所有程序/客户端。

我试图通过在此CTE中添加行号以加入CTE和组合来实现此功能,但如果您能想到以不同的方式在一行中显示所有程序/客户端,我可以接受这一点。

例如,我想:

people_id                               Programs
DFA3AFE5-F681-4B1B-89F0-31D04FA6BF7D    IHS; MCP; DCS

1 个答案:

答案 0 :(得分:1)

逗号分隔列表中的一对多关系放在一个列中,它会占用很多行并将它们放在一个'(char)'分隔列表中?我使用xml类型,因为你可以拥有可能随时间变化的复杂结构。对于那种恕我直言,递归非常激烈。

这是一个自我提取的例子,下面我将解释它:

declare @Person Table ( personID int identity, person varchar(8));

insert into @Person values ('Brett'),('Sean'),('Chad'),('Michael'),('Ray'),('Erik'),('Queyn');

declare @Orders table ( OrderID int identity, PersonID int, Desciption varchar(32), Amount int);

insert into @Orders values (1, 'Shirt', 20),(1, 'Shoes', 50),(2, 'Shirt', 22),(2, 'Shoes', 52),(3, 'Shirt', 20),(3, 'Shoes', 50),(3, 'Hat', 20),(4, 'Shirt', 20),(5, 'Shirt', 20),(5, 'Pants', 30),
(6, 'Shirt', 20),(6, 'RunningShoes', 70),(7, 'Shirt', 22),(7, 'Shoes', 40),(7, 'Coat', 80)

Select top 100
    p.person
,   o.Desciption
from @Person p
    join @Orders o on p.personID = o.PersonID
order by p.person

Select 
    p.person
,   replace(
        replace(
            replace(
            (
                select
                    o.Desciption as d
                from @Orders o
                where o.PersonID = p.personID
                for xml auto
            ), '"/><o d="', ', ')
        , '<o d="', '') 
    , '"/>', '') as SeperatedList
from @Person p
order by p.person
  1. 我正在进行嵌套选择以获取父对象(我的示例中的人)的所有子元素(在我的示例命令中)。
  2. 您不能将TSQL中的数组作为列返回....除非将其存储为xml,它可以将其自己的多元素树结构存储为单个列。
  3. 自然'对于xml auto'会给我回文本而不是xml类型(有点酷)。我遗漏了很多东西,只有使用'FOR XML(something)'有一整页白皮书。 Auto假设元素名称是我的别名'o',而我的列名为'd',它成为一个属性。
    1. 由于演员表默认为文字,我不必担心演员问题,因为我需要做一些查找和替换
    2. 我基本上找到了我为元素和列应用的标签,并使用列分隔符'替换()'它们。我选择',',你可以随意使用。
    3. 我用另外两个替换end和begin元素。你现在有一个'(char)'分隔列表。
  4. 这种方法效果很好,因为它将子分组放在它自己的数据集中,而且我所看到的通常比粘贴到现有字符串的字符串操作快得多,因为你必须使用这种方法,一旦加上内存,一次加内存加内存,一次加内存加内存....你明白了。此方法立即获取数据集的所有内容,然后仅将结果评估给最终用户。如果您有数百万个子行且速度很慢,我会先考虑转储到CTE,表变量或临时表,然后再将它们作为XML列进行转换。