Get Data by comparing a set of data with a range

时间:2015-07-31 20:25:00

标签: ms-access access-vba ms-access-2007 ms-access-2010

I am working with an Access Database and using VB/VBA for programming. I have two tbl's as shown below. The first one is to get information and price from vendors. The second one is my own company price range. I want to check for 3 Prices from 3 different Types (1,2,3) of Fruit falling into Min and Max and return the Vendor name based on the Fruit Symbol.

For example: If the prices for Apple are 2.1, 2.23, 2.47 falling into the range: 2.1 - 2.55, then accept that vendor's price and return FreshFruit Inc. If not, reject all 3 prices of that fruit Type/Symbol and show an alert message for rejection.

I have tried many different ways with queries, but it is kind of too complex. I am thinking about using scripts instead, but I am not sure about that.

Vendortbl:

Vendor |Fruit |Type|Symbol|Price

FreshFruit Inc. |Apple |1 |Ap |2.1

FreshFruit Inc. |Apple |2 |Ap |2.23

FreshFruit Inc. |Apple |3 |Ap |2.47

GreenProd LLC. |Banana |1 |Ba |0.65

GreenProd LLC. |Banana |2 |Ba |0.67

GreenProd LLC. |Banana |3 |Ba |0.63

UrFruit Inc. |Papaya |1 |Py |1.86

UrFruit Inc. |Papaya |2 |Py |1.62

UrFruit Inc. |Papaya |3 |Py |1.73

Here is another tbl:

Rangetbl

Fruit |Symbol|Min |Max

Apple |Ap |2.1 |2.55

Banana |Ba |0.6 |0.65

Papaya |Py |1.6 |1.75

Thank you for your help

1 个答案:

答案 0 :(得分:1)

您需要做的是在桌面上使用左外连接。这样你就可以找到你的不匹配(或被拒绝的供应商)。

一旦找到不匹配的内容,您就必须再做一次匹配,以排除出现在您的不匹配列表中的供应商,为您提供匹配(或接受的供应商)。

如果你想要复杂并且在Selects中使用嵌入的Selects,你可以在一个查询中编写它。

但是如果您正在使用VBA并希望让未来可能遇到您的代码的程序员保持可读性,那么您可以编写一些接着运行的不同查询。 (即第一个查询找到您的不匹配(Rejects),第二个查询与第一个查询匹配,以创建一个Accepted供应商列表。)

