#mysql #sql #sql-server #oracle #postgresql
#mysql #sql #sql-сервере #Oracle #postgresql
Вопрос:
Я пытаюсь создать метод для класса, который будет автоматически вставлять запись в таблицу. Проблема в том, что мне нужно заставить код работать для mysql, mssql, postgresql, oracle и sqlite.
Единственные решения, которые я могу придумать, это:
-
Создайте мои собственные значения первичного ключа, но это кажется очень рискованным, поскольку может быть сложно найти отказоустойчивое решение для генерации значений первичного ключа.
-
Создайте код, который переключит используемый метод на основе используемого драйвера rdbms, но это кажется неаккуратным, и я хотел бы использовать способ, соответствующий стандартам SQL, если это возможно.
Как я могу создать эту INSERT
инструкцию для работы во всех этих СУБД, если все они используют разные методы для автоматического увеличения поля первичного ключа?
Комментарии:
1. На каком языке вы пишете свое приложение?
Ответ №1:
Используйте специализированный код для каждой СУБД.
Соответствие стандартам — это хорошо, но слишком много вещей, которые работают не во всех базах данных. Начиная с простых вещей, таких как цитирование полей и значений, таких вещей, как ограничение результирующего набора заданным количеством строк и, возможно, сотнями других случаев.
Ответ №2:
Чистый универсальный
Единственный гарантированный переносимый способ сделать это во всех мыслимых базах данных и иметь только одну реализацию; это заставить приложение генерировать ключи как UUID-ы и вставлять их как обычные поля. Положительным моментом является то, что вам не нужно полагаться на реализацию, специфичную для какого-либо языка или библиотеки, для извлечения ключа, он у вас уже есть.
Альтернативой UUID, если вы занимаетесь хранением данных и не обновляете строки после их INSERT
редактирования, является криптографический хэш содержимого строки. Пусть ваше приложение объединит содержимое всех полей в одну строку и извлекет хэш SHA1 этой строки. Этот ключ для всех практических целей гарантированно уникален для этого содержимого. Также упрощает репликацию и поиск дублирующихся записей.
Последовательные номера — это не конечные значения всех первичных ключей.
Ключи UUID легче переносить, и в 2011 году они так же быстры при индексации, и пространство не должно быть проблемой, если у вас нет Facebook или Google size данных, и тогда у вас есть деньги, чтобы купить дисковое пространство, которое вам нужно, они также используют что-то другое, чем long
число.
Другим преимуществом является то, что вы также можете выполнять репликацию намного проще, потому что вам не нужно беспокоиться о том, что каждая база данных, которую вы пытаетесь синхронизировать, имеет дубликат ключа.
Общий SQL
Вы можете просто не указывать поле в INSERT
инструкции, и база данных позаботится о создании значения для вас.
PHP сделает извлечение автоматически сгенерированных ключей проблематичным, чтобы сделать это общим способом. Все, что я могу найти по этой теме, очень специализировано для любой используемой базы данных, похоже, не существует универсального API, эквивалентного JDBC для PHP.
Если вы использовали Java
Если вы используете логическое выполнение (String sql, int autoGeneratedKeys) в классе Statement. Вы можете указать ему, в каком индексе поля находится автоматически сгенерированный ключ, и он вернет его, используя ResultSet getGeneratedKeys().
Специфичных для Oracle
Если вы установите DEFAULT
значение в желаемом поле автоинкремента в своем DDL
для вызова функции, которая выбирает следующее значение из sequence
, вы можете реализовать желаемое поведение автоинкремента и в Oracle.
ПРИМЕЧАНИЕ
UUID иногда называют GUID, и они технически отличаются, но концептуально являются одним и тем же.
Комментарии:
1. Для полноты картины:
getGeneratedKeys()
также работает с Oracle, если значение генерируется в триггере2. Что касается подхода к криптографическому хэшу: Как бы вы обрабатывали обновления? Либо вам нужно обновить свой первичный ключ (полный запрет IMO), либо у вас возникнут несоответствия между вашим хэшем и вашими фактическими данными и, возможно, даже возникнут проблемы с ложными дубликатами первичного ключа.
3. @Фрэнк, они ничего не говорят о
UPDATE
заявлении, простоINSERT
. И для некоторых случаев, таких как хранилище данных, подход хэширования SHA1 идеален.4. Мне бы не хотелось использовать 128-битные UUID в качестве первичного ключа, если было бы достаточно 32 бит. Это обычная трата ресурсов , ИМО
5. «пустая трата ресурсов» — это субъективные и специфические требования, которых у нас нет. Я выбрал самое общее решение. Очевидно, что могут быть применимы ключи меньшего размера в битах, это решает операционная система. Но концепция UUID / GUID одинакова независимо от длины бита, исключая проблемы с коллизией. Меньшие длины битов будут сталкиваться быстрее.
Ответ №3:
Нет ничего проблематичного в простой вставке записей с полем автоматического увеличения: обычно вы просто опускаете это поле во вставке, база данных генерирует его как вычисленное значение по умолчанию (вот почему оно называется «auto-increment»).
Проблема переносимости возникает только тогда, когда вам нужно получить значение этого сгенерированного поля (которое часто является суррогатным первичным ключом). Нет стандартного способа SQL для получения этого.
ОТРЕДАКТИРОВАНО: oook. Согласно комментариям, касающимся моего первого абзаца (второй абзац остается в силе) :
Это правда, что не каждая база данных поддерживает прямые готовые поля автоинкремента «ПО УМОЛЧАНИЮ» (mea culpa). Однако, ЕСЛИ вы предусмотрели дизайн схемы, который поддерживает этот вид вставки (straigtforward в Postgresql, Mysql, MSSQL и — я думаю — SQLite; не прямой, но возможный — с триггерами — в Oracle), ТОГДА вы можете закодировать свои вставки SQL простым и переносимым способом. В другом месте вы не можете: в этом случае вы должны написать ВСТАВКИ, специфичные для СУБД.
Комментарии:
1. -1 поскольку не все базы данных поддерживают поля автоматического увеличения (например, Oracle)
2. Oracle поддерживает автоинкремент, вам просто нужно написать функцию для вызова
sequence
и установить эту функцию в качествеDEFAULT
значения в поле ‘NOT NULL`.3. Да, но это не переносимо, как того требует OP. Вы также могли бы определить триггер before insert, который извлекает sequence.nextval и устанавливает PK, но, ИМХО, это не относится к делу.
4.
DDL
не переносим, никогда не был, наличие specificDDL
не исключается вопросом posters. Переносимая часть, о которой они заботятся, — это код приложения, и его определенно можно сделать переносимым.5. @Jarrod подчеркивает важную часть. Хорошего способа создать такую таблицу (DDL) не существует, но JDBC отвлекает вас от этого. (Тем более что-то вроде спящего режима.) Таким образом, на стороне клиента вы можете просто выполнить ВСТАВКУ без установки столбца ID и получить новый идентификатор с помощью getGeneratedKeys.
Ответ №4:
Почему вы не используете ORM? В PHP их множество: Doctrine, Redbean и многие другие
Целью ORM является абстрагирование уровня базы данных. Похоже, это то, что вам нужно. Ваш метод будет работать с объектами в вашем коде, а ORM имеет пользовательский код, необходимый для сохранения этих объектов в вашей базе данных
Комментарии:
1. и все же моя задача — создать пользовательский orm
2. ах, хорошо. Это не было ясно в вопросе. Тогда я бы подумал, что примеры, представленные во многих существующих ORM, были бы хорошим ориентиром.