我对 SQL select from where in group byhaving 感到困惑

问题描述 投票:0回答:1
[![在此处输入图像描述][1]][1]现在说我有一个数据库,其中有一个表

kits_parts_needed

,我需要弄清楚我有哪些套件的零件,其中有字段直接与库存表相关的表,
fk_inventory_key
fk_inventory_key_for_parts
,我让用户扫描一些条形码,这些条形码给了我钥匙。然后,我可以根据数据库检查此列表,并希望能带回 1 个套件。这是 SQL。

SELECT fk_inventory_key FROM Kits_Parts_Needed WHERE fk_inventory_Key_For_Parts IN ('7F983531-7AF8-4F10-A87C-EC555FA51BDB', 'B7FAEB96-21E2-44D5-93B1-ECE4545996FF') GROUP BY fk_inventory_key HAVING COUNT(DISTINCT fk_inventory_Key_For_Parts) = 2;
现在由于某种原因该代码的工作原理如下:
它从 

fk_inventory_key

 中选择 
Kits_Parts_Needed
,其中 
fk_inventory_key_For_Parts
 位于我现在已累积的密钥列表中。

然后我按

fk_inventory_Key

 分组并使用having 函数,因为我希望它与我列表中的两个键相关。它有效。我已经在许多套件上进行了测试,它总是返回正确的套件。

现在是我的问题了。按照代码的编写方式,您可能会认为它会选择这些套件,其中

parts = part1

 OR 
part2
 然后它只会去验证 where 子句返回的这些套件是否至少有 2 个关系,而不是这两个关系匹配这是在 
IN
 子句中......但这正是它的工作原理。

有人可以向我解释一下它是如何工作的吗,因为我认为它不应该如此......或者也许我有一个愉快的意外,它刚刚在我测试过的 5 个套件上起作用。

我尝试通过拥有并获取来删除该组:

C4520143-3F5C-4433-AA9B-41550103D71C C4520143-3F5C-4433-AA9B-41550103D71C 46C42E3A-D7A3-4FA9-83B1-A3CA93395BF3
如果我只有分组并让我得到:

0CDE77A4-C626-44F6-8B19-71C440827FC8 1AC67209-62C5-4E70-B218-DFF9608754E5 2005C859-F917-4790-BF4A-6184794020AF 208C3784-FD95-438D-9F5F-F4DECF376A03 24E8B3AA-0489-4C19-8C86-3DEE1173E9BA 28C562E3-3C89-4853-8616-36CD712D3838 2B48A4EA-821C-4F98-9E06-43E53057C9F9 3CE723D8-134F-4556-8DD1-EED4C5AEA4AB 6DF89B22-F25D-4C68-BDF7-773231F80A4D 7309666C-64EB-42BB-B712-8E040ED000EF 77FA3EF7-57B1-472B-A2EC-010AE40C52F7 78E32FB5-6FBF-490C-9314-37AF1AEA27D6 8DCCBD1A-37A9-4D15-86B0-3E9D30A18C02 9472BB5F-6562-4CBA-BBC2-6A4E14458D9B 94D92945-1D96-4D13-A4EC-885FF85804AC A67C4C3C-D881-4251-80EB-AD04217B5801 C6A916B3-D3F9-4E83-B271-4F01863E9A6B ECCE496C-F7F1-4D86-8FBE-EA6ED70A69C9
当我两者都在那里时,我得到:

C4520143-3F5C-4433-AA9B-41550103D71C
这是正确答案,但为什么呢?

添加更多背景信息: 现在也许是因为这些都在同一个表中,我的问题是为什么要隐式检查以确保列表中的示例 2 值与 in 子句中的值匹配。为了测试,我创建了另一个非常简单的表,Testing_SQL,它具有以下字段:

客户_ID、订单_ID 和产品_ID

以及以下示例数据:

现在...如果您有以下 SQL:

SELECT Customer_ID FROM Testing_SQL WHERE Product_ID IN (1,5) GROUP BY Customer_ID HAVING COUNT(DISTINCT Product_ID) = 2
好吧...现在这就是我搞砸的地方,如果你看看 where 子句应该返回什么,它会返回 101 和 102。
还行吧!
分组依据,效果很好!
有?好吧,如果您查看 101 和 102,都购买了多件东西,那么如果您计算不同的 Product_ID,从技术上讲,两者都有 3,但至少有 2。为什么这会隐式重新检查 where 子句?因为它只返回 101!购买了 1 和 5 的人。

sql select group-by where-clause having
1个回答
0
投票
在我看来,你误解了逻辑。让我们逐步查看您最新的数据。首先是数据:

WITH -- S a m p l e D a t a : tbl ( CUSTOMER_ID, ORDER_ID, PRODUCT_ID ) AS ( Select 101, 100, 1 From Dual Union All Select 101, 101, 7 From Dual Union All Select 101, 102, 5 From Dual Union All Select 102, 103, 5 From Dual Union All Select 102, 104, 6 From Dual Union All Select 102, 105, 2 From Dual Union All Select 103, 106, 7 From Dual Union All Select 103, 107, 3 From Dual Union All Select 103, 108, 2 From Dual )
如果我们从样本数据中选择所有具有 PRODUCT_ID IN(1, 5) 的行

Select * From tbl Where PRODUCT_ID IN(1, 5)
/*    R e s u l t :
CUSTOMER_ID   ORDER_ID PRODUCT_ID
----------- ---------- ----------
        101        100          1
        101        102          5
        102        103          5 */
上面的结果集意味着此 Select 语句的所有其他行都不存在,并且我们添加到此代码中的任何其他内容都将仅处理这三行,因此,如果我们仅选择 CUSTOMER_ID 列...

Select CUSTOMER_ID From tbl Where PRODUCT_ID IN(1, 5)
/*
CUSTOMER_ID
-----------
        101
        101
        102 */
...我们的顾客来自同一三排。现在,如果我们 GROUP BY 我们应该为每个客户获取一行......

Select CUSTOMER_ID From tbl Where PRODUCT_ID IN(1, 5) Group By CUSTOMER_ID /* CUSTOMER_ID ----------- 101 102 */
在使用 HAVING 子句之前,我们将 Count() 聚合放入 Select...

Select CUSTOMER_ID, Count(DISTINCT PRODUCT_ID) "CNT" From tbl Where PRODUCT_ID IN(1, 5) Group By CUSTOMER_ID /* CUSTOMER_ID CNT ----------- ---------- 101 2 102 1 */
现在很明显,客户 ID HAVING 2 DISTINCT PRODUCT_ID 为 101。将该计数移至 HAVING 子句只是获取行或不获取行的另一个条件...

Select CUSTOMER_ID From tbl Where PRODUCT_ID IN(1, 5) Group By CUSTOMER_ID HAVING Count(DISTINCT PRODUCT_ID) = 2 /* CUSTOMER_ID ----------- 101 */
现在,如果您查看第一个 Select 的结果集:

/* R e s u l t : CUSTOMER_ID ORDER_ID PRODUCT_ID ----------- ---------- ---------- 101 100 1 101 102 5 102 103 5 */
客户 101 拥有产品 1 和 5,客户 102 仅有产品 5。因此,您的结果是 OK - CUSTOMER_ID 拥有两个不同的产品,而问题中的条件是 101

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