在一个单元格中返回多行

时间:2023-01-29 22:17:56

So I've looked around and seen the XML trick and the Variable trick, and neither really made enough sense to me to implement. What I have is a table with 4 Columns, The first is a unique identifier, the second is a relation to a different table, the third is varbinary(max), the last is a string. I want to combine columns three and four over column two. Is this possible?

所以我环顾四周,看到了XML技巧和变量技巧,而且我没有真正理解我的实施。我所拥有的是一个包含4列的表,第一个是唯一标识符,第二个是与不同表的关系,第三个是varbinary(max),最后一个是字符串。我想在第二列上合并第三列和第四列。这可能吗?

Example of Data:

数据示例:

| FileId  |  UniqueI1  |  BinaryData  | FileName |
|---------+------------+--------------+----------|
|   1     |     1      |    <byte>    | asp.jpg  |
|   2     |     1      |    <byte>    | asp1.jpg |
|   3     |     2      |    <byte>    | asp2.jpg |
|   4     |     2      |    <byte>    | asp3.jpg |
|   5     |     2      |    <byte>    | asp4.jpg |

Preferred Output:

|  UniqueI1  |          BinaryData          |          FileName            |
|------------+------------------------------+------------------------------|
|     1      |    <byte>, <byte>            | asp.jpg, asp1.jpg            |
|     2      |    <byte>, <byte>, <byte>    | asp2.jpg, asp3.jpg, asp4.jpg |    

I appreciate any help you may be able to provide me.

我感谢您提供给我的任何帮助。

2 个解决方案

#1


1  

Sounds like you're trying to group your data and aggregate the BinaryData and FileName columns by concatenating their values.

听起来您正在尝试对数据进行分组,并通过连接它们的值来聚合BinaryData和FileName列。

There are no built-in aggregates for concatenation in t-sql, but there are a couple of ways to reach the same results.

在t-sql中没有用于连接的内置聚合,但有几种方法可以达到相同的结果。

In my opinion, by far the easiest way is to write a custom aggregate in c# leveraging the CLR. But it can also be done using STUFF or XML. You should have a look at Does T-SQL have an aggregate function to concatenate strings?

在我看来,到目前为止最简单的方法是在c#中利用CLR编写自定义聚合。但它也可以使用STUFF或XML完成。您应该看看T-SQL是否具有连接字符串的聚合函数?

#2


0  

Try this:

DECLARE @t TABLE
    (
      FileID INT ,
      UniqueID INT ,
      Data VARBINARY(100) ,
      FileName VARCHAR(10)
    )

INSERT  INTO @t
VALUES  ( 1, 1, 1, 'asp.jpg' ),
        ( 2, 1, 2, 'asp1.jpg' ),
        ( 3, 2, 3, 'asp2.jpg' ),
        ( 4, 2, 4, 'asp3.jpg' ),
        ( 5, 2, 5, 'asp4.jpg' )


SELECT  UniqueID ,
        MAX(ca.data) AS Data,
        MAX(ca.name) AS Name
FROM    @t t1
        CROSS APPLY ( SELECT    STUFF(
                   (SELECT  ', ' + CONVERT(VARCHAR(MAX), t2.Data, 2)
                    FROM    @t t2
                    WHERE   t1.UniqueID = t2.UniqueID
                    ORDER BY FileID                  
                                FOR   XML PATH('') ,
                                          TYPE
                   ).value('.', 'varchar(max)'), 1, 2, '') AS DATA ,
                                STUFF(
                   (SELECT  ', ' + t2.FileName
                    FROM    @t t2
                    WHERE   t1.UniqueID = t2.UniqueID
                    ORDER BY FileID                  
                                FOR   XML PATH('') ,
                                          TYPE
                   ).value('.', 'varchar(max)'), 1, 2, '') AS NAME
                    ) ca
GROUP BY UniqueID

Output:

UniqueID    Data                            Name
1           00000001, 00000002              asp.jpg, asp1.jpg
2           00000003, 00000004, 00000005    asp2.jpg, asp3.jpg, asp4.jpg

For pivoting:

WITH    cte
          AS ( SELECT   * ,
                        ROW_NUMBER() OVER ( PARTITION BY UniqueID ORDER BY FileID ) AS rn
               FROM     @t
             )
    SELECT  c.UniqueID ,
            ca1.[1] AS Data1 ,
            ca1.[2] AS Data2 ,
            ca1.[3] AS Data3 ,
            ca2.[1] AS File1 ,
            ca2.[2] AS File2 ,
            ca2.[3] AS File3
    FROM    cte c
            CROSS APPLY ( SELECT    *
                          FROM      ( SELECT    UniqueID ,
                                                rn ,
                                                Data
                                      FROM      cte ci
                                      WHERE     ci.UniqueID = c.UniqueID
                                    ) t PIVOT( MAX(Data) FOR rn IN ( [1], [2], [3] ) ) p
                        ) ca1    
            CROSS APPLY ( SELECT    *
                          FROM      ( SELECT    UniqueID ,
                                                rn ,
                                                FileName
                                      FROM      cte ci
                                      WHERE     ci.UniqueID = c.UniqueID
                                    ) t PIVOT( MAX(FileName) FOR rn IN ( [1], [2], [3] ) ) p
                        ) ca2
    GROUP BY c.UniqueID, ca1.[1], ca1.[2], ca1.[3], ca2.[1], ca2.[2], ca2.[3]

