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

Posted

技术标签:

【中文标题】列的访问验证规则可能是:日期、特定文本字符串或 null【英文标题】:Access validation rule for a column that could be: a date, a specific text string, or null 【发布时间】:2014-11-07 16:56:18 【问题描述】:

我有一列可以是:

    短日期:DD/MM/YYYY 字符串:“N/A” 空

我可以使用表中的验证规则字段来强制执行此操作吗?如果是,我该怎么做?

【问题讨论】:

它必须是一个有效的日期。所以 2001 年 1 月 11 日、1950 年 9 月 12 日、2018 年 1 月 22 日都很好。 2001 年 13 月 35 日 - 不行 【参考方案1】:

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

那个宏的 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 的回答之外,以下只是将您的日期/文本信息存储在单个(文本)字段中可能仍然不是一个好主意的几个原因,即使有所有这些花哨的验证:

    通过将日期值存储为文本,您承诺在任何时候将字段值用作日期(而不只是逐字打印)将文本转换回实际日期值。这不仅令人讨厌,而且可能会对性能产生重大影响(请参见下面的第 3 点)。

    通过将日期格式“硬连线”为dd/mm/yyyy,您将其强加给您的用户。如今,人们希望应用程序尊重他们的偏好,因此如果有人决定他们想要使用 yyyy/mm/dd 格式——并且他们已经在 Windows 控制面板中指定了这一点——那么他们希望他们的应用程序使用它。

    也许最重要的是,通过将日期存储为 dd/mm/yyyy 文本,您基本上可以保证您在单日文字 dd/mm/yyyy 值之外进行的任何搜索都不会是 sargable,并且需要进行表扫描。如果您选择了yyyy/mm/dd,您至少可以通过直接字符串比较完成日期范围搜索,但是使用dd/mm/yyyy(甚至mm/dd/yyyy)字符串,您的搜索性能会受到影响。

【讨论】:

非常感谢您提供如此详细的答案。几个后续问题。 1) 对不同字段重复此操作的最佳方法是什么,我有大约 10 个需要验证的类似字段? 2. 如何导入您指定的 XML?我最终将您的示例逐行复制到宏编辑器中。再次感谢。

以上是关于列的访问验证规则可能是:日期、特定文本字符串或 null的主要内容,如果未能解决你的问题,请参考以下文章

如何设置验证规则:MS 访问中的“任务开始日期 >= 项目开始日期”

C# 字符串 数据类型 判断 与特定规则验证

用于比较具有包含日期​​的单元格的列并将特定文本粘贴到另一列的 Vba 代码

验证一列大于yii中另一列的日期

根据可能位于特定列中任何位置的日期过滤文件

Swift 4 或 Swift 5 中的 UITextView 用户输入文本验证:限制 Swift 中的特定字符