При разработке баз данных, что предпочтительный путь состоит в том, чтобы сохранить несколько верных / ложные значения?

Как указано в заголовке, при разработке баз данных, что является предпочтительным способом обработать таблицы, которые имеют несколько столбцов, которые просто хранят верный / ложные значения как просто сингл или или значение (например, "Y/N: или "0/1")? Аналогично, есть ли некоторые проблемы, которые могли бы возникнуть между различными базами данных (например, Oracle Server и SQL Server), который мог бы влиять, как столбцы обрабатываются?

13
задан rjzii 12 September 2010 в 12:36
поделиться

10 ответов

MySQL

ПРАВКА: удалена ненужная информация

-121--1620393-

Как вы отметили: typedef имеет плохое имя (это должны быть typealias (D явно добавил typealias (последний раз я смотрел))

Так что единственный способ сделать это - создать два уникальных класса.
Я не собираюсь говорить, что вы не можете написать специализацию static_cast< > делать то, что вы хотите, но я думаю, что (и я еще не задумался об этом) сделать это было бы плохой идеей (даже если это законно)Я думаю, что лучший подход заключается в том, чтобы каждый конструктор класса использовал неподписанные int, которые являются явными (поэтому нет автоматического преобразования).

 struct FID
 {
     explicit FID(unsigned int v): value(v) {}
     operator unsigned int() {return value;}
     unsigned int value;
 };

 class SID {/* Stuff */};

 FID   fid(1U);
 SID   sid(2U);

 doSomthingWithTwoSID(sid,SID(static_cast<unsigned int>(fid));

Явное использование конструктора означает отсутствие автоматического преобразования между типами.
Добавление встроенного оператора cast к неподписанной int означает, что он может использоваться в любом месте, где ожидается int.

-121--2478541-

В SQL Server существует тип данных BIT . Здесь можно хранить 0 или 1, сравнивать значения, но не выполнять MIN или MAX .

В Oracle используется только NUMBER или CHAR (1) .

В MySQL и PostgreSQL любой тип данных неявно преобразуется в BOOLEAN .

Обе системы поддерживают BOOLEAN тип данных, который можно использовать как есть без операторов в предложениях WHERE или ON :

SELECT  *
FROM    mytable
WHERE   col1

, что невозможно в SQL Server и Oracle (там нужно иметь какой-то предикат).

В MySQL BOOLEAN является синонимом TINYINT (1) .

В PostgreSQL тоже (в терминах места хранения), но логически он не неявно конвертируется в любой другой тип.

14
ответ дан 1 December 2019 в 20:42
поделиться

Вместо логических типов данных вы можете рассмотреть другую модель данных для хранения логических значений. , что может быть особенно подходящим в следующих случаях:

  • , когда у вас будет много столбцов «да / нет».
  • , когда вам, вероятно, потребуется добавить больше столбцов «да / нет» в будущем.
  • , когда значения да / нет меняются не очень часто.

Определение полномочий пользователя может быть типичным примером вышеизложенного. Рассмотрим следующие таблицы:

Table "Users":             (user_id, name, surname, country)

Table "Permissions":       (permission_id, permission_text)

Table "Users_Permissions": (user_id, permission_id)

В таблице Permissions вы должны определить все возможные разрешения, которые могут быть применимы к пользователям. Вам нужно будет добавить строку в таблицу Permissions для каждого атрибута да / нет.Как вы могли заметить, это упрощает добавление новых разрешений в будущем без изменения схемы базы данных.

В вышеупомянутой модели вы должны указать значение ИСТИНА, назначив user_id с permission_id в таблице Users_Permissions . В противном случае по умолчанию будет ЛОЖЬ.

Например:

Table "Permissions"

permission_id   text
-----------------------------------
1               "Read Questions"
2               "Answer Questions"
3               "Edit Questions"
4               "Close Questions"


Table "Users_Permissions"

user_id         permission_id
-----------------------------------
1               1
1               2
1               3
2               1
2               3

Преимущества

  • Индексирование : вы можете легко использовать индекс для запроса конкретных фактов.
  • Пробел : соглашение по умолчанию экономит место, когда у вас много ложных значений.
  • Нормализованный : Факты определены в собственных таблицах (в таблицах Permissions и Users_Permissions ). Вы можете легко сохранить дополнительную информацию по каждому факту.

Недостатки

  • Запросы : Простые запросы потребуют JOINs.
  • Значение False : чтобы установить значение false, вам нужно будет удалить строку (из таблицы Users_Permissions .) В противном случае вы можете использовать флаг «удалено» в Users_Permissions , которая также позволит вам хранить информацию для контрольных журналов, например, когда и кем было изменено разрешение. Если вы удалите строку, вы не сможете сохранить эту информацию.
4
ответ дан 1 December 2019 в 20:42
поделиться

Я думаю, что значения "Y/N" более значимы, чем "1/0". В Oracle я бы сделал следующее, чтобы данные были максимально проверены движком базы данных:

  • определяют столбцы как char(1)
  • добавляют контрольное ограничение, которое возможно значения ограничены на "в ("Y"), "N")
  • если это соответствует правилам ведения бизнеса, сделать их недействительными - это может предотвращать проблемы, когда вы неявно предположим, что все, что не является "Y имеет значение 'N' в вашем SQL
2
ответ дан 1 December 2019 в 20:42
поделиться

Используйте все, что имеет смысл для конкретного движка базы данных, который вы используете. Это интерфейс к базе данных, который должен ее обрабатывать. Если интерфейс на стороне кода для базы данных достаточно модульный, то это будет не что иное, как простое однострочное изменение для обработки другого логического типа в базовой базе данных.

2
ответ дан 1 December 2019 в 20:42
поделиться

Если СУБД поддерживает булевый тип данных, например, MySQL, используйте его. Если она не поддерживает, как и Oracle, я обычно использую char(1) со значениями Y или N. В последнем случае хорошей идеей будет написать пару функций для преобразования Java или C++ или любого другого булевого типа в Y/N и из Y/N, чтобы избежать избыточного кода для этого. Это довольно тривиальная функция, но она будет иметь дело с такими случаями, как нули или значения, отличные от Y или N, и вы хотите делать это последовательно.

Я бы определенно НЕ упаковывал флаги в одну переменную с битовыми операциями. Да, это сэкономит некоторое дисковое пространство, но цена - гораздо большая сложность и возможность ошибки. Если ваша СУБД не поддерживает битовые операции - и поскольку у меня никогда не было желания делать такие вещи, я не знаю с головы, что, если они есть, то вам будет очень сложно выбрать или отсортировать их по такому флагу. Конечно, вы можете получить все записи, удовлетворяющие другим критериям, а затем получить код вызова, вычищающий те, которые имеют правильное значение флага. Но что, если только небольшой процент записей имеет нужное значение флага, а у вас есть запрос, который объединяет множество других записей? Например, "выберите имя сотрудника, сумму (оплату) из зарплаты сотрудника, используя (employee_id) где employee.executive=true и pay.bonus=true". С помощью пункта "где" вы, вероятно, получите очень скромное количество записей. Без него вы получаете всю базу данных.

Дисковое пространство в наши дни дешевое, поэтому любая экономия на диске, скорее всего, будет неважной. Если у вас действительно есть огромное количество флагов - например, сотни или тысячи флагов на одну запись - я полагаю, что может быть какой-то случай для их упаковки. Но это было бы намного ниже моего списка вариантов дизайна.

Правка: Позвольте мне подробнее рассказать о написании класса для преобразования вашего "SQL boolean" в "Java boolean". То же самое относится и к любому языку, но в качестве примера я буду использовать Java.

Если Ваша СУБД имеет встроенный булевый тип, то с помощью Java это можно прочитать непосредственно в булевой переменной с помощью функции ResultSet.getBoolean().

Но если вы должны хранить ее как, скажем, char "Y" или "N", то вы должны считывать ее в строку. Так что для меня имеет смысл объявить такой класс:

class MyBoolean
{
  boolean value;
  final static MyBoolean TRUE=new MyBoolean(true), FALSE=new MyBoolean(false);
  public MyBoolean(boolean b)
  {
    value=b;
  }
  public MyBoolean(String s)
  {
    if (s==null)
      return null;
    else if (s.equals("Y"))
      return MyBoolean.TRUE;
    else
      return MyBoolean.FALSE;
  }
  public static String toString(MyBoolean b)
  {
    if (b==null)
      return null;
    else if (b.value)
      return "Y";
    else
      reutrn "N";
  }
  public String toString()
  {
    return toString(this);
  }
}

Тогда вы можете легко взять булевы из базы данных с "MyBoolean flag=new MyBoolean(rs.getString("flag"));" и записать в базу данных с "rs.setString("flag", flag.toString());"

И конечно, вы можете добавить в класс любую другую логику, если у вас есть другие булевы файлы, которые вам нужны. Если для некоторых целей вы хотите отобразить булевы в виде T/F или Yes/No или On/Off или что-то в этом роде, вы можете просто добавить альтернативные варианты вString -- в TFString или в ToString(value,truetext,falsetext) или что-то в этом роде -- вместо того, чтобы писать подобный код снова и снова.

2
ответ дан 1 December 2019 в 20:42
поделиться

Исходя из собственного опыта, я предпочитаю char (1) вместо «Y» или «N». Использование 0 и 1 может немного сбивать с толку в зависимости от того, сколько пива я уже выпил, а функция C ++ main () возвращает 0 в случае успеха. Типы ENUM и BIT доставляют больше хлопот, чем они того стоят.

Интересно отметить, что MySQL information_schema использует VARCHAR (3) для «ДА» или «НЕТ».

Пример:

information_schema.USER_PRIVILEGES (
  ...
  IS_GRANTABLE VARCHAR(3) NOT NULL DEFAULT ''
) 
5
ответ дан 1 December 2019 в 20:42
поделиться

Вместо добавления столбца я предлагаю вам создать другую таблицу . Выслушайте меня ...

Предположим, у вас есть таблица с именем Клиент :

CREATE TABLE Customer
(
  CustomerID NUMBER,
  Name       VARCHAR(100)
)

Теперь предположим, что вы хотите указать, может ли покупатель отображаться в результатах поиска. Один из вариантов - добавить столбец, представляющий одно из двух возможных состояний:

CREATE TABLE Customer
(
  CustomerID NUMBER,
  Name       VARCHAR(100),
  Searchable BOOLEAN /* or CHAR(1) or BIT... */
)

Ваш поисковый запрос будет выглядеть примерно так:

SELECT CustomerID, Name
  FROM Customer
 WHERE Name LIKE '%TheCustomerNameIAmLookingFor%'
   AND Searchable = TRUE /* or 'Y' or 0... */

Это красиво и просто. Многие люди в этой ветке дают хороший совет по выбору типа данных для этого столбца, чтобы синтаксис хорошо воспроизводился в различных базах данных.

Альтернатива: создание отдельной таблицы

Вместо добавления другого столбца к Customer я создам отдельную таблицу, в которой будут храниться CustomerID каждого доступного для поиска покупателя.

CREATE TABLE Customer
(
  CustomerID NUMBER,
  Name       VARCHAR(100)
)

CREATE TABLE SearchableCustomer
(
  CustomerID NUMBER
)

В этом случае покупатель считается доступным для поиска, если его CustomerID существует в таблице SearchableCustomer .Запрос для поиска клиентов теперь выглядит следующим образом:

SELECT CustomerID, Name
  FROM Customer
 WHERE Name LIKE '%TheCustomerNameIAmLookingFor%'
   AND CustomerID IN (SELECT CustomerID FROM SearchableCustomer)

. Вы увидите, что эта стратегия может быть легко перенесена между РСУБД:

  • Для поиска клиентов с возможностью поиска используется предложение IN или JOIN
  • Making клиент с возможностью поиска использует оператор INSERT
  • Чтобы сделать клиента недоступным для поиска, используется оператор DELETE

Неожиданная выгода

Вы можете дать определение доступный для поиска клиент настолько сложен, насколько вы хотите, если вы сделаете SearchableCustomer представление вместо таблицы :

CREATE VIEW SearchableCustomer AS
SELECT CustomerID
  FROM Customer
 WHERE Name LIKE 'S%' /* For some reason, management only cares about customers whose name starts with 'S' */

Ваш поисковый запрос вообще не изменится! : D По моему опыту, это привело к огромной гибкости.

1
ответ дан 1 December 2019 в 20:42
поделиться

Битовые столбцы обычно используются для представления значений типа T/F или Y/N, по крайней мере, в SQL Server. Хотя пурист баз данных может сказать вам, что битовым столбцам нет места в базах данных, потому что они "слишком близки к оборудованию" - Джо Селко (Joe Celko).

0
ответ дан 1 December 2019 в 20:42
поделиться

COM также не имеет большого значения для разработки драйвера режима ядра, но он потенциально полезен для драйверов режима пользователя. DirectShow - это, например, COM, и есть даже легкий аналог COM, используемый в DShow-фильтрах в режиме ядра.

Существует много кода, который является COM, и устаревшему коду требуются годы или десятилетия, чтобы исчезнуть. Но более важным является то, что сборка .NET выглядит как COM-объекты при использовании из C/C + +, поэтому я думаю, что есть еще некоторое значение в знании COM , если вы намерены продолжать писать C/C + + код .

Если вы планируете перейти на C #, Java или один из десятков других языков без указателей, которые (судя по вопросам здесь SO) большинство программистов приняли, то нет, не стоит стоимости возможности.

-121--3126653-

В зависимости от того, насколько сильно необходимо оптимизировать производительность сайта, вместо этого можно использовать Combres .

Большое преимущество заключается в том, что он делает только minify и gzip ваших файлов javascript, но он также объединяет все файлы в один, так что есть только один HTTP-запрос для всех ваших файлов javascript. Кроме того, оно также использует кэширование на стороне клиента, так что файл загружается только при необходимости. Кроме того, он делает все это и для CSS-файлов.

Это довольно легко настроить, так что вместо того, чтобы пытаться исправить это, ваше время может быть лучше потрачено на получение Комбра вместо этого.

-121--1930412-

"SELECT * ОТ mytable WHERE col1

, что невозможно в SQL Server и Oracle (там нужно иметь какой-то или предикат) ".

Который идет только для того, чтобы показать, какая нелепая и смехотворная мерзость на самом деле Oracle и SQL Server.

Если col1 объявлен как тип BOOLEAN, то выражение «col1» IS является предикатом.

Если семантика предложения WHERE требует, чтобы его выражение просто вычислялось до истинного значения, и если какой-то столбец объявляется имеющим тип «истинное значение», то «WHERE that-column» должен быть как разрешен, так и поддержан. Период. Любая система, которая не просто выставляет своих авторов за некомпетентные посредственные кучи, которыми они являются.

0
ответ дан 1 December 2019 в 20:42
поделиться

Обычно я делал бы это вообще без значений BIT / BOOLEAN. Вместо этого у меня было бы три стола. Допустим, у нас есть система управления проектами, в которой есть проекты, и у этих проектов есть множество атрибутов.

Затем у нас есть таблицы:

Project
 - Project_ID (INT),
 - Name (VARCHAR)

Attribute
 - Attribute_ID (INT),
 - Name (VARCHAR)

ProjectAttribute_Rel
 - Project_ID (INT),
 - Attribute_ID (INT)

Является ли атрибут проекта истинным или ложным, зависит от того, есть ли для него строка в ProjectAttribute_Rel.

Как правило, вы будете иметь дело с Attribute_ID в своем коде, поэтому, когда вы читаете атрибуты проекта (где у вас предположительно есть Project_ID), вы просто делаете (в качестве примера произвольно используется PHP):

$arrAttributes = array();
$oQuery = mysql_query('
    SELECT Attribute_ID
    FROM ProjectAttribute_Rel
    WHERE Project_ID = '.addslashes($iProjectId).'
');
while ($rowAttribute = mysql_fetch_assoc($oQuery)) {
    $arrAttributes[] = $rowAttribute['Attribute_ID'];
}

At На этом этапе вы можете проверить, является ли атрибут проекта истинным, проверив, существует ли он вообще в $ arrAttributes. В PHP это будет:

if (in_array($arrAttributes, $iAttributeId)) {
    // Project attribute is true!
}

Этот подход также позволяет вам выполнять всевозможные трюки, чтобы избежать перечисления множества атрибутов при обновлении, опять же, когда вы выбираете (потому что SELECT * плохой в коде), когда вы вставляете и т. Д. вперед. Это потому, что вы всегда можете перебрать атрибут таблицы, чтобы найти доступные атрибуты, поэтому, если вы добавите один и сделаете это таким образом, добавление / редактирование / удаление атрибутов будет тривиальным. Скорее всего, ваш SQL даже не нужно будет менять, потому что сами атрибуты определены в базе данных, а не в коде.

Надеюсь, это поможет.

-1
ответ дан 1 December 2019 в 20:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: