Я пытаюсь сделать код автоинкремента с датой, и он сбросит код на днях.
У меня есть эта миграция.
public function up()
{
Schema::create('records', function (Blueprint $table) {
$table->id();
//other codes here...
});
}
Затем я добавляю столбец, который автоматически увеличивает 5 цифр, используя
ALTER TABLE id ADD my_id AS RIGHT('00000' + CAST(id AS VARCHAR(5)) , 5) PERSISTED
У меня есть этот запрос на моем контроллере
public function get_records(Request $request){
$records = DB::table('records')->select(
'records.my_id',
//other codes here...
)
->get();
$recordlist = [];
$currentMonth = Carbon::now()->format('mm');
$currentDay = Carbon::now()->format('dd');
foreach($records as $data):
$data->CODE = 'Z' . $currentMonth . $currentDay . '-' .$data->my_id;
$recordlist[] = $data;
endforeach;
return recordlist;
// OUTPUT --> CODE: 'Z0331-0001'
}
Я хотел бы, чтобы мой вывод был похож на ..
today is 03/31
CODE:
Z0331-00001
Z0331-00002
Z0331-00003
.....
Z0331-00010
Z0331-00011
Z0331-00012
.....
Z0331-00100
Z0331-00101
Z0331-00102
//The other day(04/01)..
CODE:
Z0401-00001
Z0401-00002
Z0401-00003
.....and so on
Я только что придумал эту транзакцию.
Я просто добавляю таблицу,
ALTER TABLE records DROP COLUMN my_id
ALTER TABLE records ADD my_id VARCHAR(5) NOT NULL
Тогда мой запрос..
$createdrecord = //last created record ex(CODE: 'Z0330-00265' created_at: '03/30(yesterday)' )
$today = Carbon::now();
foreach($records as $data){
if ($today != $createdrecord){
$data->my_id = '00000';
}else{
$data->my_id += 1;
}
}
Я думаю, что это будет хорошо, но мой код не работает..
Спасибо за помощь.
Вы не указали, какую БД вы используете. Если это mysql, я готов поделиться скелетом кода, который я реализовал. Важным моментом в последовательности является то, что вы блокируете строку. поэтому у вас есть параллелизм, но вы не подвержены гонке, когда одна и та же последовательность # может быть выделена 2x или более.
Я использую SqlDbx. Вот мой пример таблицы, которую я использовал с автоинкрементом (некоторые данные скрыты)
Это инструмент администратора, а не rdbms! Какую реляционную базу данных вы используете? Это MySQL? Постгрескл? Оракул? SQL-сервер......
Извините, это MySql.






