列的访问验证规则可以是:日期,特定文本字符串或null

时间:2014-11-07 16:56:18

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

我有一个列可以是:

  1. 短日期:DD / MM / YYYY
  2. 字符串:“N / A”
  3. 我可以使用表格中的验证规则字段来强制执行此操作吗?如果是这样我该怎么做?

1 个答案:

答案 0 :(得分:1)

尝试在字段级别使用单个验证规则进行验证可能有点繁琐,但由于您使用的是Access 2010,因此您可以使用Before Change data macro进行验证:

BeforeChange.png

该宏的XML源代码是

<?xml version="1.0" encoding="utf-16" standalone="no"?>
<DataMacros xmlns="http://schemas.microsoft.com/office/accessservices/2009/11/application">
  <DataMacro Event="BeforeChange">
    <Statements>
      <Action Collapsed="true" Name="SetLocalVar">
        <Argument Name="Name">dateStringIsValid</Argument>
        <Argument Name="Value">False</Argument>
      </Action>
      <ConditionalBlock>
        <If>
          <Condition>IsNull([dateString])</Condition>
          <Statements>
            <Action Collapsed="true" Name="SetLocalVar">
              <Argument Name="Name">dateStringIsValid</Argument>
              <Argument Name="Value">True</Argument>
            </Action>
          </Statements>
        </If>
        <ElseIf>
          <Condition>UCase([dateString])=&quot;N/A&quot;</Condition>
          <Statements>
            <Comment>force to uppercase for consistency</Comment>
            <Action Collapsed="true" Name="SetField">
              <Argument Name="Field">dateString</Argument>
              <Argument Name="Value">UCase([dateString])</Argument>
            </Action>
            <Action Collapsed="true" Name="SetLocalVar">
              <Argument Name="Name">dateStringIsValid</Argument>
              <Argument Name="Value">True</Argument>
            </Action>
          </Statements>
        </ElseIf>
        <ElseIf>
          <Condition>Len([dateString])=10</Condition>
          <Statements>
            <Action Collapsed="true" Name="SetLocalVar">
              <Argument Name="Name">ddStr</Argument>
              <Argument Name="Value">Mid([dateString],1,2)</Argument>
            </Action>
            <Action Collapsed="true" Name="SetLocalVar">
              <Argument Name="Name">mmStr</Argument>
              <Argument Name="Value">Mid([dateString],4,2)</Argument>
            </Action>
            <Action Collapsed="true" Name="SetLocalVar">
              <Argument Name="Name">yyyyStr</Argument>
              <Argument Name="Value">Mid([dateString],7,4)</Argument>
            </Action>
            <Action Collapsed="true" Name="OnError">
              <Argument Name="GoTo">Next</Argument>
            </Action>
            <Action Collapsed="true" Name="SetLocalVar">
              <Argument Name="Name">newDate</Argument>
              <Argument Name="Value">DateSerial(Val([yyyyStr]),Val([mmStr]),Val([ddStr]))</Argument>
            </Action>
            <Action Collapsed="true" Name="OnError">
              <Argument Name="GoTo">Fail</Argument>
            </Action>
            <ConditionalBlock>
              <If>
                <Condition>[MacroError].[Number]=0</Condition>
                <Statements>
                  <Comment>make sure DateSerial() hasn&#39;t converted an invalid date to a valid one (e.g. 32/01/2014 -&gt;
                  01/02/2014)</Comment>
                  <ConditionalBlock>
                    <If>
                      <Condition>(Year([newDate])=Val([yyyyStr])) And (Month([newDate])=Val([mmStr])) And
                      (Day([newDate])=Val([ddStr]))</Condition>
                      <Statements>
                        <Comment>reassemble to ensure consistent separators</Comment>
                        <Action Collapsed="true" Name="SetField">
                          <Argument Name="Field">dateString</Argument>
                          <Argument Name="Value">[ddStr] &amp; &quot;/&quot; &amp; [mmStr] &amp; &quot;/&quot; &amp;
                          [yyyyStr]</Argument>
                        </Action>
                        <Action Collapsed="true" Name="SetLocalVar">
                          <Argument Name="Name">dateStringIsValid</Argument>
                          <Argument Name="Value">True</Argument>
                        </Action>
                      </Statements>
                    </If>
                  </ConditionalBlock>
                </Statements>
              </If>
            </ConditionalBlock>
          </Statements>
        </ElseIf>
      </ConditionalBlock>
      <ConditionalBlock>
        <If>
          <Condition>[dateStringIsValid]=False</Condition>
          <Statements>
            <Action Collapsed="true" Name="RaiseError">
              <Argument Name="Number">1</Argument>
              <Argument Name="Description">dateString is not valid.</Argument>
            </Action>
          </Statements>
        </If>
      </ConditionalBlock>
    </Statements>
  </DataMacro>
</DataMacros>

(有关如何将数据宏XML代码传入和传出Access数据库的信息,请参阅问题here。)


顺便说一下,在我对你之前的问题here的回答之后,以下几个原因只是为什么将日期/文本信息存储在单个(文本)字段中可能仍然不是很好想法,即使所有这些花哨的验证:

  1. 通过将日期值存储为文本,您可以随时将文本转换回实际日期值,只要您想将字段值用作日期(除了只是逐字打印)。这不仅令人讨厌,而且可能会产生重大的性能影响(见下文第3点)。

  2. 通过“硬连线”将日期格式设置为dd/mm/yyyy,您将强制它在您的用户身上。这些天人们希望应用程序尊重他们的偏好,所以如果有人决定他们想要使用yyyy/mm/dd格式 - 并且他们已经在Windows控制面板中指定了 - 那么他们希望他们的应用程序使用它。

  3. 也许最重要的是,通过将日期存储为dd/mm/yyyy文字,您基本上可以保证您在单日文字dd/mm/yyyy值之外进行的搜索不会是sargable需要进行表扫描。如果您已经确定yyyy/mm/dd,则可以通过直接字符串比较至少完成日期范围搜索,但使用dd/mm/yyyy(或甚至mm/dd/yyyy)字符串,您的搜索效果将受到影响。