查询结果是单行还是多个值,逗号分隔

时间:2018-10-12 14:50:59

标签: sql tsql sql-server-2012 pivot transpose

我有三个具有以下结构的表(商店,销售和产品):

--Stores
IdStore   StoreName
1A        Store A
2B        Store B
3C        Store C

-- Products
IdProduct   Desc
1G          Product 1
2A          Product 2
3A          Product 3
4A          Product 4

--Sales
TicketNo  Store     Product     Qty
1001      Store A   Product 1   10
1002      Store A   Product 1   10
1003      Store B   Product 3   50
1004      Store A   Product 2   20
1005      Store A   Product 3   5
1006      Store B   Product 1   30

目前,我有以下查询:

SELECT S.StoreName, sum(SA.Qty), P.Desc
FROM SALES SA
cross apply (select top 1 * from Stores S where SA.Store = S.StoreName) S
cross apply (select top 1 * from Products P where SA.Product = P.Desc) P
group by S.StoreName, P.Desc

根据上述表结构和数据,查询结果如下:

-- output
StoreName    Qty   Desc
Store A      20    Product 1
Store A      20    Product 2
Store A      5     Product 3
Store B      30    Product 1
Store B      20    Product 2

我的问题是,是否存在一种获得相同结果但顺序不同的方法,以及是否有可能从同一行的一个商店中获取所有结果,像这样:

Store    Product 1  Product 2  Product 3
Store A  20         20         5    
Store B  30         20         0

或类似的东西

Store     Result (in same line)
Store A   20;20;5;
Store B   30;20;0;

2 个答案:

答案 0 :(得分:2)

首先,您应该使用INNER JOIN而不是交叉应用:

SELECT S.StoreName, P.Desc,sum(SA.Qty) as QTY
FROM SALES SA
    INNER JOIN Stores S ON SA.Store = S.StoreName
    INNER JOIN Products P ON SA.Product = P.Desc
group by S.StoreName, P.Desc

如果事先知道列数,则可以使用PIVOT运算符将行转换为列:

SELECT S.StoreName, [Product 1], [Product 2], [Product 3]
FROM 
( SELECT SA.StoreName, P.Desc,SA.Qty
  FROM SALES SA
    INNER JOIN Stores S ON SA.Store = S.StoreName
    INNER JOIN Products P ON SA.Product = P.Desc
) Q
PIVOT 
(
    SUM(Qty)
    FOR Q.Desc IN ([Product 1], [Product 2], [Product 3])
) AS pvt
ORDER BY StoreName

但是坦率地说,在客户端上生成适当的表可能会更容易。 PIVOT无法处理任意数量的列。另一方面,在ASP.NET中,可以使用LINQ等按商店和产品对数据进行分组,然后根据该数据生成表行。如果使用了像Entity Framework这样的ORM,则数据将已经处于适当的结构中。

生成所需表可以使用两个循环,例如:

<thead>
    <tr>
        <th>Store Name</th>
        <th>Product 1</th>
        ...
    </tr>
</thead>
@foreach(var store in Model.Stores)
{
    <tr>
        <td>@store.StoreName</td>
        @foreach(var product in store.Products.OrderBy(p=>p.Desc))
        {
           <td>@product.Qty</td>
        }
    </tr>
}

您可以使用LINQ获得所有产品名称,例如:

var productNames = Stores.SelectMany(store=>store.Products)
                         .Select(p=>p.Desc)
                         .Distinct()
                         .OrderBy(desc=>desc)
                         .ToArray();

并使用它们来循环生成标头

答案 1 :(得分:1)

您在这里。您将需要PIVOT函数,但需要定义产品的名称。

在下面查看样机:

DECLARE @Stores TABLE(IdStore VARCHAR(100),[StoreName] VARCHAR(100));
INSERT INTO @Stores 
--Stores
select '1A','Store A' UNION ALL
select '2B','Store B' UNION ALL
select '3C','Store C'


DECLARE @Products TABLE(IdProduct VARCHAR(100),[Desc] VARCHAR(100));
INSERT INTO @Products 
-- Products
select '1G','Product 1' UNION ALL
select '2A','Product 2' UNION ALL
select '3A','Product 3' UNION ALL
select '4A',' Product 4'

DECLARE @Sales TABLE(TicketNo INT, Store  VARCHAR(100),[Product] VARCHAR(100), Qty INT);
INSERT INTO @Sales
--Sales
select '1001','Store A','Product 1','10' UNION ALL
select '1002','Store A','Product 1','10' UNION ALL
select '1003','Store B','Product 3','50' UNION ALL
select '1004','Store A','Product 2','20' UNION ALL
select '1005','Store A','Product 3','5' UNION ALL
select '1006','Store B','Product 1','30'




SELECT p.*
FROM 
(
    SELECT S.StoreName, SA.Qty, P.[Desc]
    FROM
        @SALES SA
    left join @Stores S on SA.Store = S.StoreName
    left join  @Products P on SA.Product = P.[Desc] 

)t
PIVOT
(
    SUM(Qty) FOR [Desc] IN ([Product 1],[Product 2],[Product 3] /*add as many as you need*/)
)p;