SQL - 未知项目数时连接值

时间:2015-04-07 18:09:16

标签: sql sql-server tsql concatenation

我目前正在刷新我的SQL知识,并在以下查询中遇到一些困难。

要求是:

对于每个制造商,按字母顺序列出" /"作为他所生产的所有类型产品的分界。

演绎:制造商,产品类型'列表

以下解决方案确实有效,但我并不完全理解......

;with
t1 as 
    (select  maker, type, DENSE_RANK() over(partition by maker  order by type) rn
    from product
),
tr(maker, type,lev) as
    (select distinct t1.maker, cast(t1.type as nvarchar) , 2 from t1 where t1.rn = 1
    union all
    select t1.maker, cast(tr.type +'/'+t1.type as nvarchar), lev + 1
    from t1 join tr on (t1.maker = tr.maker and t1.rn = tr.lev
    )
)

select maker, max(type) names from tr group by maker

这些输出:

1 | A | Laptop/PC/Printer
2 | B | Laptop/PC
3 | C | Laptop
4 | D | Printer
5 | E | PC/Printer

*第二列是制造商,第三列是动态连接的类型列表。

现在,我对lev究竟是如何动态增长感到有些困惑。我在这里缺少某种循环吗? 为什么从2开始? 如果没有"演员"?

,它为什么不起作用

如果有人能够解释这个问题背后的逻辑,我将非常感激。

非常感谢!

1 个答案:

答案 0 :(得分:0)

你正在看的是一个递归的CTE,一个自称的CTE。它是你认为的循环"影响。当我第一次看到它时,递归会在我的大脑中产生扭结。它有助于查看一些示例并尝试创建一些您自己的简单示例。我仍然不是最好的,但我变得更好。我在你的代码中添加了一些注释。希望这会有所帮助。

;WITH t1
AS (
    SELECT  maker,
            type,
            --Partition says each maker is a group so restart at 1
                --Order by type is alphabetic
                --DENSE_RANK() means if there are two the of the same item, they get the same number
            DENSE_RANK() OVER (PARTITION BY maker ORDER BY type) rn
    FROM product
    ),
--This is a recursive CTE meaning a CTE that calls itself(what is doing the "looping"
tr (maker,type,lev)
AS (
    --Grab only the distinct items from your ranked table
    SELECT DISTINCT t1.maker,
        cast(t1.type AS NVARCHAR),
        2 --This is the start of your recursive loop
    FROM t1
    WHERE t1.rn = 1

    UNION ALL

    --Recursively loop through you data, adding each string at the end with the '/'
    SELECT t1.maker,
        cast(tr.type + '/' + t1.type AS NVARCHAR),
        --Plus one to grab the next value
        lev + 1
    FROM t1
    INNER JOIN tr ON (
            --Only match the same makers
            t1.maker = tr.maker
            --Match to the next value
            AND t1.rn = tr.lev
            )
    )

--I think you know what this does
SELECT maker,
    max(type) names
FROM tr
GROUP BY maker