这是创建 SQL 断言的正确方法吗?
为了做出以下类型的断言,
create assertion assert
check "EMPTY SET" = (select User
from Video
where date=current_date()
group by user
having count(*) >= 10
这个断言对吗?
create assertion assert
check 0 = (select count(*)
from Video
where date=current_date()
group by user
having count(*) >= 10
in order to make the following type of assertion
create assertion assert
check "EMPTY SET" = (select User
from Video
where date=current_date()
group by user
having count(*) >= 10
is this assertion right?
create assertion assert
check 0 = (select count(*)
from Video
where date=current_date()
group by user
having count(*) >= 10
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
有关
CREATE ASSERTION
的完整详细信息,请参阅 ISO SQL-92 标准规范。CHECK
定义应放在括号中。CURRENT_DATE
没有括号。USER
和DATE
是保留字。SQL 语句应以分号字符终止。
SQL 关键字应大写。
尝试更像这样的事情:
您可以使用在线 Mimer SQL-92 测试语法是否正确验证器。但是,您还应该测试您的逻辑,例如
CURRENT_DATE
是不确定的。另外,我不认为这个
ASSERTION
会起作用。当子查询的基数小于 10 时,它将返回零行,并且0 = 空集
将计算为UNKNOWN
。当子查询的基数为 10 或更大时,搜索条件将评估TRUE
。 SQL-92 标准状态请注意,您可以将
CHECK (0 = (SELECT COUNT(*) FROM...))
构造替换为CHECK (NOT EXISTS (SELECT * FROM...))
,我发现后者更容易写。更新:
正如我上面所说,您的逻辑似乎有缺陷,因此很难正确实施;)
假设规则是将每个用户每天的视频限制为 10 个。因为这只涉及到单个表,所以使用表级
CHECK
约束会更合适;更新表时会检查这样的约束,这在这种情况下就足够了(不过,没有理由它不能是一个 ASSERTION ,理论上可以在每次任何时候进行检查架构中的表已更新):更新2:
再次考虑一下,仅当表/架构中的数据更新时才会检查
CHECK
/ASSERTION
。在约束中使用 CURRENT_DATE(和其他非确定性函数)的问题在于,业务规则可能会因时钟从一个时间段到下一个时间段的滴答而失效,但如果数据没有“如果在此期间没有更改,则不会检测到数据完整性故障,并且数据库将包含无效数据。另一个考虑因素是一年的含义。
它可以是日历年(1月1日至12月31日(含))或企业定义的其他固定日期(例如4月1日至3月31日(含)),在这种情况下,按年份和用户分组然后进行计数是微不足道的。
一个更有趣的情况是,规则限制任何 12 个月期间的计数;将其扩展到过去和未来可以避免上述“非确定性”问题。
考虑使用辅助日历表的标准方法,包含适用于企业的每一天,扩展到仅根据需要,过去和未来仍应仅包含几千行。每行都将日期作为键,第二列表示该日期加上一年(如果需要,您可以以一天的粒度微调“一年”的定义!)测试将涉及加入日历表,根据日历日期和用户进行分组并进行计数,例如:
这可以放入
CHECK (NOT EXISTS (...
) 约束中。这仍然可以是表级CHECK
约束:因为日历表是一个辅助表,所以它只会受到不频繁的受控更新的影响(但如果需要,也可以是一个ASSERTION
)。For full details on
CREATE ASSERTION
see the ISO SQL-92 Standard spec.The
CHECK
definition should be in parentheses.CURRENT_DATE
does not have parentheses.USER
andDATE
are reserved words.SQL statements should be terminated with a semicolon character.
SQL Keywords should be in upper case.
Try something more like this:
You can test that the syntax is correct using the online Mimer SQL-92 Validator. However, you should also test your logic e.g.
CURRENT_DATE
is non-deterministic.Also, I don't think this
ASSERTION
will ever bite. When the cardinality of the subquery is less than 10 it will return zero rows and0 = empty set
will evaluate toUNKNOWN
. When the cardinality of the subquery is 10 or greater then the search condition will evaluateTRUE
. SQL-92 Standard statesNote you can replace your
CHECK (0 = (SELECT COUNT(*) FROM...))
construct withCHECK (NOT EXISTS (SELECT * FROM...))
, the latter of which I find easier to write.UPDATE:
As I said above, your logic appears flawed so it is hard to implement properly ;)
Let's say the rule is to limit Videos to 10 per user per day. Because this involves only a single table, it would be more appropriate to use a table-level
CHECK
constraint; such a constraint is checked when the table is updated which is sufficient in this case (there's no reason why it couldn't be anASSERTION
, though, which in theory could be checked each time any table in the schema is updated):UPDATE 2:
Consider again that a
CHECK
/ASSERTION
will only be checked when data in the table/schema is updated. The problem with usingCURRENT_DATE
(and other non-determninistic functions) in a constraint is that the business rule can be invalidated simply by the clock ticking over from one time period to the next but if the data hasn't been changed in that period then the data integrity failure will not be detected and the database will contain invalid data.Another consideration is what is meant by a year in context.
It could be the calendar year (1 Jan to 31 Dec inclusive) or other other fixed dates defined by enterprise (e.g. 1 Apr to 31 Mar inclusive), in which case grouping by year and user then counting is trivial.
A more interesting case is when the rule limits the tally for any 12 month period; extending this to both the past and future avoid the above 'non-deterministic' issue.
Consider a standard approach of using an auxiliary calendar table, containing one row for every day applicable to the enterprise, extended into the past and future only as far as required should still only comprise a few thousand rows. Each row would have the date as a key with a second column for that date plus one year (and if necessary you could fine tune the definition of 'a year' at one-day granularity!) The test for would involve joining to the Calendar table, grouping on the calendar date and user and counting e.g. something like this:
This could be put in a
CHECK (NOT EXISTS (...
constraint. This could still be a table-levelCHECK
constraint: because the Calendar table is an auxiliary table it would only be suject to infrequent controlled updates (but again could be anASSERTION
if required).