以下是我的源数据的粗略示例:

OrderStatus | CustomerID | OrderNbr | LoadNbr | Product | Quantity
------------+------------+----------+---------+---------+---------
   OPEN     |     1      | ORD00001 |    1    |  0012   | 12
   OPEN     |     1      | ORD00001 |    2    |  0024   | 20

我想要达到的结果是:

 OrderStatus | CustomerID | OrderNbr | Prod01 | Quantity01 | Prod02 | Quantity02 | Ratio01 | Ratio02
-------------+------------+----------+--------+------------+--------+------------+---------+---------
    OPEN     |     1      | ORD00001 |  0012  |     12     |  0024  |   20       |  37.5   |   62.5

为了简洁起见,我只列出了2个产品.但在我得到的数据中,可能有8种以上的产品.

我一直在try 的是:

WITH OrderSummary AS (
  SELECT O.OrderStatus,
         O.CustomerID,
         O.OrderNbr,
         'TotalQty' = I1.Quantity + I2.Quantity,
         'Prod01' = I1.Product,
         'Quantity01' = I1.Quantity,
         'Prod02' = I2.Product,
         'Quantity02' = I2.Quantity
  FROM   Orders O
  LEFT JOIN Orders I1 ON O.OrderNbr = I1.OrderNbr AND I1.LoadNbr = 1
  LEFT JOIN Orders I2 ON O.OrderNbr = I2.OrderNbr AND I1.LoadNbr = 2
)

SELECT  *,
        'Ratio01' = Quantity01 / TotalQty * 100,
        'Ratio02' = Quantity02 / TotalQty * 100
FROM    OrderSummary

这或多或少是我目前正在运行的.但我得到的结果是这样的:

 OrderStatus | CustomerID | OrderNbr | Prod01 | Quantity01 | Prod02 | Quantity02 | Ratio01 | Ratio02
-------------+------------+----------+--------+------------+--------+------------+---------+---------
    OPEN     |     1      | ORD00001 |  0012  |     12     |  0024  |   20       |  37.5   |   62.5
    OPEN     |     1      | ORD00001 |  0012  |     12     |  0024  |   20       |  37.5   |   62.5

因此,我只是try 使用DISTINCT声明运行,这在大多数情况下都是有效的……但是我的样本数据中有顺序,无论如何都会返回重复的行.

So the question I have是我是否从正确的Angular 来处理这个问题.在同一个表上使用联接是将结果压缩到一行的最佳方式吗?或者,有没有更好的方法来实现这一点?我在某种程度上受到我正在工作的环境的限制:我无法控制提供给我的数据格式,并且我must将结果以单行的形式呈现给执行数据库查询的应用程序.

编辑:一些额外的澄清.对于任何给定的订单,状态、客户、订单号等都是相同的.LoadNbr、Product和Quantity行在每个条目之间是唯一的.因此,一个包含8个产品的订单将有8行,我正在try 将其折叠为单行.

推荐答案

在我看来,要做到这一点,最简单的方法是通过"条件聚合",而不是通过"轴运算符".但是,首先,如果您包括一个WHERE子句来隐藏不需要的行,那么现有的查询将会起作用:例如:

WITH OrderSummary
AS (
    SELECT
          O.OrderStatus
        , O.CustomerID
        , O.OrderNbr
        , 'TotalQty' = O.Quantity + I2.Quantity + I3.Quantity + I4.Quantity 
                    + I5.Quantity + I6.Quantity + I7.Quantity + I8.Quantity
        ,     'Prod01' = O.Product
        , 'Quantity01' = O.Quantity
        ,     'Prod02' = I2.Product
        , 'Quantity02' = I2.Quantity
        ,     'Prod03' = I3.Product
        , 'Quantity03' = I3.Quantity
        -- more of the same here
    FROM Orders O
    LEFT JOIN Orders I2 ON O.OrderNbr = I2.OrderNbr AND I2.LoadNbr = 2
    LEFT JOIN Orders I3 ON O.OrderNbr = I3.OrderNbr AND I3.LoadNbr = 3
    LEFT JOIN Orders I4 ON O.OrderNbr = I4.OrderNbr AND I4.LoadNbr = 4
    -- more of the same here
    WHERE O.LoadNbr = 1
    )