Output:

UniqueID    Data1       Data2       Data3       File1     File2     File3
1           0x00000001  0x00000002  NULL        asp.jpg   asp1.jpg  NULL
2           0x00000003  0x00000004  0x00000005  asp2.jpg  asp3.jpg  asp4.jpg

You can change this to dynamic query if you don't want to manually add additional files.

如果您不想手动添加其他文件,可以将其更改为动态查询。

#1


1  

Sounds like you're trying to group your data and aggregate the BinaryData and FileName columns by concatenating their values.

听起来您正在尝试对数据进行分组,并通过连接它们的值来聚合BinaryData和FileName列。

There are no built-in aggregates for concatenation in t-sql, but there are a couple of ways to reach the same results.

在t-sql中没有用于连接的内置聚合,但有几种方法可以达到相同的结果。

In my opinion, by far the easiest way is to write a custom aggregate in c# leveraging the CLR. But it can also be done using STUFF or XML. You should have a look at Does T-SQL have an aggregate function to concatenate strings?

在我看来,到目前为止最简单的方法是在c#中利用CLR编写自定义聚合。但它也可以使用STUFF或XML完成。您应该看看T-SQL是否具有连接字符串的聚合函数?

#2


0  

Try this:

DECLARE @t TABLE
    (
      FileID INT ,
      UniqueID INT ,
      Data VARBINARY(100) ,
      FileName VARCHAR(10)
    )

INSERT  INTO @t
VALUES  ( 1, 1, 1, 'asp.jpg' ),
        ( 2, 1, 2, 'asp1.jpg' ),
        ( 3, 2, 3, 'asp2.jpg' ),
        ( 4, 2, 4, 'asp3.jpg' ),
        ( 5, 2, 5, 'asp4.jpg' )


SELECT  UniqueID ,
        MAX(ca.data) AS Data,
        MAX(ca.name) AS Name
FROM    @t t1
        CROSS APPLY ( SELECT    STUFF(
                   (SELECT  ', ' + CONVERT(VARCHAR(MAX), t2.Data, 2)
                    FROM    @t t2
                    WHERE   t1.UniqueID = t2.UniqueID
                    ORDER BY FileID                  
                                FOR   XML PATH('') ,
                                          TYPE
                   ).value('.', 'varchar(max)'), 1, 2, '') AS DATA ,
                                STUFF(
                   (SELECT  ', ' + t2.FileName
                    FROM    @t t2
                    WHERE   t1.UniqueID = t2.UniqueID
                    ORDER BY FileID                  
                                FOR   XML PATH('') ,
                                          TYPE
                   ).value('.', 'varchar(max)'), 1, 2, '') AS NAME
                    ) ca
GROUP BY UniqueID

Output:

UniqueID    Data                            Name
1           00000001, 00000002              asp.jpg, asp1.jpg
2           00000003, 00000004, 00000005    asp2.jpg, asp3.jpg, asp4.jpg

For pivoting:

WITH    cte
          AS ( SELECT   * ,
                        ROW_NUMBER() OVER ( PARTITION BY UniqueID ORDER BY FileID ) AS rn
               FROM     @t
             )
    SELECT  c.UniqueID ,
            ca1.[1] AS Data1 ,
            ca1.[2] AS Data2 ,
            ca1.[3] AS Data3 ,
            ca2.[1] AS File1 ,
            ca2.[2] AS File2 ,
            ca2.[3] AS File3
    FROM    cte c
            CROSS APPLY ( SELECT    *
                          FROM      ( SELECT    UniqueID ,
                                                rn ,
                                                Data
                                      FROM      cte ci
                                      WHERE     ci.UniqueID = c.UniqueID
                                    ) t PIVOT( MAX(Data) FOR rn IN ( [1], [2], [3] ) ) p
                        ) ca1    
            CROSS APPLY ( SELECT    *
                          FROM      ( SELECT    UniqueID ,
                                                rn ,
                                                FileName
                                      FROM      cte ci
                                      WHERE     ci.UniqueID = c.UniqueID
                                    ) t PIVOT( MAX(FileName) FOR rn IN ( [1], [2], [3] ) ) p
                        ) ca2
    GROUP BY c.UniqueID, ca1.[1], ca1.[2], ca1.[3], ca2.[1], ca2.[2], ca2.[3]

Output:

UniqueID    Data1       Data2       Data3       File1     File2     File3
1           0x00000001  0x00000002  NULL        asp.jpg   asp1.jpg  NULL
2           0x00000003  0x00000004  0x00000005  asp2.jpg  asp3.jpg  asp4.jpg

You can change this to dynamic query if you don't want to manually add additional files.

如果您不想手动添加其他文件,可以将其更改为动态查询。