5

鉴于这种 :

delimiter //
create procedure setup()
begin
  declare d datetime;
  set d = rounddate(now());

  create table s_time (req_id int not null,
                       ser_id int not null,
                       hel_id int not null,
                       posted int unsigned not null,
                       completed int unsigned not null default 0
                      )
  partition by range (completed) (partition p0 values less than ( unix_timestamp(d) ),
                                  partition p1 values less than ( unix_timestamp(d + interval 1 day) )
                                 );
end//

我得到:

ERROR 1064 (42000) : Constant, random, or timezone-dependent expression in (sub)partitioning function are not allowed

有没有办法让它工作,或者我必须使用硬编码字符串作为输入。即使用:unix_timestamp('2012-07-07 00:00:00')

4

2 回答 2

6

为了将解决方案保留在完整的 sql 中,这就是我发现的。

delimiter //
create procedure setup()
begin
  declare d, d2 int;
  set d = unix_timestamp();
  set d2 = unix_timestamp(now() + interval 1 day);

  create table s_time (req_id int not null,
                       ser_id int not null,
                       hel_id int not null,
                       posted int unsigned not null,
                       completed int unsigned not null default 0
                      );

  SET @stmt = concat('alter table s_time PARTITION BY RANGE (completed) (
                      partition p0 values less than (', d, '),
                      partition p1 values less than (', d2, '))');
  PREPARE pStmt FROM @stmt;
  EXECUTE pStmt;
  DEALLOCATE PREPARE pStmt;

end//
delimiter ;
call setup();
于 2012-06-26T13:56:51.453 回答
3

这不起作用的原因不是很清楚,我怀疑文档或错误消息中存在错误。在我看来,您收到的错误是不恰当的。

根据手册:

分区表达式中不允许使用以下结构:

  • 存储过程、存储函数、UDF 或插件。
  • 声明的变量或用户变量。

这解释了为什么您的表定义失败。

现在,如何摆脱你的变量?如果您尝试从分区定义中删除声明的变量:

CREATE TABLE s_time (
    completed INT UNSIGNED NOT NULL DEFAULT 0
)
PARTITION BY RANGE ( completed  ) (
    PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP() )
);

你会得到同样的错误。但是,MySQL手册指出:

也可以在 VALUES LESS THAN 子句中使用表达式。但是,MySQL 必须能够评估表达式的返回值作为 LESS THAN (<) 比较的一部分

根据这个定义,UNIX_TIMESTAMP()应该是一个有效的表达式。手册中的这句话至少可以说是不准确的。我很想知道其他人是否可以提供另一种理解。

现在,查看错误消息,如果您将LESS THAN子句视为“分区函数”的一部分,那么错误消息开始变得有意义:

错误 1064 (42000):不允许在(子)分区函数或 LESS THAN 子句中使用常量、随机或时区相关表达式

通过“随机”,它们也意味着non-deterministic,该UNIX_TIMESTAMP()函数是根据定义的。

为了实现您想要做的事情,除了使用外部脚本生成合适的ALTER TABLE命令外,我没有看到其他解决方案。

1)创建您的初始表:

CREATE TABLE s_time (
    req_id INT NOT NULL,
    ser_id INT NOT NULL,
    hel_id INT NOT NULL,
    posted INT UNSIGNED NOT NULL,
    completed INT UNSIGNED NOT NULL DEFAULT 0
) PARTITION BY RANGE (completed) (
    PARTITION p0 VALUES LESS THAN (0),
    PARTITION p1 VALUES LESS THAN (1)
);

2)不时重组分区(例如使用PHP):

<?php
    $query = 
        "ALTER TABLE s_time REORGANIZE PARTITION p0, p1 INTO (
            PARTITION p0 VALUES LESS THAN ($today),
            PARTITION p1 VALUES LESS THAN ($tomorrow)
        )";

请参阅此处的概念证明

于 2012-06-25T20:00:55.230 回答