SELECT
      *
    , 'Ratio01' = Quantity01 / TotalQty * 100
    , 'Ratio02' = Quantity02 / TotalQty * 100
    , 'Ratio03' = Quantity03 / TotalQty * 100
    -- more of the same here
FROM OrderSummary

但这非常难看,而且有问题(例如,如果缺少任何数量,TotalQty可能为空.

另一种方法是使用如下方法:

SELECT
      OrderStatus     
    , CustomerID     
    , OrderNbr     
    , ca.TotalQty     
    , max(CASE WHEN o.LoadNbr = 1 THEN o.Product ELSE '' END) AS Product1
    , max(CASE WHEN o.LoadNbr = 1 THEN o.Quantity ELSE 0 END) AS Quantity1
    , max(CASE WHEN o.LoadNbr = 1 THEN round(o.Quantity * 100.0 / ca.TotalQty,2) ELSE 0 END) AS Ratio1
    , max(CASE WHEN o.LoadNbr = 2 THEN o.Product ELSE '' END) AS Product2
    , max(CASE WHEN o.LoadNbr = 2 THEN o.Quantity ELSE 0 END) AS Quantity2
    , max(CASE WHEN o.LoadNbr = 2 THEN round(o.Quantity * 100.0 / ca.TotalQty,2) ELSE 0 END) AS Ratio2
    -- more of the same here
FROM Orders AS O
CROSS APPLY (
    SELECT SUM(q.Quantity) AS TotalQty
    FROM Orders AS q
    WHERE q.OrderNbr = o.OrderNbr     
    ) AS ca
GROUP BY
      OrderStatus     
    , CustomerID     
    , OrderNbr  

这也可以设置为"动态",如下所示:

DECLARE @cols AS NVARCHAR(MAX);
DECLARE @sql AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT ', max(CASE WHEN o.LoadNbr = ' 
  + CONVERT(VARCHAR(10), LoadNbr) + ' THEN o.Product ELSE '''' END) AS Product' 
  + CONVERT(VARCHAR(10), LoadNbr) + ', max(CASE WHEN o.LoadNbr = ' 
  + CONVERT(VARCHAR(10), LoadNbr) + ' THEN o.Quantity ELSE 0 END) AS Quantity' 
  + CONVERT(VARCHAR(10), LoadNbr) + ', max(CASE WHEN o.LoadNbr = ' 
  + CONVERT(VARCHAR(10), LoadNbr) + ' THEN round(o.Quantity * 100.0 / ca.TotalQty,2) ELSE 0 END) AS Ratio' 
  + CONVERT(VARCHAR(10), LoadNbr)
             FROM (SELECT DISTINCT LoadNbr FROM Orders) O
             FOR XML PATH(''), TYPE
             ).value('.', 'NVARCHAR(MAX)') 
         ,1,2,'');

select @cols;

SET @sql = 'SELECT OrderStatus
    , CustomerID
    , OrderNbr
    , ca.TotalQty
    , ' + @cols + '
FROM Orders AS O
CROSS APPLY (
    SELECT SUM(q.Quantity) AS TotalQty FROM Orders AS q
    WHERE q.OrderNbr = o.OrderNbr
    ) AS ca
GROUP BY OrderStatus
    , CustomerID
    , OrderNbr
    , ca.TotalQty';

select @sql;

EXEC sp_executesql @sql;

this demonstration

Sql相关问答推荐

如何解决Error:operator is not unique:unknown—unknown在一个动态SQL查询?""""

retrofit AWS Athena中的JSON

删除事务中的本地临时表

使用列表作为参数进行 Select ,如果为空,则在PostgreSQL中不使用参数进行 Select

从数据库中查找总和大于或等于查询中的数字的数字

对表进行多项 Select 以返回最大值和时间

如何实现同一列的递归计算?

缺少日期标识

如何用QuestDB生成蜡烛图?

使用SQL数据库中的现有列派生或修改几个列

从类似JSON的字符串列创建新列

嵌套Json对象的SQL UPDATE WHERE

在Power Bi中将SQL代码转换为DAX

在 R 值的 SQL 块中显示值

将最近的结束日期与开始日期相匹配

PostgreSQL:从多个字段收集特定指标的最后一个条目

没有调用子查询的嵌套 JOIN语法是什么?

如何从三个连接表中获取数据,并始终显示第一个表中的数据,以及第三个表中的空值或现有记录?

将varchar (7)列转换为datetime

SQL:获取连接表的第一个项目