嵌套的iif()语句“太复杂”,无法在MS Access中运行

时间:2019-06-27 18:38:45

标签: ms-access access-vba

我当前正在更新我为工作而创建的数据库,以将事务分类为事务类型。这要求我使用一个iif()语句,该语句变得太复杂而无法运行。在进行深入探讨之前,我想对冗长的描述表示歉意,但是我想确保提供足够的信息。

设置舞台

交易(RefID)可以是以下之一:

  • 3PL
  • 4PL
  • 空运
  • 仅海关

此任务的复杂性之一是,根据交易的情况,类似于商品编号或服务名称的收费代码(CC)可以是3PL或4PL。例如,如果RefID上也存在Ocean_Freight的CC,而CC的PO_Management则为CC,则该事务为3PL事务。但是,如果存在RefID上没有Ocean_Freight的PO_Management CC,则这将是4PL事务。

我有以下CC可用于定义交易:

CC说明

仅3PL

  • 远洋货运
    • 除非下面的“ 3PL或4PL根据情况”部分中有CC,否则该CC将定义交易。
  • 托盘管理
    • 除非下面的“ 3PL或4PL根据情况”部分中有CC,否则该CC将定义交易。

仅空运

  • 空运货物

3PL或4PL视情况而定

  • PO_Management
    • 使用Ocean_Freight或Drayage Management的RefID上存在CC时为3PL
    • 在没有上述CC的RefID上存在CC时的4PL
  • CROM费用

    • 使用Ocean_Freight或Drayage Management的RefID上存在CC时为3PL
    • 在没有Ocean_Freight,Drayage Management或PO_Management的RefID上存在CC的4PL
  • EDI

    • 使用Ocean_Freight或Drayage Management的RefID上存在CC时为3PL
    • 在没有Ocean_Freight,Drayage Management或PO_Management的RefID上存在CC的4PL
  • 预订管理费
    • 使用Ocean_Freight或Drayage Management的RefID上存在CC时为3PL
    • 在没有Ocean_Freight,Drayage Management,PO_Management或EDI的RefID上存在CC的4PL
  • 运费
    • 使用Ocean_Freight或Drayage Management的RefID上存在CC时为3PL
    • 如果RefID上存在CC,而没有Ocean_Freight,运费,托盘管理,PO_Management,EDI或订舱管理费,则为4li
  • 手续费
    • 使用Ocean_Freight或Drayage Management的RefID上存在CC时为3PL
    • 如果RefID上存在CC,而没有Ocean_Freight,运费管理,托盘管理,PO_Management,EDI,预订管理费或货运代理费,则为4PL

仅海关

请注意-在没有这些CC且没有海关条目的情况下,可以将我认为上述每个CC都归为交易定义收费代码(TDCC) CC,该交易被定义为“仅海关”交易。

示例交易:

https://imgur.com/e57buni

我到目前为止所做的事情

我以前在Access中使用嵌套的iif()语句完成了此操作,但是在某些情况下,由于没有隔离每个CC,因此我提取了重复的记录。例如,如果同一事务上同时存在PO_Management和Handling Charge,则两者都将被赋予“ 4PL”的值,而实际上,我只希望定义一个事务。这就是使我无法修复代码的原因。

驱动大多数查询的查询称为“第2步”,它基于RefID上是否存在CC来执行sum(iif(criteria here,1,0))。如果RefID上存在CC,则它提供的值> 0,这使我可以引用此查询来确定如何定义RefID。

为了进一步完善我的原始方法,我再次查询了“步骤”。在此查询中,我在上面的CC说明部分中应用了上面的逻辑。

我曾尝试使用嵌套的iif()语句,也曾尝试使用Switch()函数,但是两者都达到了同一点:“您输入的表达式太复杂了。”我已经进行了一些研究,我相信答案是使用VBA的私有功能,但是我对理解如何创建功能并不满意。有谁有更好的方法来解决这个问题?请找到我最近尝试使用switch()函数的示例,该函数可消除以下错误:

Transaction Type: 

    Switch(
      [Steps]![OF] > 0           And [Steps]![CC] = "Ocean Freight","3PL",
      [Steps]![AF] > 0           And [Steps]![CC] = "Air_Freight","Air Freight",
      [Steps]![Dray] > 0         And [Steps]![CC] = "Drayage Management","3PL",
      [Steps]![PO 4PL] > 0       And [Steps]![CC] = "PO_Management","4PL",
      [Steps]![PO 3PL] > 0       And [Steps]![CC] = "PO_Management","3PL",
      [Steps]![CROM 4PL] > 0     And [Steps]![CC] = "CROM Fee","4PL",
      [Steps]![CROM 3PL] > 0     And [Steps]![CC] = "CROM Fee","3PL",
      [Steps]![EDI 4PL] > 0      And [Steps]![CC] = "EDI","4PL",
      [Steps]![EDI 3PL] > 0      And [Steps]![CC] = "EDI","3PL",
      [Steps]![BMF 4PL] > 0      And [Steps]![CC] = "Booking Management Fee","4PL",
      [Steps]![BMF 3PL] > 0      And [Steps]![CC] = "Booking Management Fee","3PL",
      [Steps]![FF 4PL] > 0       And [Steps]![CC] = "Forwarding Fee","4PL",
      [Steps]![FF 3PL] > 0       And [Steps]![CC] = "Forwarding Fee","3PL", 
      [Steps]![Handling 4PL] > 0 And [Steps]![CC] = "Handling Charge","4PL", 
      [Steps]![Handling 3PL] > 0 And [Steps]![CC] = "Handling Charge","3PL"
    )

