基于多个表和条件进行筛选的SQL命令

问题描述 投票:1回答:1

我正在尝试学习sql,它使我发疯。我似乎无法掌握实现所需输出的正确语法。我正在观看udemy上的视频并阅读有关试图自学的基本sql书籍,但似乎它们都不足以帮助我弥合我似乎无法克服的差距。

我对SELECT,FROM,WHEN命令的基础知识有很好的了解。我似乎在了解使用聚合函数的知识,但我绝不是专家。

我有两个表,“订单”和“ OrderDet”。 “订单”包含CustomerName和OrderNo,而OrderDet包含其他所有内容,例如PartNo,DateFinished,OrderNo等。

我有多个客户可以订购相同零件号的情况。我想显示所有客户下的所有最后订单。

例如

SELECT Orders.CustDesc, OrderDet.OrderNo, OrderDet.PartNo, OrderDet.DateFinished
FROM Orders
JOIN OrderDet ON Orders.OrderNo = OrderDet.OrderNo
ORDER BY OrderDet.PartNo, OrderDet.DateFinished

此查询返回:

Customer   OrderNo   PartNo     Date Finished
--------------------------------------------------------
Cust 1      5032    12345678-1  NULL
Cust 2     10032    12345678-1  2019-06-05 14:54:25.853
Cust 2      1048    12345678-1  2019-07-08 00:00:00.000
Cust 1      5028    12345678-1  2019-09-30 11:45:45.960
Cust 1      5029    12345678-1  2019-09-30 12:49:35.713
Cust 1      5030    12345678-1  2019-09-30 13:04:57.333
Cust 1      5031    12345678-1  2019-10-10 13:58:22.653

我仍在学习何时以及如何使用聚合函数,但是似乎无法完全掌握该概念。我尝试在“日期”列上使用MAX,并在“客户和零件号”上使用GROUP,但是除非删除订单号,否则输出永远不会折叠到我想要的位置。

例如,我使用过:

SELECT Orders.CustDesc, OrderDet.PartNo, MAX(OrderDet.DateFinished)
FROM Orders
JOIN OrderDet ON Orders.OrderNo = OrderDet.OrderNo
GROUP BY Orders.CustDesc, OrderDet.PartNo
ORDER BY OrderDet.PartNo

从SELECT中删除OrderDet.OrderNo,并从Order By中删除OrderDet.DateFinished。这将返回我想要的行输出,但是缺少我想要的所有列。

Customer  PartNo     Date Finished
--------------------------------------------
Cust 2  12345678-1  2019-07-08 00:00:00.000
Cust 1  12345678-1  2019-10-10 13:58:22.653

我尝试将OrderNo重新添加到混合中时,得到的输出与第一个相同。我想我理解为什么会这样,因为所有的OrderNo都是唯一的并且无法分组,但是我无法掌握如何克服这个问题。

我了解这是基本的SQL命令,但似乎无法理解如何获取所需的输出。在此示例中,我只想根据PartNo的最后日期看到两行唯一的客户,但要显示整行的内容。不只是三栏。

同样,我正在尝试学习这些内容,并且我只能阅读和重新阅读相同的基本内容,以学习这么长时间。我阅读的所有内容似乎都缺少那一刻“ AH HA”所需的信息。

也许有人可以帮助弥合这种差距?

sql sql-server-2017
1个回答
0
投票

我将您的问题解释为想要给定客户的每个订购的零件的最新订单。

为此,我建议使用窗口功能:

select CustDesc, OrderNo, od.DateFinished
from (select o.custdesc, od.orderno, od.partno, od.datefinished,
             row_number() over (partition by o.custdesc, od.partno order by od.datefinished desc) as seqnum
      from Orders o join
           orderdet od
           on o.OrderNo = od.OrderNo
     ) od
where seqnum = 1;
order by od.PartNo, od.DateFinished

-1
投票

解决这个问题的关键是:不要聚合,而是过滤。

从列出每个OrderDet的所有Order的现有查询开始,您可以添加一个联接条件,该联接条件使用correlated子查询以每个OrderDet的最新Order进行过滤:] >

SELECT o.CustDesc, d.OrderNo, d.PartNo, d.DateFinished
From Order o
JOIN OrderDet d 
    ON  o.OrderNo = d.OrderNo
    AND d.DateFinished = (
        SELECT MAX(d1.DateFinished)
        FROM Order o1
        JOIN OrderDet d1 ON o1.OrderNo = d1.OrderNo
        WHERE o1.CustDesc= o.CustDesc
    )
Order By d.PartNo, d.DateFinished

另一个典型的解决方案是使用窗口函数RANK(),如果您的RDBMS支持的话:

SELECT 
    o.CustDesc, 
    d.OrderNo, 
    d.PartNo, 
    d.DateFinished
FROM (
    SELECT 
        o.*, 
        d.*, 
        RANK() OVER(PARTITION BY d.CustDesc ORDER BY d.DateFinished DESC) rn
    From Order o
    JOIN OrderDet d ON  o.OrderNo = d.OrderNo
) t
WHERE rn = 1

内部查询查询按CustDesc降序对具有相同DateFinished的记录组中的每个记录进行排名。然后,外部查询将在每个组的顶部记录上进行过滤。

旁注:有意义的表别名使查询更短,更容易理解。我修改了您现有的查询以使用它们。

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