如何查询以创建一组集合

时间:2009-12-01 13:33:08

标签: sql-server-2005 tsql

我有一个普通的连接表,其中有两列是其他表的键。记录是映射到一系列资产的客户。

asset_map  
-----------

customer_id    asset_id
-----------------------
     1            1
     1            2
     2            1
     2            2
     3            1
     3            2
     3            3
     4            1
     4            2

大约有10个资产,每个客户都可以映射到这些资产的任意组合。我想要实现的是这样的:

grouping    customer_id    asset_id
------------------------------------
    1            1            1
    1            1            2
    1            2            1
    1            2            2  
- - - - - - - - - - - - - - - - - - 
    2            3            3
    2            3            1
    2            3            2  
- - - - - - - - - - - - - - - - - - 
    1            4            1
    1            4            2

请注意,客户1,2和4属于相同的分组,因为它们映射到资产1和2.客户3不在分组中,而是在1,2和3中。

2 个答案:

答案 0 :(得分:1)

您可以尝试这样的事情

DECLARE @Table TABLE(
    customer_id INT,
    asset_id INT
)

INSERT INTO @Table (customer_id,asset_id) SELECT 1,1
INSERT INTO @Table (customer_id,asset_id) SELECT 1,2
INSERT INTO @Table (customer_id,asset_id) SELECT 2,1
INSERT INTO @Table (customer_id,asset_id) SELECT 2,2
INSERT INTO @Table (customer_id,asset_id) SELECT 3,1
INSERT INTO @Table (customer_id,asset_id) SELECT 3,2
INSERT INTO @Table (customer_id,asset_id) SELECT 3,3
INSERT INTO @Table (customer_id,asset_id) SELECT 4,1
INSERT INTO @Table (customer_id,asset_id) SELECT 4,2

SELECT  * 
FROM    @Table

;WITH CTE AS (
        SELECT  *,
                ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY customer_id, asset_id) RowNumber
        FROM    @Table
),
CTELinked AS (
        SELECT  customer_id,asset_id, RowNumber,
                CAST(CAST(asset_id AS VARCHAR(10)) AS VARCHAR(MAX)) Grouped
        FROM    CTE
        WHERE   RowNumber = 1
        UNION ALL
        SELECT  c.customer_id,c.asset_id, c.RowNumber,
                CAST(CTELinked.Grouped + ',' + CAST(c.asset_id AS VARCHAR(10)) AS VARCHAR(MAX))
        FROM    CTE c INNER JOIN
                CTELinked ON c.customer_id = CTELinked.customer_id AND c.RowNumber  = CTELinked.RowNumber + 1
),
CTEConcat AS (
        SELECT  CTELinked.*
        FROM    CTELinked INNER JOIN
                (
                    SELECT customer_id, MAX(RowNumber) MaxRows
                    FROM CTELinked
                    GROUP BY customer_id
                ) Maxes ON CTELinked.customer_id = Maxes.customer_id AND CTELinked.RowNumber = Maxes.MaxRows
)
SELECT  g.GroupingID,
        c.customer_id,
        t.asset_id
FROM    CTEConcat c INNER JOIN
        (
            SELECT  Grouped,
                    ROW_NUMBER() OVER(ORDER BY Grouped) GroupingID
            FROM    (
                        SELECT  DISTINCT 
                                Grouped
                        FROM    CTEConcat
                    ) sub
        ) g ON c.Grouped = g.Grouped INNER JOIN
        @Table t ON c.customer_id = t.customer_id

使用sp和CURSOR X进行编辑 - (

这应该有点帮助

DECLARE @customer_id INT
    DECLARE CUR CURSOR FOR 
    SELECT DISTINCT customer_id FROM @Table

    OPEN CUR
    FETCH NEXT FROM CUR INTO @customer_id

    DECLARE @CustTable TABLE(
            customer_id INT,
            assetids VARCHAR(MAX)
    )
    DECLARE @CustTableIDS TABLE(
            ID INT IDENTITY(1,1),
            assetids VARCHAR(MAX)
    )

    WHILE @@FETCH_STATUS = 0
    BEGIN
        DECLARE @ConCats AS VARCHAR(MAX)
        SET @ConCats = NULL
        SELECT  @ConCats = COALESCE(@ConCats + ',' + CAST(asset_id AS VARCHAR(50)), CAST(asset_id AS VARCHAR(50)))
        FROM    @Table
        WHERE   customer_id = @customer_id
        ORDER BY asset_id

        INSERT INTO @CustTable SELECT @customer_id, @ConCats
        IF NOT EXISTS(SELECT 1 FROM @CustTableIDS WHERE assetids = @ConCats) 
        BEGIN
            INSERT INTO @CustTableIDS SELECT @ConCats
        END

        FETCH NEXT FROM CUR INTO @customer_id
    END

    CLOSE CUR
    DEALLOCATE CUR

    SELECT  * 
    FROM    @Table

    SELECT  ctid.ID,
            ct.customer_id,
            t.asset_id 
    FROM    @CustTableIDS ctid INNER JOIN
            @CustTable ct ON ctid.assetids = ct.assetids INNER JOIN
            @Table t ON ct.customer_id = t.customer_id

答案 1 :(得分:1)

WITH    rows (customer_id, asset_id) AS
        (
        SELECT  1, 1
        UNION ALL
        SELECT  1, 2
        UNION ALL
        SELECT  2, 1
        UNION ALL
        SELECT  2, 2
        UNION ALL
        SELECT  3, 1
        UNION ALL
        SELECT  3, 2
        UNION ALL
        SELECT  3, 3
        UNION ALL
        SELECT  4, 1
        UNION ALL
        SELECT  4, 2
        )
SELECT  (
        SELECT  CAST(asset_id AS VARCHAR(10)) + '.' AS [text()]
        FROM    rows ri
        WHERE   ri.customer_id = ro.customer_id
        ORDER BY
                asset_id
        FOR XML PATH('')
        ) AS assets,
        ra.*
FROM    (
        SELECT  DISTINCT customer_id
        FROM    rows
        ) ro
JOIN    rows ra
ON      ra.customer_id = ro.customer_id