Как указано в заголовке, при разработке баз данных, что является предпочтительным способом обработать таблицы, которые имеют несколько столбцов, которые просто хранят верный / ложные значения как просто сингл или или значение (например, "Y/N: или "0/1")? Аналогично, есть ли некоторые проблемы, которые могли бы возникнуть между различными базами данных (например, Oracle Server и SQL Server), который мог бы влиять, как столбцы обрабатываются?
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.
В 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
тоже (в терминах места хранения), но логически он не неявно конвертируется в любой другой тип.
Вместо логических типов данных вы можете рассмотреть другую модель данных для хранения логических значений. , что может быть особенно подходящим в следующих случаях:
Определение полномочий пользователя может быть типичным примером вышеизложенного. Рассмотрим следующие таблицы:
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
). Вы можете легко сохранить дополнительную информацию по каждому факту. Недостатки
Users_Permissions
.) В противном случае вы можете использовать флаг «удалено» в Users_Permissions
, которая также позволит вам хранить информацию для контрольных журналов, например, когда и кем было изменено разрешение. Если вы удалите строку, вы не сможете сохранить эту информацию. Я думаю, что значения "Y/N" более значимы, чем "1/0". В Oracle я бы сделал следующее, чтобы данные были максимально проверены движком базы данных:
Используйте все, что имеет смысл для конкретного движка базы данных, который вы используете. Это интерфейс к базе данных, который должен ее обрабатывать. Если интерфейс на стороне кода для базы данных достаточно модульный, то это будет не что иное, как простое однострочное изменение для обработки другого логического типа в базовой базе данных.
Если СУБД поддерживает булевый тип данных, например, 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) или что-то в этом роде -- вместо того, чтобы писать подобный код снова и снова.
Исходя из собственного опыта, я предпочитаю 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 ''
)
Вместо добавления столбца я предлагаю вам создать другую таблицу . Выслушайте меня ...
Предположим, у вас есть таблица с именем Клиент
:
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
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 По моему опыту, это привело к огромной гибкости.
Битовые столбцы обычно используются для представления значений типа T/F или Y/N, по крайней мере, в SQL Server. Хотя пурист баз данных может сказать вам, что битовым столбцам нет места в базах данных, потому что они "слишком близки к оборудованию" - Джо Селко (Joe Celko).
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» должен быть как разрешен, так и поддержан. Период. Любая система, которая не просто выставляет своих авторов за некомпетентные посредственные кучи, которыми они являются.
Обычно я делал бы это вообще без значений 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 даже не нужно будет менять, потому что сами атрибуты определены в базе данных, а не в коде.
Надеюсь, это поможет.