如何获取 1 条记录作为结果,包括左连接和循环?

问题描述 投票:0回答:2

我遇到了一个我自己无法解决的情况,希望获得支持如何解决它: 我目前正在 SQL Server 18 上构建一个数据仓库。在临时数据库中,我有一个 SoLine 表,它组合了多个 Oracle 表中的数据。这些表中有 ONT.OE_Order_Price_Attribs,其中包含要连接到基表 ONT.OE_Order_Lines_All 的 Header_Id 和 Line_Id:


SELECT
    OL.*,
    OPA.*
FROM ONT.OE_Order_Lines_All OL

LEFT JOIN ONT.OE_Order_Price_Attribs OPA
    ON OL.Header_Id = OPA.Header_Id
    AND OL.Line_Id = OPA.Line_Id

OPA 有时每个 Header_Id、Line_Id 和 Last_Update_Date 包含多个记录(因此这些记录包含所有相同的值):

标题_Id 线路_Id 最后更新日期 定价_上下文 订单_价格_属性_Id Att1 Att2 Att3 Att4 Att5
123 456 2023-12-13 10:00:00 01 789 A B C D E
123 456 2023-12-13 10:00:00 01 790 A B C D F

除了 Order_Price_Attrib_Id 列之外,其余列也相同。但 att* 列可能相同或不同。

我想要实现的是我只有 1 条记录作为结果。如果 Header_Id、Line_Id 和 Last_Update_Date 列相同,则应显示具有最新 Order_price_Attrib_Id 的记录。因此,在上面的示例中,Id 为 790,无论 att* 是否相同或不同。但我确实想看看 att* 列

因此,对于订单行表中的每个 Header_Id 和 Line_Id 组合,都需要根据 SoLine 表中每条记录的 Order_Price_Attrib_Id 找到 attrib 表的最新 Header_Id 和 Line_id。 因此(至少我认为)需要一个循环来找到每个组合。

我尝试在 Order_Price_Attrib_Id 上使用 MAX 函数,但遗憾的是没有成功。我还尝试使用带有 count(*) 等的子查询。但不幸的是到目前为止还没有结果。

我很难编写这些更高级/更困难的查询,因为我不是编写查询的真正专家。我可以编写基础知识,但目前这些类型的查询有点遥不可及。

因此,我们非常感谢任何帮助,因此已经提前感谢您。

约里

我似乎没有以任何方式让 SoLine 表中的每条记录只有 1 条记录作为结果

sql-server loops left-join data-warehouse
2个回答
0
投票

我们可以使用

ROW_NUMBER()
为由
PARTITION BY
子句指定的定义组内的每一行分配唯一的序号,然后我们选择每组的最新行,使用
ORDER BY
子句按降序对数据进行排序:

SELECT *
FROM (
  SELECT
    OL.*,
    OPA.*,
    ROW_NUMBER() OVER (PARTITION BY OL.Header_Id, OL.Line_Id, OL.Last_Update_Date ORDER BY Order_Price_Attrib_Id DESC) AS rn
  FROM OE_Order_Lines_All OL
  LEFT JOIN OE_Order_Price_Attribs OPA
     ON OL.Header_Id = OPA.Header_Id
     AND OL.Line_Id = OPA.Line_Id
) AS S
WHERE rn = 1;

0
投票

这是一个古老的问题,T-SQL 中的一个解决方案是

outer apply
功能:

select
    OL.*,
    OPA.*
from ONT.OE_Order_Lines_All OL
    outer apply (select top 1 *
                 from ONT.OE_Order_Price_Attribs OPA
                 where OL.Header_Id = OPA.Header_Id
                     and OL.Line_Id = OPA.Line_Id
                 order by Order_price_Attrib_Id desc) OPA

如您所见,这实际上为

OL
中的每一行运行一个子查询,按
OPA.Order_price_Attrib_Id
排序并仅给出第一个结果,因此最终结果集保持相同的大小。

您可以使用两个

left joins
执行类似的操作,但查询最终可能会更加复杂(不过可能性能更好):

select
    OL.*,
    OPA.*
from ONT.OE_Order_Lines_All OL
    left join ONT.OE_Order_Price_Attribs OPA
         on OL.Header_Id = OPA.Header_Id
        and OL.Line_Id = OPA.Line_Id
    left join ONT.OE_Order_Price_Attribs OPAX
         on OL.Header_Id = OPAX.Header_Id
        and OL.Line_Id = OPAX.Line_Id
        and OPAX.Order_price_Attrib_Id > OPA.Order_price_Attrib_Id
where OPAX.Order_price_Attrib_Id is null

在这里,您还再次连接来自

ONT.OE_Order_Price_Attribs
的所有行,但前提是
Order_price_Attrib_Id
大于之前连接的
Order_price_Attrib_Id
。然后丢弃所有不为空的结果,即只保留不存在更大的
Order_price_Attrib_Id
的结果。正如你所看到的,我将其中一张连接表命名为
OPAX
来表示它只能被扔掉。您当然可能更喜欢其他东西,也许
OPA_greater
或其他东西。

© www.soinside.com 2019 - 2024. All rights reserved.