SQL Server 2016 子查询指南

Posted

技术标签:

【中文标题】SQL Server 2016 子查询指南【英文标题】:SQL Server 2016 Sub Query Guidance 【发布时间】:2017-09-18 09:36:28 【问题描述】:

我目前正在为我的 SQL 课程做作业,但我被卡住了。我不是在寻找完整的代码来回答这个问题,只是在正确的方向上轻轻一点。如果你确实提供了完整的代码,你会介意你为什么这样做的一个小解释(这样我实际上可以学到一些东西。)

问题来了:

编写返回三列的 SELECT 语句:EmailAddressShipmentId,以及每个客户的订单总额。为此,您可以按EmailAddressShipmentId 列对结果集进行分组。此外,您必须根据ShipItems 表中的列计算订单总额。

编写第二个 SELECT 语句,在其 FROM 子句中使用第一个 SELECT 语句。主查询应返回两列:客户的电子邮件地址和该客户的最大订单。为此,您可以按EmailAddress 列对结果集进行分组。

我对如何从Clients 表中提取EmailAddress 列感到困惑,因为为了加入它,我必须引入其他未使用的表。我假设有一种更简单的方法可以使用子查询来做到这一点,因为这正是我们当时正在做的事情。

【问题讨论】:

请注意,“子查询”和“相关子查询”之间是有区别的——我知道这会让一些认为所有子查询都是相关子查询的初学者望而却步。顺便说一句,这并不适用于您的问题。 请提供您正在使用的表的定义。到目前为止,我可以看到 Clients ( EmailAddress )Shipments ( ShipmentId )ShipItems ( ShipmentId ) - 只是这 3 个表和列吗?订单总额在哪里定义?它是存储在Shipments 还是必须从ShipItems 计算? 您写了“EmailAddress [...],因为为了加入它,我必须引入其他未使用的表。” - 你还没有说涉及到哪些其他表或为什么你认为它们“没有被使用”。据我所知,它们正在被使用。 【参考方案1】:

将 SQL 视为处理数据集而不仅仅是表。表只是一组数据。因此,当您以这种方式查看数据时,您会立即看到下面的查询返回一组数据,该数据由另一个集合的整体组成,即一个表:

SELECT * FROM MyTable1

现在,如果您只从 MyTable1 中获取前两列,您将返回一个仅包含第 1 列和第 2 列的不同集合:

SELECT col1, col2 FROM MyTable1

现在您可以将第二组数据(数据的子集)也视为“表”并像这样查询它:

SELECT 
    *
FROM (
    SELECT
        col1,
        col2
    FROM
        MyTable1
)

这将返回内部集中提供的两列中的所有列。

因此,您的内部查询(由于您似乎是学生,我不会为您写,而且我不适合给您完整的答案)将是一个由 GROUP BY 组成的查询子句和订单值字段的 SUM。但是您需要了解的关键是这种思维定势:您可以将 ENTIRE 查询包装在括号内,并像我上面所做的那样将其视为表格。希望这会有所帮助。

【讨论】:

【参考方案2】:

你需要一个子查询,像这样:

select emailaddress, max(OrderTotal) as MaxOrder 
from
( -- Open the subquery
select Cl.emailaddress, 
       Sh.ShipmentID, 
       sum(SI.Value) as OrderTotal -- Use the line item value column in here
from Client Cl -- First table
inner join Shipments Sh -- Join the shipments
  on Sh.ClientID =  Cl.ClientID
inner join ShipItem SI -- Now the items
  on SI.ShipmentID = Sh.ShipmentID
group by C1.emailaddress, Sh.ShipmentID -- here's your grouping for the sum() aggregation
) -- Close subquery
group by emailaddress -- group for the max()

【讨论】:

【参考方案3】:

对于第一个查询,您可以将客户加入到货件(在 ClientId 上)。 和 ShipItems 表(在 ShipmentId 上)的发货。 然后对结果进行分组,并计算或求和您需要的总数。

为表使用别名很有用,尤其是当您从具有相同列名的连接表中选择字段时。

select 
 c.EmailAddress, 
 i.ShipmentId,
 SUM((i.ShipItemPrice - i.ShipItemDiscountAmount) * i.Quantity) as TotalPriceDiscounted
from ShipItems i
join Shipments s on (s.ShipmentId = i.ShipmentId)
left join Clients c on (c.ClientId = s.ClientId)
group by i.ShipmentId, c.EmailAddress
order by i.ShipmentId, c.EmailAddress;

在子查询中使用该分组查询,您可以获得每个 EmailAddress 的最大总数。

select EmailAddress, 
-- max(TotalShipItems) as MaxTotalShipItems,
max(TotalPriceDiscounted) as MaxTotalPriceDiscounted
from (
   select 
    c.EmailAddress, 
    -- i.ShipmentId, 
    -- count(*) as TotalShipItems,
    SUM((i.ShipItemPrice - i.ShipItemDiscountAmount) * i.Quantity) as TotalPriceDiscounted
   from ShipItems i
   join Shipments s on (s.ShipmentId = i.ShipmentId)
   left join Clients c on (c.ClientId = s.ClientId)
   group by i.ShipmentId, c.EmailAddress
) q
group by EmailAddress
order by EmailAddress

请注意,如果您不使用 TOP,ORDER BY 在子查询中几乎没有意义。

【讨论】:

好的,所以我想我应该提供更多信息。 ShipItems 表不与 Clients 表共享 PK 或 FK。唯一与 flients 表共享任何 PK 或 FK 的表是 Shipments 表。这就是为什么最初我没有看到如果不引入 Shipments 表你会如何做到这一点。但您使用它的唯一目的是能够加入 Clients 和 ShipItems 表。 再次阅读您的帖子,我想我已经弄清楚了。谢谢,如果需要任何额外的帮助,会再次发布。 @BrettHawkins 我更改了第二个查询,因此它现在包含一个 Shipments 表。我认为原始问题中忽略了此类表。 好的,所以在编写第一个查询时,我已经完成了所有工作,但它没有给出任何结果。这是我写的查询:SELECT c.EmailAddress, s.ShipmentId, SUM((sh.ShipItemPrice - sh.ShipItemDiscountAmount) * sh.Quantity) AS OrderTotal FROM Clients AS c JOIN Shipments AS s ON c.ClientID = s。 ClientID 加入 ShipItems AS sh ON s.ShipmentID = sh.ShipItemsID GROUP BY EmailAddress, s.ShipmentID @BrettHawkins 我认为您应该使用 ShipItems 作为基表,并加入其他人。并与客户表的左连接。这样,当 ClientId 无法链接时,您也会得到计数。

以上是关于SQL Server 2016 子查询指南的主要内容,如果未能解决你的问题,请参考以下文章

如何提高 SQL Server 查询的性能以选择具有值的行不在子查询中的一次计数

sql server——子查询

SQL Server 之 子查询与嵌套查询

ORACLE LEFT JOIN 子查询 在SQL SERVER中可以使用如图中的子查询,ORACLE中怎么实现

如何优化此 SQL Server 查询 - 多个子查询

在 Sql Server 中使用子查询更新查询