SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 18.04.2013 19:02:37

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2420

Уникальность значения с радиусом действия

Приветствую, коллеги!

Суть моей проблемы: есть таблица t в которой есть поле dt (datetime). Хотелось бы наложить такое ограничение (представим, что есть check constraint'ы smile, ну или можно же в mariadb функциональный индекс сделать ), чтобы нельзя было добавить (изменить) запись, в которой dt будет ближе чем, допустим, на 40 дней к любой другой записи.
То есть если у нас есть одна запись в таблице

id          dt
1          2013-07-01

то  можно добавить запись с dt='2013-05-05', но нельзя добавить с dt='2013-05-25'.
также  можно добавить запись с dt='2013-08-25', но нельзя добавить с dt='2013-08-05'.

Если бы нужно было сделать уникальность в рамках месяца, года или дня - то уникальным функциональным индексом вопрос решился бы. А вот если уникальность в смысле отклонения определенного количества дней - не могу придумать как-то (. Решение в виде триггера, который будет пробегать по всей таблице и сравнивать разницу по модулю между каждым dt с 40 днями остаётся, но как-то это из пушки по воробьям, может проще можно как-то выкрутиться?

Поделитесь соображениями плиз.


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#2 20.04.2013 18:40:09

evgeny
Гуру
Зарегистрирован: 04.05.2009
Сообщений: 335

Re: Уникальность значения с радиусом действия

Привет.
Если я все правельно понял, то можно так:

Создаем новую колонку time_step
Создаем составной уникальный индекс на (id,time_step)

Вычисляем time_step по формуле:

time_step = (current timestamp /timestamp one day) / range_limit)


timestamp one day = 86416
range_limit = 40 days

INSERT INTO my_table (id,dt,time_step) VALUES(1,'2013-04-20',ceil((UNIX_TIMESTAMP('2013-04-20 00:00:00')/86416)/40));
 


Пример:

select ceil((UNIX_TIMESTAMP('2013-03-01 00:00:00')/86416)/40); -- 395
select ceil((UNIX_TIMESTAMP('2013-04-10 00:00:00')/86416)/40); -- 396
select ceil((UNIX_TIMESTAMP('2013-04-20 00:00:00')/86416)/40); -- 396              
select ceil((UNIX_TIMESTAMP('2013-05-01 00:00:00')/86416)/40); -- 396
select ceil((UNIX_TIMESTAMP('2013-05-30 00:00:00')/86416)/40); -- 397
 

Отредактированно evgeny (20.04.2013 21:50:59)

Неактивен

 

#3 21.04.2013 20:23:05

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2420

Re: Уникальность значения с радиусом действия

Привет!

Спасибо за наводку. Только проблема в том, что предложенный тобой метод - он не обеспечивает уникальности в смысле "радиуса" числа - между первым и тридцатым мая разница меньше чем 40 дней, а предложенные запросы дают разные числа - 396 и 397.

То есть если сделать уникальный индекс на ceil((UNIX_TIMESTAMP(dt)/86416)/40), то СУБД не выругается на попытку вставить тридцатое мая 2013 при наличии уже имеющейся записи с 1-м мая 2013. Хотя должна - при моей постановке задачи.

Или я чего-то не учел?


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#4 21.04.2013 20:46:50

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Уникальность значения с радиусом действия

Задача не похожа на формализуемый constraint. Видимо только триггером.

Неактивен

 

#5 21.04.2013 20:51:49

evgeny
Гуру
Зарегистрирован: 04.05.2009
Сообщений: 335

Re: Уникальность значения с радиусом действия

deadka написал:

Привет!

Спасибо за наводку. Только проблема в том, что предложенный тобой метод - он не обеспечивает уникальности в смысле "радиуса" числа - между первым и тридцатым мая разница меньше чем 40 дней, а предложенные запросы дают разные числа - 396 и 397.

То есть если сделать уникальный индекс на ceil((UNIX_TIMESTAMP(dt)/86416)/40), то СУБД не выругается на попытку вставить тридцатое мая 2013 при наличии уже имеющейся записи с 1-м мая 2013. Хотя должна - при моей постановке задачи.

Или я чего-то не учел?

Что то я действительно не то намутил :-)

Неактивен

 

#6 21.04.2013 21:11:51

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2420

Re: Уникальность значения с радиусом действия

evgeny написал:

Что то я действительно не то намутил :-)

Да не, просто предложенное тобой решение немножко другую задачу решает smile.

rgbeast написал:

Задача не похожа на формализуемый constraint. Видимо только триггером.

Похоже на то sad.

Спасибо!


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#7 22.04.2013 01:06:57

evgeny
Гуру
Зарегистрирован: 04.05.2009
Сообщений: 335

Re: Уникальность значения с радиусом действия

Можно тригером так


DELIMITER $$

DROP TRIGGER /*!50032 IF EXISTS */ `mytrig`$$

CREATE
    TRIGGER `mytrig` BEFORE INSERT ON `my_table`
    FOR EACH ROW BEGIN

    set @mindate:=null;
    set @maxdate:=null;
    select dt into @mindate from my_table where mdate>=NEW.dt order by dt limit 1;
    select dt into @maxdate from my_table where mdate<=NEW.dt order by dt desc limit 1;
   
     if((@maxdate and @maxdate>(NEW.dt-interval 40 day))
    or @mindate and (@mindate<(NEW.dt+interval 40 day))) then
    SET NEW = 'Date in forbidden range';
    end if;

    END;
$$

DELIMITER ;
 

Неактивен

 

#8 22.04.2013 01:22:20

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2420

Re: Уникальность значения с радиусом действия

Ага, что-то такое, спасибо ). На самом деле мне для postgresql надо ( как я писал вначале треда - представим, что у нас есть check constraint'ы, это жжж было неспроста ), но, конечно, было интересно, как задача решается "в общем" виде. В-общем виде, видимо, триггером как раз. В слоне, к слову, нашлась такая приятная штука как интервальный тип (для типа даты в том числе) и сопутствующие плюшки, видимо этим и воспользуюсь.

Никто не в курсе, к слову, может быть в MariaDB тоже планируются интервальные типы? В текущей версии не видел.


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson