Вот предложение по использованию локальной переменной вместо повторения вашего подзапроса три раза. Вы сказали, что это ваша забота.
CREATE TRIGGER `update_request_missions_after_insert` BEFORE INSERT ON `request_missions`
FOR EACH ROW
BEGIN
DECLARE next_id INT;
SELECT COALESCE(MAX(id),0) + 1 INTO next_id FROM request_missions;
IF next_id BETWEEN 1 AND 9 THEN
SET NEW.rm_number = CONCAT(DATE_FORMAT(CURDATE(),'%y'), '-', '00000', next_id);
END IF;
END
Предупреждение: это страдает от состояния гонки. Например, если два сеанса вставляются в таблицу одновременно, они могут оба читать одно и то же next_id
.
Также, как @ P.Salmon прокомментировал выше, результаты не определены, если next_id
> 9. Я не уверен, что вы пытаетесь сделать.
Возможно, вы захотите разрешить более длинные числа и дополнить их фиксированной длиной нулями:
LPAD(next_id, 6, '0')
См. Руководство по функции LPAD () . [ 1123]
Я использовал COALESCE(MAX(id),0)
, чтобы убедиться, что по крайней мере одно возвращаемое значение, отличное от NULL, в случае, если таблица содержит ноль строк.
Это также касается:
DATE_FORMAT(CURDATE(),'%y')
Год из двух цифр перенесется на 00
через 81 год. Именно так и была создана проблема Y2K! Я знаю, что к тому времени вы не будете работать над кодом, поэтому вам может быть все равно. Но вы всегда должны кодировать так, как будто человек, который в конечном итоге поддерживает ваш код, является жестоким психопатом, который знает, где вы живете.
Ваш новый код опубликован в другом ответе:
Это лучшее решение для обработки чисел next_id до 999 999.
CREATE TRIGGER `update_request_missions_after_insert` BEFORE INSERT ON `request_missions`
FOR EACH ROW
BEGIN
DECLARE next_id INT;
SELECT COALESCE(MAX(id),0) + 1 INTO next_id FROM request_missions;
IF next_id < 1000000 THEN
SET NEW.rm_number = CONCAT(DATE_FORMAT(CURDATE(),'%y'), '-', LPAD(next_id, 6, '0'));
ELSE
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'RM Number has reached capacity'
END IF;
END
Проблема состояния гонки отличается, и пока вы не используете MAX(id)
, чтобы найти последний идентификатор, решения не существует. Проблема в том, что у вас может быть несколько клиентов, одновременно вставляющих в таблицу. Каждый сеанс клиента будет читать одно и то же значение для MAX(id)
и использовать его.
Вы должны прочитать о Расовых условиях .
Что вам действительно нужно, так это какой-то способ использования значения AUTO_INCREMENT
, которое генерирует новые уникальные значения в поточно-ориентированном виде, и копирует значение в ваш rm_number
.
К сожалению, нет способа сделать это в триггере. Во время триггера BEFORE INSERT новое значение AUTO_INCREMENT еще не генерируется. Во время триггера AFTER INSERT вы не можете изменить NEW.rm_number
, потому что вставка уже сделана. В прошлом я писал об этом:
Причина код, кажется, избыточен, состоит в том, потому что программисту новичка это, кажется, определяет то же самое дважды. Но это не то, что делает код. Это определяет две отдельных вещи, которые просто, оказывается, имеют тот же тип. Это определяет следующее:
List<int>
. List<int>
.Рассмотрите следующее:
Person[] coworkers = new Employee[20];
Здесь недублирование более ясно, потому что переменная и выделенный объект имеют два различных типа (ситуация, которая законна, если тип объекта происходит из или реализует тип переменной).
Поскольку мы увлекаются компиляторами и ошибками компилятора.
Я вижу еще одну проблему с использованием var для лени как этот
var names = new List<string>();
При использовании var переменная, названная "именами", вводится как List<string>,
но Вы в конечном счете только использовали бы один из интерфейсов, наследованных List<T>.
IList<string> = new List<string>();
ICollection<string> = new List<string>();
IEnumerable<string> = new List<string>();
Можно ли автоматически использовать все этого, но можно рассмотреть то, что соединяет интерфейсом с Вами, хотел использовать в то время, когда Вы написали код?
Ключевое слово var не улучшает удобочитаемость в этом примере.
Ваш конкретный пример является действительно немного подробным, но большинством способов C# довольно минимизирован.
Я очень предпочел бы этот (C#)
int i;
к этому (VB.NET)
Dim i as Integer
Теперь, конкретный пример, который Вы выбрали, является чем-то о.NET в целом, которая находится немного на длинной стороне, но я не думаю, что это - отказ C#. Возможно, вопрос должен быть перефразирован, "Почему код.NET таким образом подробный?"
Используйте var, если очевидно, что тип читателю.
//Use var here
var names = new List<string>();
//but not here
List<string> names = GetNames();
От microsofts C# программирующий руководство
Ключевое слово var может также быть полезным, когда определенный тип переменной утомителен для ввода на клавиатуре, или очевиден, или не добавляет к удобочитаемости кода
C# определенно становится менее подробным после добавления функциональной поддержки.
Это только "избыточно" при сравнении его с динамически типизированными языками. Это полезно для полиморфизма и ошибок открытия во время компиляции. Кроме того, это делает код auto-complete/intellisense легче для Вашего IDE (при использовании одного).
Исторический артефакт статического контроля типов / синтаксис C; сравните пример Ruby:
distances = []
Улучшения компилятора для C# 3.0 (который соответствует.Net 3.5) устраняют часть этого вида вещи. Таким образом, Ваш код может теперь быть написан как:
var distances = new List<int>();
Обновленный компилятор намного лучше в выяснении типов на основе дополнительной информации в операторе. Это означает, что существует меньше экземпляров, где необходимо указать тип или для присвоения, или как часть Дженерика.
Однако существуют все еще некоторые области, которые могли быть улучшены. Частью этого является API, и некоторые происходят просто из-за ограничений строгого контроля типов.
вместо того, чтобы думать о нем как избыточном, думайте о той конструкции как о функции, чтобы позволить Вам сохранять строку.
вместо наличия
Расстояния списка; расстояния = новый Список ();
c# позволяет Вам поместить их на одну строку.
Одна строка говорит, что "Я буду использовать переменную, названную расстояниями, и это будет иметь список типов". Другая строка говорит, "Выделяют новый Список и вызывают конструктора без параметров".
Это слишком избыточно? Возможно. при выполнении его этот путь дает Вам некоторые вещи, хотя
1. Выделяет объявление переменной от объектного выделения. Разрешение:
IEnumerable<int> distances = new List<int>();
// or more likely...
IEnumerable<int> distances = GetList();
2. Это позволяет, чтобы более сильный статический тип проверил компилятор - предоставление ошибок компилятора, когда Ваши объявления не соответствуют присвоениям, а не ошибкам периода выполнения.
Оба из них требуются для записи программного обеспечения? Нет. Существует много языков, которые не делают этого и/или расходятся во многих других точках.
"Доктор! причиняет боль, когда я делаю это!" - "Больше не делают этого"
Если Вы находите, что не нуждаетесь или хотите вещи, которые c# дает Вам, попробуйте другие языки. Даже если Вы не используете их, зная, что другие могут дать Вам огромное повышение того, как Вы приближаетесь к проблемам. Если Вы действительно используете один, большой!
Так или иначе можно найти, что достаточно перспективы позволяет себе говорить, что "Мне не нужна строгая статическая проверка типа, осуществленная c# компилятором. Я буду использовать Python", вместо того, чтобы гореть c# как слишком избыточный.
Вы могли всегда говорить:
var distances = new List<int>();
Поскольку другие сказали: var
удаляет дублирование, но оно имеет потенциальные отрицательные последствия обслуживания. Я сказал бы, что это также имеет потенциальные положительные последствия обслуживания.
К счастью, Eric Lippert пишет об этом намного более красноречиво, чем я: http://csharpindepth.com/ViewNote.aspx?NoteID=63 http://csharpindepth.com/ViewNote.aspx?NoteID=61
Поскольку объявление типа не обязательно имеет какое-либо отношение к инициализации его.
Я могу объявить
List<int> foo;
и оставьте это быть инициализированными позже. Где дублирование затем? Возможно, это получает значение от другой функции как BuildList ().
Поскольку другие упомянули, что новое ключевое слово var позволяет Вам обойти это, но необходимо инициализировать переменную в объявлении так, чтобы компилятор мог сказать то, что вводит его.
Что такое redudant об этом?
List<int> listOfInts = new List<int>():
Переведенный в английский язык: (РЕДАКТИРОВАНИЕ, очищенное немного для разъяснения)
Едва ли подробный, когда Вы думаете о том, что это делает.
Конечно, существует альтернатива:
var listOfInts = new List<int>();
Здесь мы используем вывод типа C#, потому что Вы присваиваете ему сразу, C# может выяснить то, что вводит Вас, хотят создать объектом, просто созданным в "куче".
Чтобы полностью понять, как CLR обрабатывает типы, я рекомендую читать CLR Через C#.
redunancy не был предназначен, по сути, но был побочным эффектом того, что все переменные и поля должны были иметь описание типа. Когда Вы принимаете во внимание, что все объектные инстанцирования также упоминают имя типа в новом выражении, Вы получаете избыточно выглядящие операторы.
Теперь с выводом типа с помощью ключевого слова var, то дублирование может быть устранено. Компилятор достаточно умен для понимания этого. Следующий C++ также имеет автоматическое ключевое слово, которое делает то же самое.
Главная причина они представили var, тем не менее, была для анонимных типов, которые не имеют никакого имени:
var x = new {Foo = Bar, Number = 1};
Во многих ответах на этот вопрос авторы думают как составители или апологеты. Важное правило хорошего программирования: Не повторяйся!
Предотвращение этого ненужного повторения является явной целью дизайна Go, например:
Заикание (
foo.Foo * myFoo = new (foo.Foo)
) уменьшено путем получения простого типа с помощью конструкции: =
declare-and-initialize.