通过将一组数据与范围进行比较来获取数据
Get Data by comparing a set of data with a range
我正在使用 Access 数据库并使用 VB/VBA 进行编程。我有两个 tbl,如下所示。第一个是从供应商处获取信息和价格。第二个是我自己公司的价格区间。我想检查 3 种不同类型 (1,2,3) 的水果的 3 种价格,分为最小值和最大值以及 return 基于水果符号的供应商名称。
例如:
如果 Apple 的价格为 2.1、2.23、2.47,落入范围:2.1 - 2.55,则接受供应商的价格和 return FreshFruit Inc。如果不是,则拒绝该水果的所有 3 个价格 Type/Symbol 和显示拒绝的警告消息。
我尝试过很多不同的查询方式,但有点太复杂了。我正在考虑改用脚本,但我不确定。
供应商bl:
供应商|水果|类型|符号|价格
FreshFruit Inc. |Apple |1 |Ap |2.1
FreshFruit Inc. |Apple |2 |Ap |2.23
FreshFruit Inc. |Apple |3 |Ap |2.47
GreenProd LLC。 |香蕉 |1 |Ba |0.65
GreenProd LLC。 |香蕉 |2 |Ba |0.67
GreenProd LLC。 |香蕉 |3 |Ba |0.63
UrFruit Inc. |木瓜 |1 |Py |1.86
UrFruit Inc. |木瓜 |2 |Py |1.62
UrFruit Inc. |木瓜 |3 |Py |1.73
这是另一个列表:
Rangetbl
水果 |符号|最小值 |最大值
苹果 |Ap |2.1 |2.55
香蕉 |Ba |0.6 |0.65
木瓜 |Py |1.6 |1.75
感谢您的帮助
您需要做的是考虑在您的 table 上使用左外连接。这样您就可以找到不匹配的(或被拒绝的供应商)。
找到不匹配项后,您必须进行另一次匹配以排除出现在不匹配列表中的供应商,从而为您提供匹配项(或接受的供应商)。
如果你想复杂一点,在Selects中使用嵌入的Selects,你可以在一个查询中全部写完。
但是如果您正在使用 VBA 并希望它对可能遇到您的代码的未来程序员保持可读性,您可以编写几个不同的查询 运行 一个接一个。 (即第一个查询找到您的不匹配项(拒绝),您的第二个查询与第一个查询匹配以创建已接受供应商列表。)
其他一些注意事项:
它可能会帮助您索引您拥有的 table 并创建主要的
键。
阅读第三范式。它会帮助你设计
更好 tables。 (你不必成为第三范式的奴隶......
但知道它可以帮助你解决很多问题
数据结构更容易理解。)
祝你好运:)
编辑 2015 年 8 月 5 日:
好的...我有时间帮助解决细节问题。使用 Left Outer Join 查找不匹配项可能很难弄清楚。所以这是我最好的解释它们的方法:
首先,您需要将 [Rangetbl] 中的 [Symbol] 字段设置为主键,以便在不允许重复的情况下对其进行索引(如果尚未)。您不能在此字段中允许重复项,否则左外连接将无法正常工作。 (如果你在那里需要重复项,你需要重组你的 tables...这是另一个超出此解决方案范围的讨论。)同时将它的 "Allow Zero Length" 设置为 "No" .数据集中也不能有 Null 值。
您需要在 Access 数据库项目中创建一个新查询。 (取消过去的向导,所以你有一个空白查询。)
您可以将其保存为 [qry01NonMatches]。
切换到 "SQL View"(使用功能区左上方的按钮。)
复制此 SQL 代码:
SELECT DISTINCT Vendortbl.Vendor
FROM Vendortbl LEFT OUTER JOIN Rangetbl ON
(Vendortbl.Symbol = Rangetbl.Symbol)
AND (Vendortbl.Price <= Rangetbl.Max)
AND (Vendortbl.Price >= Rangetbl.Min)
WHERE isnull(Rangetbl.Symbol) = true;
这是您的左外连接,用于查找至少有一个记录超出给定符号 min/max 范围的所有供应商。这给出了被您拒绝的供应商列表。
这是怎么做到的(您可能会问)?
Left Outer Join 告诉数据库 return 无论如何,所有 Vendortbl 记录。但是它加入了 Rangetbl,如果找到匹配项,它将 return Rangetbl 数据。我们在这里使用的技巧是,如果存在 No Match,我们仍将获得 Vendortbl 记录,但由于没有 Rangetbl 记录,Rangetbl 字段将填充 Null 值。 (很明显!因为没有可匹配的数据。)记住这一点以供稍后讨论。
但是我们匹配的是什么?
我们希望根据两个 table 中的符号字段匹配记录。 (如果你的逻辑在未来变得更复杂,你可以根据需要匹配多个字段。)但是由于我们想强制左外连接为我们提供非匹配的 Null 值,我们还必须包括以下条件在 table 连接级别测试最小值和最大值。因此,我们使用 "AND" 语句并根据 Rangetbl Min 和 Rangetbl Max 测试 Vendortbl 价格。这三个测试将匹配符号并测试价格是否在最小最大范围内。
Vendortbl 匹配将从 Rangetbl 抓取的字段中包含有效数据。而 Vendortbl Non-Mathces 将从 Rangetbl 抓取的字段中具有 Null 值。
但我们只需要不匹配项!
嗯,这很简单。您只需添加一个 WHERE 子句来测试 Rangetbl 字段中的 Null 值。该字段中的 Null 值表示未找到匹配项。您可以选择任何 Rangetbl 字段进行测试,但我选择了 Symbol,因为它保证在匹配发生时不会有空值。 这很重要!再读一遍! 这里的神奇之处在于,如果您有一个 Null,您就知道该记录不符合您的测试标准!您已找到不匹配项(或拒绝项)。
但在 Access 中,它不能很好地测试空值。所以你必须使用一个叫做 "IsNull()" 的函数来测试你感兴趣的字段。如果 IsNull 为真,你测试的字段有一个 Null 值。因此,isnull(Rangetbl.Symbol) = true
将 return 您的 Rangetbl Null 记录,这是您的不匹配项。
但是等等!我们还没有完成!
我们只希望每个供应商有一个记录。当所有三个 Symbol 都未通过测试时会发生什么?您将获得每个不匹配项的供应商记录。因此,您可能拥有三个 "UrFruit Inc." 记录。 那个会很烦人。所以......为了确保在失败的情况下只获得一条记录,你必须在 SELECT 子句之后放置 DISTINCT 。这可确保您的被拒绝供应商只会在列表中出现一次。
哒哒!您现在可以创建调用 [qry01NonMatches] 并列出所有拒绝的报告或表格(或两者)。
嗯...这解决了您的拒绝列表问题。但是你的 Accepts 呢?
您可以使用相同的 Left Outer Join 逻辑来查找匹配的记录(这意味着记录符合您的所有测试并落在您的范围内)。因为您知道您所有的不匹配项是谁……不在此列表中的是匹配项。因此,找到与我们刚刚创建的不匹配列表不匹配的记录。
再次强调,您需要在 Access 数据库项目中创建一个新查询。 (取消过去的向导,所以你有一个空白查询。)
您可以将其保存为 [qry02Matches]。
切换到 "SQL View"(使用功能区左上方的按钮。)
在此SQL代码中复制:
SELECT DISTINCT Vendortbl.Vendor
FROM Vendortbl LEFT OUTER JOIN qry01NonMatches ON
Vendortbl.Vendor = qry01NonMatches.Vendor
WHERE IsNull(qry01NonMatches.Vendor) = true;
注意...我们正在将 Vendortbl 加入我们之前为查找不匹配的供应商而进行的查询。
我们再次需要 Vendortbl 中的所有记录,但这次我们匹配拒绝查询。但是这次我们想在 Vendor Field 上进行测试。因此,匹配项将在 qry01NonMatches 供应商字段中包含数据,而不匹配项将在 qry01NonMatches 供应商字段中包含空值。但是由于匹配有我们的拒绝,我们想要保存不匹配(这是我们的非拒绝或 "accepts")。因此,为了保存不匹配项,我们需要一个 WHERE 子句来检查 qry01NonMatches.Vendor 是否为 Null。即:IsNull(qry01NonMatches.Vendor) = true
再一次,我们需要在 SELECT 子句之后使用 DISTINCT,这样我们只能为每个唯一的供应商获得一条记录。这在这里非常重要,因为逻辑规定每个接受的供应商总是有三个记录。
哇啦!现在您可以创建一个报告或表格(或两者)来调用 [qry02Matches] 并列出所有已接受的供应商。
(如果您想列出所有您接受的价格,您可以从查询中删除 DISTINCT 并显示您想要的任何 Vendortbl 字段。)
Left Outer Joins 的强大程度令人惊奇,一旦您理解了它们,使用起来又是多么简单。希望这个解释有所帮助。 :)
最后一点建议:您应该考虑制作一个 [VendorSymbol] 字段,以便您可以在第二个查询中匹配 that。这是一个重要的数据库设计问题。您会发现人们会在 [Vendor] 等描述字段中拼错内容。某些条目可能会被缩写,而其他条目可能会被完整拼写。因此,不同的拼写不会匹配,即使它们代表相同的实体。在这种情况下,第三范式是你的朋友。它是更好的数据库设计,将为您省去很多麻烦。
我正在使用 Access 数据库并使用 VB/VBA 进行编程。我有两个 tbl,如下所示。第一个是从供应商处获取信息和价格。第二个是我自己公司的价格区间。我想检查 3 种不同类型 (1,2,3) 的水果的 3 种价格,分为最小值和最大值以及 return 基于水果符号的供应商名称。
例如: 如果 Apple 的价格为 2.1、2.23、2.47,落入范围:2.1 - 2.55,则接受供应商的价格和 return FreshFruit Inc。如果不是,则拒绝该水果的所有 3 个价格 Type/Symbol 和显示拒绝的警告消息。
我尝试过很多不同的查询方式,但有点太复杂了。我正在考虑改用脚本,但我不确定。
供应商bl:
供应商|水果|类型|符号|价格
FreshFruit Inc. |Apple |1 |Ap |2.1
FreshFruit Inc. |Apple |2 |Ap |2.23
FreshFruit Inc. |Apple |3 |Ap |2.47
GreenProd LLC。 |香蕉 |1 |Ba |0.65
GreenProd LLC。 |香蕉 |2 |Ba |0.67
GreenProd LLC。 |香蕉 |3 |Ba |0.63
UrFruit Inc. |木瓜 |1 |Py |1.86
UrFruit Inc. |木瓜 |2 |Py |1.62
UrFruit Inc. |木瓜 |3 |Py |1.73
这是另一个列表:
Rangetbl
水果 |符号|最小值 |最大值
苹果 |Ap |2.1 |2.55
香蕉 |Ba |0.6 |0.65
木瓜 |Py |1.6 |1.75
感谢您的帮助
您需要做的是考虑在您的 table 上使用左外连接。这样您就可以找到不匹配的(或被拒绝的供应商)。
找到不匹配项后,您必须进行另一次匹配以排除出现在不匹配列表中的供应商,从而为您提供匹配项(或接受的供应商)。
如果你想复杂一点,在Selects中使用嵌入的Selects,你可以在一个查询中全部写完。
但是如果您正在使用 VBA 并希望它对可能遇到您的代码的未来程序员保持可读性,您可以编写几个不同的查询 运行 一个接一个。 (即第一个查询找到您的不匹配项(拒绝),您的第二个查询与第一个查询匹配以创建已接受供应商列表。)
其他一些注意事项:
它可能会帮助您索引您拥有的 table 并创建主要的 键。
阅读第三范式。它会帮助你设计 更好 tables。 (你不必成为第三范式的奴隶...... 但知道它可以帮助你解决很多问题 数据结构更容易理解。)
祝你好运:)
编辑 2015 年 8 月 5 日:
好的...我有时间帮助解决细节问题。使用 Left Outer Join 查找不匹配项可能很难弄清楚。所以这是我最好的解释它们的方法:
首先,您需要将 [Rangetbl] 中的 [Symbol] 字段设置为主键,以便在不允许重复的情况下对其进行索引(如果尚未)。您不能在此字段中允许重复项,否则左外连接将无法正常工作。 (如果你在那里需要重复项,你需要重组你的 tables...这是另一个超出此解决方案范围的讨论。)同时将它的 "Allow Zero Length" 设置为 "No" .数据集中也不能有 Null 值。
您需要在 Access 数据库项目中创建一个新查询。 (取消过去的向导,所以你有一个空白查询。)
您可以将其保存为 [qry01NonMatches]。
切换到 "SQL View"(使用功能区左上方的按钮。)
复制此 SQL 代码:
SELECT DISTINCT Vendortbl.Vendor
FROM Vendortbl LEFT OUTER JOIN Rangetbl ON
(Vendortbl.Symbol = Rangetbl.Symbol)
AND (Vendortbl.Price <= Rangetbl.Max)
AND (Vendortbl.Price >= Rangetbl.Min)
WHERE isnull(Rangetbl.Symbol) = true;
这是您的左外连接,用于查找至少有一个记录超出给定符号 min/max 范围的所有供应商。这给出了被您拒绝的供应商列表。
这是怎么做到的(您可能会问)?
Left Outer Join 告诉数据库 return 无论如何,所有 Vendortbl 记录。但是它加入了 Rangetbl,如果找到匹配项,它将 return Rangetbl 数据。我们在这里使用的技巧是,如果存在 No Match,我们仍将获得 Vendortbl 记录,但由于没有 Rangetbl 记录,Rangetbl 字段将填充 Null 值。 (很明显!因为没有可匹配的数据。)记住这一点以供稍后讨论。
但是我们匹配的是什么?
我们希望根据两个 table 中的符号字段匹配记录。 (如果你的逻辑在未来变得更复杂,你可以根据需要匹配多个字段。)但是由于我们想强制左外连接为我们提供非匹配的 Null 值,我们还必须包括以下条件在 table 连接级别测试最小值和最大值。因此,我们使用 "AND" 语句并根据 Rangetbl Min 和 Rangetbl Max 测试 Vendortbl 价格。这三个测试将匹配符号并测试价格是否在最小最大范围内。
Vendortbl 匹配将从 Rangetbl 抓取的字段中包含有效数据。而 Vendortbl Non-Mathces 将从 Rangetbl 抓取的字段中具有 Null 值。
但我们只需要不匹配项!
嗯,这很简单。您只需添加一个 WHERE 子句来测试 Rangetbl 字段中的 Null 值。该字段中的 Null 值表示未找到匹配项。您可以选择任何 Rangetbl 字段进行测试,但我选择了 Symbol,因为它保证在匹配发生时不会有空值。 这很重要!再读一遍! 这里的神奇之处在于,如果您有一个 Null,您就知道该记录不符合您的测试标准!您已找到不匹配项(或拒绝项)。
但在 Access 中,它不能很好地测试空值。所以你必须使用一个叫做 "IsNull()" 的函数来测试你感兴趣的字段。如果 IsNull 为真,你测试的字段有一个 Null 值。因此,isnull(Rangetbl.Symbol) = true
将 return 您的 Rangetbl Null 记录,这是您的不匹配项。
但是等等!我们还没有完成!
我们只希望每个供应商有一个记录。当所有三个 Symbol 都未通过测试时会发生什么?您将获得每个不匹配项的供应商记录。因此,您可能拥有三个 "UrFruit Inc." 记录。 那个会很烦人。所以......为了确保在失败的情况下只获得一条记录,你必须在 SELECT 子句之后放置 DISTINCT 。这可确保您的被拒绝供应商只会在列表中出现一次。
哒哒!您现在可以创建调用 [qry01NonMatches] 并列出所有拒绝的报告或表格(或两者)。
嗯...这解决了您的拒绝列表问题。但是你的 Accepts 呢?
您可以使用相同的 Left Outer Join 逻辑来查找匹配的记录(这意味着记录符合您的所有测试并落在您的范围内)。因为您知道您所有的不匹配项是谁……不在此列表中的是匹配项。因此,找到与我们刚刚创建的不匹配列表不匹配的记录。
再次强调,您需要在 Access 数据库项目中创建一个新查询。 (取消过去的向导,所以你有一个空白查询。)
您可以将其保存为 [qry02Matches]。
切换到 "SQL View"(使用功能区左上方的按钮。)
在此SQL代码中复制:
SELECT DISTINCT Vendortbl.Vendor
FROM Vendortbl LEFT OUTER JOIN qry01NonMatches ON
Vendortbl.Vendor = qry01NonMatches.Vendor
WHERE IsNull(qry01NonMatches.Vendor) = true;
注意...我们正在将 Vendortbl 加入我们之前为查找不匹配的供应商而进行的查询。
我们再次需要 Vendortbl 中的所有记录,但这次我们匹配拒绝查询。但是这次我们想在 Vendor Field 上进行测试。因此,匹配项将在 qry01NonMatches 供应商字段中包含数据,而不匹配项将在 qry01NonMatches 供应商字段中包含空值。但是由于匹配有我们的拒绝,我们想要保存不匹配(这是我们的非拒绝或 "accepts")。因此,为了保存不匹配项,我们需要一个 WHERE 子句来检查 qry01NonMatches.Vendor 是否为 Null。即:IsNull(qry01NonMatches.Vendor) = true
再一次,我们需要在 SELECT 子句之后使用 DISTINCT,这样我们只能为每个唯一的供应商获得一条记录。这在这里非常重要,因为逻辑规定每个接受的供应商总是有三个记录。
哇啦!现在您可以创建一个报告或表格(或两者)来调用 [qry02Matches] 并列出所有已接受的供应商。
(如果您想列出所有您接受的价格,您可以从查询中删除 DISTINCT 并显示您想要的任何 Vendortbl 字段。)
Left Outer Joins 的强大程度令人惊奇,一旦您理解了它们,使用起来又是多么简单。希望这个解释有所帮助。 :)
最后一点建议:您应该考虑制作一个 [VendorSymbol] 字段,以便您可以在第二个查询中匹配 that。这是一个重要的数据库设计问题。您会发现人们会在 [Vendor] 等描述字段中拼错内容。某些条目可能会被缩写,而其他条目可能会被完整拼写。因此,不同的拼写不会匹配,即使它们代表相同的实体。在这种情况下,第三范式是你的朋友。它是更好的数据库设计,将为您省去很多麻烦。