需要发生什么?

最终,我想引用“步骤”查询以在我的输出查询中驱动一个称为“交易类型”的字段。当然,这对我来说是横向的,因为我无法在iif()语句中获得足够的嵌套。这向我表明我将要解决所有这些错误,并且存在一个更简单的解决方案。

3 个答案:

答案 0 :(得分:4)

您有一个相对简单的一对一映射情况。解决此问题的一种有效而灵活的方法是创建一个映射表来封装您的规则:

OF  AF  Dray  [PO 4PL]  [PO 3PL]  [CROM 4PL]  CC                     RefId
1                                             "Ocean Freight"        "3PL"
    1                                         "Air_Freight"          "Air Freight"
        1                                     "Drayage Management"   "3PL"
              1                               "PO_Management"        "4PL"
                        1                     "PO_Management"        "3PL"
                                  1           "CROM Fee"             "4PL"

在表中为要检查的其他字段添加更多列。

现在可以编写一个SELECT(或类似的UPDATE语句),该SELECT基于表中的规则选择RefId(警告,这是伪代码,我现在没有MS Access对此进行测试):

SELECT
  t.*
  r.RefId
FROM
  Transactions t
  LEFT JOIN TransactionMappings m ON
    t.CC = m.CC
    AND (
      (t.OF > 0 AND m.OF = 1) OR
      (t.AF > 0 AND m.AF = 1) OR
      (t.Dray > 0 AND m.Dray = 1) OR
      (t.[PO 4PL] > 0 AND m.[PO 4PL] = 1) OR
      (t.[PO 3PL] > 0 AND m.[PO 3PL] = 1)
    )

优点是

  • 比较干净的代码
  • 您无需修改​​SQL即可修改映射规则
  • JOIN(可能)比嵌套/复杂Switch()更快,尽管这需要进行测量
  • 使它变得更加复杂相对容易(诸如“添加要检查的数字范围”或“在某些情况下例外”之类的事情归结为在映射表中添加更多列并指定更多JOIN条件),以相同的方式嵌套的Switch()更加复杂。

答案 1 :(得分:3)

当函数的参数过多时,会发生太复杂错误。一个简单的解决方法是拆分开关:

您可以轻松地将//Initializing single cURL descriptor $ch1 = curl_init("example.com/registerFlood.php"); //HTTPS portocol $ch2 = curl_init("example.com/registerFlood.php"); //HTTPS portocol // cURL options //$ch1 curl_setopt($ch1, CURLOPT_POST, TRUE); curl_setopt($ch1, CURLOPT_POSTFIELDS, 'username=TESTINGW&password1=vsadf!daG1&email=nrvcsdsabg&submit=submit'); //$ch2 curl_setopt($ch2, CURLOPT_POST, TRUE); curl_setopt($ch1, CURLOPT_POSTFIELDS, 'username=51INGW&password1=vsadf!daG1&email=nrvcsdsabg&submit=submit'); //Initializing multi cURL descriptor $mh = curl_multi_init(); //Adding handles curl_multi_add_handle($mh,$ch1); curl_multi_add_handle($mh,$ch2); //Executing multi cURL do { $status = curl_multi_exec($mh, $active); echo curl_multi_strerror(curl_multi_errno($mh)); if ($active) { curl_multi_select($mh); } } while ($active && $status == CURLM_OK); //Closing Descriptors curl_multi_remove_handle($mh, $ch1); curl_multi_remove_handle($mh, $ch2); curl_multi_close($mh); 拆分为Switch(Compare1, Result1, Compare2, Result2, Compare3, Result3, Compare4, Result4)。虽然我们确实增加了复杂性,但我们的各个switch语句采用的参数较少,因此Access抱怨的可能性较小。

在您的示例中,将其分成两个样子:

Switch(Compare1, Result1, Compare2, Result2, True, Switch(Compare3, Result3, Compare4, Result4))

那仍然是相当多的参数,因此您可能需要将其分为三部分。

答案 2 :(得分:0)

首先创建一个私有函数非常简单,代码如下:

Private Function functionName(Arguments)

'your code here

End function

唯一的问题是,即使具有函数,您的switch语句本身也太长且太复杂。您将获得重复的值,因为它将具有多个“ true”值。为了解决这个问题,一组If和Else If语句会更好地工作。请查看此页面以获取更多详细信息https://docs.microsoft.com/en-us/office/vba/language/concepts/getting-started/using-ifthenelse-statements