Формирование номеров записей (актов) с указанием года в номере.

Руслан

Новичок
Формирование номеров записей (актов) с указанием года в номере.

Здравствуйте, коллеги.
Имеется вопрос.
В системе формируются акты. id записи акта является его номером. Актов формируется много. К концу года встал вопрос о том, что бы разбивать номера актов погодично. Т.е. в 2009 г. все номера актов имеют вид 9-0001, 9-0002 и т.д., в 2010 г. соответственно 10-0001, 10-0002 и т.д. Т.е с каждого нового года автоинкремент части после "-" сбрасывается на 1.
Осложняется задача ещё тем, что система уже в работе и значительно переписывать структуру накладно.
Вопрос несколько даже теоретический - как бы вы реализовали такой переход на погодичные номера? (желательно с завязкой на id, хотя что-то мне подсказывает, что от id приётся отойти).
Жду советов. Спасибо.
 

Вурдалак

Продвинутый новичок
Естественно, необходимо структуру поменять: вместо одной колонки (id) добавить две (id, year). :)

-~{}~ 14.12.09 17:59:

Подразумевается, что новая колонка id будет INT с AUTO_INCREMENT
 

Руслан

Новичок
Вурдалак
то есть получим следующее.
есть поле id - как и сейчас с автоинкрементом.. Есть поле год.
Но как решать момент с тем, что бы автоинкремент сбрасывался на 1 в начале каждого года. Иначе будет:
9-2134; 10-2135.
А должно быть: 9-2134; 10-0001.
Может быть следует сделать иначе. Оставить id как есть. Добавить поле предположим numb, который будет автоинкрементиться и автоинкремент которого будет сбрасываться в конце года. И поле year c годом (теоретически можно использовать уже имеющееся поле aktdate (тип даных date).
Так же вроде как можно использовать одно поле в текстовом формате и формировать номер на лету - но помоему это не очень хорошо..
Что думаете? Создавать numb и year и сбрасывать автоинкремент numb'a в начале года?
 

Вурдалак

Продвинутый новичок
Автор оригинала: Руслан
Но как решать момент с тем, что бы автоинкремент сбрасывался на 1 в начале каждого года. Иначе будет:
9-2134; 10-2135.
А должно быть: 9-2134; 10-0001.
А зачем сбрасывать-то?

Автор оригинала: Руслан
Может быть следует сделать иначе. Оставить id как есть. Добавить поле предположим numb, который будет автоинкрементиться и автоинкремент которого будет сбрасываться в конце года. И поле year c годом (теоретически можно использовать уже имеющееся поле aktdate (тип даных date).
Так же вроде как можно использовать одно поле в текстовом формате и формировать номер на лету - но помоему это не очень хорошо..
Что думаете? Создавать numb и year и сбрасывать автоинкремент numb'a в начале года?
Лишние проблемы себе создаёшь подобными решениями. Придётся AUTO_INCREMENT эмулировать, сбрасывать значение, составной ключ делать — зачем всё это?
 

zerkms

TDD infected
Команда форума
Составной первичный ключ.
year + id
id автоинкрементный
 

Руслан

Новичок
Вурдалак
Сбрасывать затем, чтобы не было актов с номерами 10-25356..
Неудобно. В год до 3000 актов формируется. Уже сейчас люди, которые работают с системой в тысячах путаются. Поэтому и встал такой вопрос, иначе его бы просто не стояло.

zerkms
А обнуление инкремента ежегодное как в этом случае реализуется?


Сейчас почитал по составным ключам информацию. Мне кажется в моём случае не стоит оперировать составным ключём. Вот эта форма 10-0001 нужна только для пользователя, ну уровне скрипта вся обработка будет по id, который может быть каким угодно, и ссылки в таблицах так же будут по id.
 

O1&g

Новичок
Я вам идею дам от MSSQL, так как долго надо проверять и вы конвертнете на MуSQL.

3 степа:

сосдаем темп таблицу:
PHP:
DECLARE @MyTableVar table(
    newID int IDENTITY(1,1) NOT NULL,
    AktDate datetime, // ваше поле
// другие поля которые вам нужны
);
далее, делаем селект из основной таблицы в темп:
PHP:
Select 
AktDate datetime, // ваше поле
// другие поля которые вам нужны
from OriginalТable
INTO @MyTableVar;
далее, делаем селект из темп таблицы:
PHP:
SELECT 
	Cast(DATEPART(year,[AktDate]) as varchar(4)) + '-' + CAST([newID] as varchar(3000)) as AktID,
// другие поля которые вам нужны
FROM @MyTableVar;
Как-то так
 

zerkms

TDD infected
Команда форума
Руслан
А обнуление инкремента ежегодное как в этом случае реализуется?
а не нужно его сбрасывать. для каждого года оно будет само по себе начинаться с 1.

ps: не слушай O1&g, он говорит фигню.
 

Руслан

Новичок
O1&g
ОК.
Но в этом случае получается, что временная таблица будет присваивать id (инкрементом) всем записям, которые будут запрошены.
Т.е. если я запрошу акты за 2 месяца с 01.12.2009г. по 01.02.2010г. , то первый выведенный акт будет 09-0001 (что неверно), а акт за 01.01.2010 будет не 10-0001.


Или я неверно понял суть использования временной таблицы?


Мне вот на фоне вашей идеи пришла в голову мысль, о том что под каждый год можно создавать таблицу. Тогда инкремент будет верным для каждого года, а формировать номер акта для пользователя можно при запросе из id и даты. Но в этом случае надо автоматизировать создание таблиц кждый НГ и помимо этого в ссылках на акты добавляется имя таблицы. При поиске актов по диапазону дат начнутся прыжки по таблицам. Вобщем какая-то тяжёлая структура получается.

Наверное как я и писал придётся создать в таблице актов (в одной таблице актов) поле numb и как-то инкрементить его вручную с учётом перехода на НГ. А при выводе формировать номер акта из этого numb и aktdate.


Ф_а_н_а_та бы почитать, он спец по всяким каверзным ситуёвинам (хотя он скажет, что это банальная задача и возможно будет прав)

-~{}~ 15.12.09 06:59:

zerkms
Из за изменения префикса? Я правильно понимаю? Возможно ты прав и возможно, это стандартное и верное решение.
 

zerkms

TDD infected
Команда форума
Из за изменения префикса? Я правильно понимаю? Возможно ты прав и возможно, это стандартное и верное решение.
проверить это займёт 30 секунд (на создание таблицы с 2 столбцами и 1 индексом).
не могу понять, почему вместо этой проверки ты предпочёл писать огромный пост, обсуждающий мало того, что бредовую мысль, так ещё и продолжающий её (мысль) ещё более бредово
Мне вот на фоне вашей идеи пришла в голову мысль, о том что под каждый год можно создавать таблицу.
обожемой, чего мелочиться - давайте создавать по таблице на каждую запись. а ещё лучше - каждую запись хранить вообще в отдельной ферме серверов. :)
 

Руслан

Новичок
zerkms
Ну проверить я сейчас не смогу при всём желании, сервера под рукой нет, а удалёно к нему добраться по некоторым причинам не могу.
А когда начал писать пост, то признаюсь, с составными ключами ещё знаком не был. Поэтому видимо и пост носит такой теоретический характер.
По поводу продолжения мысли ещё более бредово соглашусь. Я собствено и сам написал, что
тяжёлая структура получается
хотя хотелось написать "мутная".

Ну как доберусь до места рабочего проверю.
 

zerkms

TDD infected
Команда форума
Код:
mysql> INSERT INTO `test` (`year`) VALUES (2008), (2008), (2008), (2009), (2009), (2008);
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM `test`;
+------+----+
| year | id |
+------+----+
| 2008 |  1 |
| 2008 |  2 |
| 2008 |  3 |
| 2008 |  4 |
| 2009 |  1 |
| 2009 |  2 |
+------+----+
6 rows in set (0.00 sec)
Код:
CREATE TABLE `test` (
  `year` YEAR(4) NOT NULL,
  `id` INTEGER(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`year`, `id`)
)ENGINE=MyISAM
AUTO_INCREMENT=1 ROW_FORMAT=FIXED CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
 

Руслан

Новичок
zerkms
Зерк, спасибо. Действительно помог. Вдогонку вопрос. Вот мы date поставили not null, но если поставить null, то он же вместо null, будет сам подставлять текущий год (что мне и нужно) по типу timestamp'а. Но так как мы его обозначили в составе праймари, он не даёт обозначиться как null. Не знаешь как можно поступить?

И ещё, нельзя ли как то связать id и date, что бы при selecte одного из них (допустим id) вытягивались оба?
 

zerkms

TDD infected
Команда форума
Вот мы date поставили not null, но если поставить null, то он же вместо null, будет сам подставлять текущий год (что мне и нужно) по типу timestamp'а.
с какой стати?

И ещё, нельзя ли как то связать id и date, что бы при selecte одного из них (допустим id) вытягивались оба?
какие оба? у тебя id не уникальный сейчас.
 

Руслан

Новичок
zerkms
Хм. Что-то поставил сейчас prefixdate=10 (остальные все 09), а он мне в id не дал "1", дал следующее по инкременту 2265. Хотя праймари и id и prefixdate. Не знаешь в чём косяк может быть?

Автор оригинала: zerkms
с какой стати?
Ну в манах написано, что
Величины типа YEAR могут быть заданы в различных форматах: -\\-
Как результат выполнения функции, возвращающей величину, приемлемую в контексте типа данных YEAR (такой как NOW()).
Т.е. то же самое, что TIMESTAMP когда его null'ем обзываешь. Он не принимает значение NULL, но выдаёт при этом текущее время.
Для остальных (кроме первого) столбцов типа TIMESTAMP также можно задать установку в значение текущих даты и времени. Для этого необходимо просто установить столбец в NULL или в NOW().
Или в случае с YEAR нужно однозначно инициализировать функцию NOW как для DATE?

какие оба? у тебя id не уникальный сейчас.
Я понимаю. =) Я имею ввиду если предположим я делаю выборку по каким то данным из акта (предположим акты по определённым заводам, не по id), то нельзя ли как то связать id и prefixdate, что бы они отдавались вместе, что бы при разбиении массива они были одной переменной. Или это вызовет какие-то неудобства?
 

Руслан

Новичок
zerkms
Ну про конкатенацию пр селекте я знаю. Я просто чего изголяюсь как уж на скорвороде, всё ж хочется поменьше переписывать. А теперь придётся кучу запросов переписывать. Ну значит придётся.

-~{}~ 16.12.09 07:52:

Зерк, инкремент не сбрасывается на id если меняется prefixdate. Кстати сейчас ищу ищу инфу по поводу того, что он должен сбрасываться, а нигде такой инфы не вижу. Единственое условие - это что группа prefixdate и id должна быть уникальна. Ну так она в любом случае уникальна при инкременте id, какой бы prefixdate не был.

Ты не тестил свою таблицу, код которой ты писал? У тебя получилось?
 

zerkms

TDD infected
Команда форума
Сверху