Вам нужна дополнительная таблица, в которой вы храните счетчики. Он должен иметь 2 столбца:
Каждый раз, когда вы создаете record, вы должны проверять, есть ли что-то в таблице счетчиков на текущую дату.
Если он пустой - используйте ID = 1 и сохраните его в таблице счетчиков.
Если он не пуст, используйте счетчик + 1 и увеличивайте счетчик.
Проблема в том, что данные еще не добавлены. Итак, код начинается с 00000, а мой счетчик по-прежнему равен NULL.
Кажется, вы не понимаете здесь идею. Эта таблица, о которой он говорит, является таблицей последовательности. Счетчик используется для отслеживания последнего выделенного идентификатора. Каждый раз, когда вам нужен новый идентификатор, вы выбираете значение из этой таблицы и увеличиваете его на 1. Вы используете полученное значение для обновления my_id вашей таблицы. Как я уже упоминал, важно, чтобы вы заблокировали строку последовательности, чтобы она была невосприимчива к условиям гонки. Как он заявил, если строки еще не существует, вы создаете ее в своем коде, устанавливаете для нее значение 1 и используете 1 в качестве своего идентификатора. Ключом этой таблицы вы сделаете столбец даты.
Спасибо за объяснение. Кажется, я понял эту идею. Извините, я не совсем хорошо понимаю английский.
ОБНОВЛЯТЬ В процессе попытки ответить на этот вопрос мы установили, что у Автора MS Sql Server 2008, а не MySQL, как было заявлено изначально.
Поскольку в MS Sql Server есть объекты Sequence, эта идея может быть реализована с использованием схемы именования последовательностей, где последовательности именуются по дате.
select count(*) as count_of from sys.sequences where name = "SEQ_2023_04_04"
create sequence SEQ_2023_04_04 START WITH 1 AS INT
SELECT NEXT VALUE FOR SEQ_2023_04_04
Примечание:
Я оставляю детали PHP этих запросов вам. Например, чтобы узнать, какое имя последовательности для текущего дня в вашем коде, вы можете использовать
$seq = 'SEQ_' . date('Y_m_d');
Я опустил Schema здесь, так как я не знаю, что вы на самом деле делаете, но имена схем, возможно, придется ссылаться в этих запросах по мере необходимости. Вы должны убедиться, что понимаете понятия базы данных и схемы сервера MS Sql.
Это реализация MySQL идеи, предложенной NoOoZ24, поэтому не забудьте дать ему голос/кредит.
Сначала вам нужна таблица последовательности:
CREATE table sequence (id DATE PRIMARY KEY, counter int unsigned DEFAULT 1);
Вот хранимая процедура MySQL, которая будет действовать как ваш генератор последовательности:
DELIMITER //
CREATE PROCEDURE `getSequenceCounter`(
IN p_date DATE
)
BEGIN
DECLARE v_id DATE;
DECLARE v_counter INT DEFAULT 0;
DECLARE v_errorMsg VARCHAR(256);
DECLARE EXIT HANDLER FOR SQLEXCEPTION, SQLWARNING
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
IF NOT EXISTS(
SELECT *
FROM sequence
WHERE id = p_date
) THEN
INSERT INTO sequence (id) values (CURDATE());
END IF;
SELECT id, counter
INTO v_id, v_counter
FROM sequence
WHERE id = p_date
FOR UPDATE;
UPDATE sequence SET counter = counter + 1
WHERE id = v_id;
COMMIT;
SELECT v_counter as counter;
END;
//
DELIMITER ;
Из командной строки вы можете запустить этот sproc, используя CALL:
call getSequenceCounter(CURDATE());
Глядя на код, вы должны заметить, что он создаст строку последовательности для даты, если она не существует, и вернет вам начальное значение, которое будет равно 1.
call getSequenceCounter(CURDATE());
+---------+
| counter |
+---------+
| 1 |
+---------+
Запустите его снова, и вы увидите следующее значение и так далее.
В последний раз я смотрел, что нет способа вызвать хранимую процедуру mysql из Eloquent, поэтому вам придется использовать DB::select или построить запрос. Обе эти техники показаны в ответах на этот вопрос.
Спасибо. Я все еще пытаюсь понять это, используя указанную вами процедуру sql, и пытаюсь выполнить ее в своей транзакции БД. Но у меня возникли некоторые ошибки при создании этого table sequence , поэтому я не могу начать с таблицы с образцом последовательности таблиц.
Вы уверены, что ваша база данных MySQL, а не SQL Server? Из окна SQL вашего инструмента, что вы получаете, когда запускаете SELECT @@version
Мне очень жаль, но я даю вам версию sql, которую я использую в phpMyadmin. Это Microsoft SQL Server 2008 R2 (RTM). Спасибо и извините еще раз.
Эта версия SQL Server прекращает свое существование везде, кроме Azure, и даже с Azure она прекращает свое существование в июле этого года. Вы должны посмотреть на обновление как можно скорее.
Это означает, что я не могу сделать/любой возможный способ добиться результата в моей проблеме, используя мой текущий sql?
Я показал пошаговый метод использования объекта последовательности сервера sql. Это еще проще и не требует имитации последовательности, так как sql server имеет последовательности как объекты. Смотрите обновления, которые я сделал в верхней части моего ответа.
Вы хотите написать собственный генератор последовательности, в идеале реализованный в виде хранимой процедуры. См. ответ NoOorZ24. Вашей таблице нужны my_id и my_id_date. Когда вам понадобится новый идентификатор, генератор последовательности предоставит вам его автоматически. Единственным сложным кодом будет добавление строки последовательности для дня, когда ее еще нет.