Sql 选择子查询分组依据
我对这个简单的查询有疑问。我得到了错误 子查询返回了多个值。当子查询后跟=、!=、=或子查询用作表达式时,这是不允许的Sql 选择子查询分组依据,sql,sql-server,subquery,Sql,Sql Server,Subquery,我对这个简单的查询有疑问。我得到了错误 子查询返回了多个值。当子查询后跟=、!=、=或子查询用作表达式时,这是不允许的 我尝试过解决这个问题,并且知道我缺少一个简单的解决方案。子查询本身检索我正在查找的信息,与主查询一样,在分离时也是如此。谢谢你的帮助 我只能在上面的查询中看到这个子查询 SELECT ISNULL(SUM(dbo.PurchaseOrderReceived.QtyReceived),0) FROM dbo.PurchaseOrderReceived INNE
我尝试过解决这个问题,并且知道我缺少一个简单的解决方案。子查询本身检索我正在查找的信息,与主查询一样,在分离时也是如此。谢谢你的帮助 我只能在上面的查询中看到这个子查询
SELECT ISNULL(SUM(dbo.PurchaseOrderReceived.QtyReceived),0)
FROM dbo.PurchaseOrderReceived
INNER JOIN dbo.PurchaseOrderlineItems ON dbo.PurchaseOrderReceived.POLIID = dbo.PurchaseOrderlineItems.POLIID
INNER JOIN dbo.Inventory ON dbo.PurchaseOrderlineItems.InvMasID = dbo.Inventory.InvMasID
INNER JOIN dbo.Duties Duties_1 ON dbo.Inventory.DutyClass = Duties_1.DutyID
WHERE (Duties_1.DutyClass = 252)
AND (dbo.PurchaseOrderlineItems.Deleted = 0)
AND (dbo.PurchaseOrderReceived.ReceivedDate > CONVERT(DATETIME,'2018-08-22 00:00:00',102))
GROUP BY dbo.Inventory.PARTNO
按PARTNO分组这应该返回多个值。确保满足
where
和内部联接
条件的零件号不超过一个我只能在上面的查询中看到此子查询
SELECT ISNULL(SUM(dbo.PurchaseOrderReceived.QtyReceived),0)
FROM dbo.PurchaseOrderReceived
INNER JOIN dbo.PurchaseOrderlineItems ON dbo.PurchaseOrderReceived.POLIID = dbo.PurchaseOrderlineItems.POLIID
INNER JOIN dbo.Inventory ON dbo.PurchaseOrderlineItems.InvMasID = dbo.Inventory.InvMasID
INNER JOIN dbo.Duties Duties_1 ON dbo.Inventory.DutyClass = Duties_1.DutyID
WHERE (Duties_1.DutyClass = 252)
AND (dbo.PurchaseOrderlineItems.Deleted = 0)
AND (dbo.PurchaseOrderReceived.ReceivedDate > CONVERT(DATETIME,'2018-08-22 00:00:00',102))
GROUP BY dbo.Inventory.PARTNO
按PARTNO分组这应该返回多个值。确保满足
where
和internal join
条件的零件号不超过一个子查询需要返回一个值,而在您的子查询中它返回多个值,这是因为内部分组由PARTNO
。您可以通过删除该分组,或者使用TOP 1,或者只包含带有SUM、MAX、MIN的子查询来解决它
另一件事,因为您的子查询也使用相同的和相对的源,所以您可以加入它们(这样会更好)
大概是这样的:
SELECT TOP 100 PERCENT
dbo.Inventory.PARTNO
, ISNULL(SUM(dbo.por.QtyReceived), 0) AS Purchased
, ISNULL(SUM(dbo.OrderItems.QtyShipped), 0) AS Ordered
, ISNULL(SUM(DISTINCT dbo.MRP.QtyOnHand), 0) AS QOH
FROM dbo.Orders
JOIN dbo.OrderItems ON dbo.Orders.OrderID = dbo.OrderItems.OrderID
JOIN dbo.Inventory ON dbo.OrderItems.InvMasID = dbo.Inventory.InvMasID
JOIN dbo.MRP ON dbo.Inventory.InvMasID = dbo.MRP.InvMasID
JOIN dbo.Duties ON dbo.Inventory.DutyClass = dbo.Duties.DutyID
LEFT JOIN dbo.PurchaseOrderlineItems poli ON poli.InvMasID = dbo.Inventory.InvMasID AND poli.Deleted = 0
LEFT JOIN dbo.PurchaseOrderReceived por ON por.POLIID = poli.POLIID AND (dbo.por.ReceivedDate > CONVERT(DATETIME, '2018-08-22 00:00:00', 102))
WHERE
dbo.Orders.ShipDate > CONVERT(DATETIME, '2018-08-22 00:00:00', 102)
AND (dbo.Duties.DutyClass = 252)
GROUP BY dbo.Inventory.PARTNO
我无法验证结果,因为您没有提供任何样本,但我认为它足以展示这种方法 子查询需要返回一个值,而在您的查询中,它返回多个值,这是因为内部组by
PARTNO
。您可以通过删除该分组,或者使用TOP 1,或者只包含带有SUM、MAX、MIN的子查询来解决它
另一件事,因为您的子查询也使用相同的和相对的源,所以您可以加入它们(这样会更好)
大概是这样的:
SELECT TOP 100 PERCENT
dbo.Inventory.PARTNO
, ISNULL(SUM(dbo.por.QtyReceived), 0) AS Purchased
, ISNULL(SUM(dbo.OrderItems.QtyShipped), 0) AS Ordered
, ISNULL(SUM(DISTINCT dbo.MRP.QtyOnHand), 0) AS QOH
FROM dbo.Orders
JOIN dbo.OrderItems ON dbo.Orders.OrderID = dbo.OrderItems.OrderID
JOIN dbo.Inventory ON dbo.OrderItems.InvMasID = dbo.Inventory.InvMasID
JOIN dbo.MRP ON dbo.Inventory.InvMasID = dbo.MRP.InvMasID
JOIN dbo.Duties ON dbo.Inventory.DutyClass = dbo.Duties.DutyID
LEFT JOIN dbo.PurchaseOrderlineItems poli ON poli.InvMasID = dbo.Inventory.InvMasID AND poli.Deleted = 0
LEFT JOIN dbo.PurchaseOrderReceived por ON por.POLIID = poli.POLIID AND (dbo.por.ReceivedDate > CONVERT(DATETIME, '2018-08-22 00:00:00', 102))
WHERE
dbo.Orders.ShipDate > CONVERT(DATETIME, '2018-08-22 00:00:00', 102)
AND (dbo.Duties.DutyClass = 252)
GROUP BY dbo.Inventory.PARTNO
我无法验证结果,因为您没有提供任何样本,但我认为它足以展示这种方法 简单的解决方案似乎是在子查询或主SELECT语句中为库存表添加别名,并通过主查询中的
PARTNO
过滤子查询中的记录。我认为别名是个好主意:
SELECT TOP 100 PERCENT
i.PARTNO
, ( SELECT ISNULL(SUM(por.QtyReceived), 0)
FROM dbo.PurchaseOrderReceived por
JOIN dbo.PurchaseOrderlineItems poli ON por.POLIID = poli.POLIID
JOIN dbo.Inventory i1 ON poli.InvMasID = i1.InvMasID
JOIN dbo.Duties d1 ON i1.DutyClass = d1.DutyID
WHERE (d1.DutyClass = 252)
AND (i1.PARTNO = i.PARTNO)
AND (poli.Deleted = 0)
AND (por.ReceivedDate > CONVERT(DATETIME, '2018-08-22 00:00:00', 102))
) AS Purchased
, ISNULL(SUM(oi.QtyShipped), 0) AS Ordered
, ISNULL(SUM(DISTINCT m.QtyOnHand), 0) AS QOH
FROM dbo.Orders o
JOIN dbo.OrderItems oi ON o.OrderID = oi.OrderID
JOIN dbo.Inventory i ON oi.InvMasID = i.InvMasID
JOIN dbo.MRP m ON i.InvMasID = m.InvMasID
JOIN dbo.Duties d ON i.DutyClass = d.DutyID
WHERE (o.ShipDate > CONVERT(DATETIME, '2018-08-22 00:00:00', 102))
AND (d.DutyClass = 252)
GROUP BY i.PARTNO
简单的解决方案似乎是在子查询或主SELECT语句中对库存表使用别名,并通过主查询中的
PARTNO
过滤子查询中的记录。我认为别名是个好主意:
SELECT TOP 100 PERCENT
i.PARTNO
, ( SELECT ISNULL(SUM(por.QtyReceived), 0)
FROM dbo.PurchaseOrderReceived por
JOIN dbo.PurchaseOrderlineItems poli ON por.POLIID = poli.POLIID
JOIN dbo.Inventory i1 ON poli.InvMasID = i1.InvMasID
JOIN dbo.Duties d1 ON i1.DutyClass = d1.DutyID
WHERE (d1.DutyClass = 252)
AND (i1.PARTNO = i.PARTNO)
AND (poli.Deleted = 0)
AND (por.ReceivedDate > CONVERT(DATETIME, '2018-08-22 00:00:00', 102))
) AS Purchased
, ISNULL(SUM(oi.QtyShipped), 0) AS Ordered
, ISNULL(SUM(DISTINCT m.QtyOnHand), 0) AS QOH
FROM dbo.Orders o
JOIN dbo.OrderItems oi ON o.OrderID = oi.OrderID
JOIN dbo.Inventory i ON oi.InvMasID = i.InvMasID
JOIN dbo.MRP m ON i.InvMasID = m.InvMasID
JOIN dbo.Duties d ON i.DutyClass = d.DutyID
WHERE (o.ShipDate > CONVERT(DATETIME, '2018-08-22 00:00:00', 102))
AND (d.DutyClass = 252)
GROUP BY i.PARTNO
是时候重新开始并应用一些最佳编码实践了。你的加入是以一种“非典型”的方式组织的,很多人都很难理解。混淆的代码可能会导致错误。移动联接子句以跟随实际联接的表。例如,你有
FROM dbo.Orders
JOIN dbo.OrderItems
JOIN dbo.Inventory
ON dbo.OrderItems.InvMasID = dbo.Inventory.InvMasID
ON dbo.Orders.OrderID = dbo.OrderItems.OrderID
JOIN dbo.MRP ON dbo.Inventory.InvMasID = dbo.MRP.InvMasID
JOIN dbo.Duties ON dbo.Inventory.DutyClass = dbo.Duties.DutyID
您没有在第一次加入OrderItems之后加入associated ON子句-不知怎的,它在加入库存之后结束了。奇怪的是,join to MRP的on子句确实紧跟在该表之后。不一致是开发人员的坏习惯。我觉得比“非典型”做事更糟糕。最后,使用alias减少混乱,使代码更易于阅读。更容易阅读意味着你的代码更容易被理解。改进的版本是:
FROM dbo.Orders as Ord
JOIN dbo.OrderItems as Itm on Ord.OrderID = Itm.OrderID
JOIN dbo.Inventory as Inv on Itm.InvMasID = Inv.InvMasID
JOIN dbo.MRP as MRP ON Inv.InvMasID = MRP.InvMasID
JOIN dbo.Duties as Duties ON Inv.DutyClass = Duties.DutyID
您可以对表进行模式限定,这很好——很少看到海报会这样做。但是,它也会使名称非常长,这也是建议使用别名的原因之一
接下来,您将选择“百分之一百前几名”。当你认为你需要这个的时候,停止编写代码,去做一些其他的事情。这是永远不会有用的。如果SSMS试图通过添加它来“修复”某些东西,请不要相信它
您发布的问题是子查询。您试图“修复”原始问题,但没有告诉我们该问题是什么。这是因为查询返回了错误的求和值。为什么会这样?因为您没有将子查询与外部查询关联,所以它为每个单独的库存行计算一个值
要做到这一点,您需要在子查询中删除与库存的联接。为什么?因为适当库存行的键将来自外部查询-这就是如何将内部与外部关联起来。没有GROUPBY子句,因为您的目标是为外部查询中的每一行计算一个值。group by子句从逻辑上指示您打算在该查询中生成多行—这不是您希望发生的(并且不能发生,因为引擎将在该情况下生成错误—您已经发现)。还有一些问题:
- 别名问题(显然)使子查询难以读取
- 在当前位置可能不需要使用isnull,但在其他位置需要使用isnull。子查询总是可能找不到匹配的行并返回空值。如果不需要null值,可以使用isnull包装整个子查询。因为你这样做了,所以在你现在拥有它的地方你不需要它。在你目前拥有的地方,它可能不需要用于“匹配”情况——但我不能在不了解你的模式的情况下肯定地说。不管怎样,正确的位置将否定它在求和计算中的必要性李>
- where子句中的重复条件。一旦正确关联,就不需要这样做
,( SELECT SUM(POR.QtyReceived)
FROM dbo.PurchaseOrderReceived as POR
JOIN dbo.PurchaseOrderlineItems as POItm
ON POR.POLIID = POItm.POLIID
WHERE Inv.InvMasID = POItm.InvMasID --this is the correlation
AND POItm.Deleted = 0
AND POR.ReceivedDate > CONVERT(DATETIME, '2018-08-22 00:00:00', 102))
) AS Purchased
希望我没有添加任何打字错误或错误-显然我自己无法检查。但这至少给了你一个更好的起点。您对日期的使用看起来很可疑,但我不知道您的模式或数据,也不知道它是如何使用的,也不知道您查询的目的是什么 是时候重新开始并应用一些最佳编码实践了。您的加入是以“非典型”的方式组织的