Результат запроса в одной строке или нескольких значениях в одном, разделенных запятой - PullRequest
0 голосов
/ 12 октября 2018

У меня есть три таблицы (магазины, продажи и продукты) со следующей структурой:

--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 голосов
/ 12 октября 2018

Вот, пожалуйста.Вам понадобится функция 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;
0 голосов
/ 12 октября 2018

Прежде всего, вы должны использовать INNER JOIN, а не CROSS APPLY:

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 для группировки данных по магазинам и продуктам, а затем генерировать строки таблицы на основе этого.Если используется ORM-подобная Entity Framework, данные уже будут в правильной структуре.

Для создания необходимой таблицы можно использовать два цикла, например:

<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();

И использовать их для генерации самих заголовков в цикле

...