要记住的其他一些事项:

  1. 它可能会帮助您索引您拥有的表并创建主表 键。

  2. 阅读第三范式。它可以帮助您设计 更好的桌子。 (你不必成为第三范式的奴隶...... 但知道它可以帮助你解决很多问题 数据结构更容易理解。)

  3. 祝你好运:)

    2015年8月5日编辑:

    好的......我有时间帮忙解决细节问题。使用左外连接来查找不匹配可能很难搞清楚。所以这是我最好的解释它们:

    首先,您需要将[Rangetbl]中的[Symbol]字段变为主键,以便它允许无重复索引(如果它还没有)。您不能在此字段中允许重复,否则左外部联接将无法正常工作。 (如果您需要重复,那么您需要对表格进行重组......而另一个讨论超出了此解决方案的范围。)同时设置它" s"允许零长度"到"不"。您也不能在数据集中使用Null值。

    您需要在Access数据库项目中创建一个新查询。 (取消通过向导,以便查询空白。)

    您可以将其另存为[qry01NonMatches]。

    Swicth to" 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;
    

    这是您的左外连接,以查找至少有一条记录超出给定符号的最小/最大范围的所有供应商。这给出了您拒绝的供应商列表。

    这是怎么做的(你可能会问)?

    Left Outer Join告诉数据库无论如何返回所有Vendortbl记录。但它加入Rangetbl并且如果找到匹配则将返回Rangetbl数据。我们在这里使用的技巧是,如果有 No Match ,我们仍将获得Vendortbl记录,但由于没有Rangetbl记录,Rangetbl字段将填充Null值。 (显然!因为没有可匹配的数据。)请在讨论的后期记住这一点。

    但是我们匹配的是什么?

    我们希望根据两个表中的符号字段匹配记录。 (如果您的逻辑在未来变得更加复杂,您可以根据需要匹配多个字段。)但是,由于我们要强制Left Outer Join为非匹配项提供Null值,我们还必须包含在表连接级别测试Min和Max。因此我们使用&#34; AND&#34;对Rangetbl Min和Rangetbl Max测试Vendortbl价格并进行测试。这三个测试将匹配符号并测试价格是否在最小最大范围内。

    Vendortbl Matches将在Rangetbl中获取的字段中包含有效数据。并且Vendortbl Non-Mathces在从Rangetbl抓取的字段中将具有Null值。

    但我们只想要非比赛!

    那很容易。您只需添加一个WHERE子句来测试Rangetbl中字段中的Null值。该字段中的Null值表示找不到匹配项。您可以选择要测试的任何Rangetbl字段,但我选择了Symbol,因为它确保在匹配发生时没有Null。 那很重要!再读一遍!这里的神奇之处在于,如果你有空,你知道这个记录不符合你的测试标准!您已找到您的不匹配(或拒绝)。

    但是在Access中,它并没有很好地测试空值。所以你必须使用一个名为&#34; IsNull()&#34;的函数。测试您感兴趣的字段。如果IsNull为true,则您测试的字段具有Null值。因此,isnull(Rangetbl.Symbol) = true将返回您的非匹配的Rangetbl Null记录。

    但是等等!我们还没有完成! 我们只想为每个供应商提供一条记录。当所有三个符号都未通过测试时会发生什么?您将获得每次非匹配的供应商记录。因此,你可能有三个&#34; UrFruit公司。&#34;记录。 会很烦人。所以......为了确保在失败的实例中只获得一条记录,你必须将DISTINCT放在SELECT子句之后。这可确保您的已拒绝供应商仅在列表中显示一次。

    塔达!您现在可以创建一个调用[qry01NonMatches]并列出所有拒绝的报表或表单(或两者)。

    嗯......这解决了你的拒绝列表问题。但你的接受呢?

    您可以使用相同的Left Outer Join逻辑来查找您的匹配记录(这意味着记录符合您的所有测试并落在您的范围内)。既然你知道你的所有非匹配是谁......那个不在这个列表中的那些是匹配的。因此,找到我们刚创建的不匹配不匹配列表的记录。

    再一次,您需要在Access数据库项目中创建一个新查询。 (取消通过向导,以便查询空白。)

    您可以将其另存为[qry02Matches]。

    Swicth to&#34; SQL View&#34; (使用左上方功能区上的按钮。)

    复制此SQL代码:

    SELECT DISTINCT Vendortbl.Vendor
        FROM Vendortbl LEFT OUTER JOIN qry01NonMatches ON 
            Vendortbl.Vendor = qry01NonMatches.Vendor
        WHERE IsNull(qry01NonMatches.Vendor) = true;
    

    注意......我们正在将Vendortbl加入我们之前为查找不匹配供应商而进行的查询。

    再次,我们想要来自Vendortbl的所有记录,但这次我们匹配拒绝查询。但是我们这次要在供应商领域进行测试。因此,匹配将在qry01NonMatches供应商字段中包含数据,而非匹配将在qry01NonMatches供应商中具有空值。但由于匹配有我们的拒绝,我们希望保存不匹配(这是我们的非拒绝或&#34;接受&#34;)。因此,为了保存不匹配,我们需要一个WHERE子句来检查qry01NonMatches.Vendor是否为Null。这是:IsNull(qry01NonMatches.Vendor) = true

    再次,我们需要在SELECT子句之后使用DISTINCT,因此我们只为每个唯一供应商获取一条记录。这在这里非常重要,因为逻辑规定每个接受的供应商总会有三条记录。

    哇啦啦!现在,您可以创建一个调用[qry02Matches]的报表或表单(或两者),并列出所有已接受的供应商。

    (如果您想列出所有可接受的价格,您可以从查询中删除DISTINCT并显示您喜欢的任何Vendortbl字段。)

    令人惊讶的是,左外连接有多强大,一旦你理解它们就会变得多么简单。希望这个解释有所帮助:)

    最后一点建议:您应该考虑创建一个[VendorSymbol]字段,以便在第二个查询中匹配那个。这是一个重要的数据库设计问题。你会发现人们会在[供应商]这样的描述字段中拼错。有些条目可能会缩写,其他条目可能完全拼写出来。因此,即使它们代表相同的实体,不同的拼写也不会匹配。在这种情况下,第三范式是您的朋友。它是更好的数据库设计,可以为您节省大量的麻烦。