Как сохранить список в столбце таблицы базы данных - PullRequest
94 голосов
/ 18 июня 2010

Итак, за ответ Мехрдада на связанный вопрос , я понял , что «правильный» столбец таблицы базы данных не хранит список.Скорее, вы должны создать другую таблицу, которая эффективно содержит элементы указанного списка, а затем связываться с ней напрямую или через соединительную таблицу.Однако тип списка, который я хочу создать, будет состоять из уникальных элементов (в отличие от примера fruit , связанного с вопросом).Кроме того, элементы в моем списке явно отсортированы - это означает, что если бы я хранил элементы в другой таблице, мне пришлось бы сортировать их каждый раз, когда я к ним обращался.Наконец, список является в основном атомарным в том смысле, что в любое время, когда я захочу получить доступ к списку, я захочу получить доступ ко всему списку, а не просто к его части - поэтому глупо вынуждать выдавать запрос к базе данных, чтобы собрать вместе кусочкисписок.

Решение AKX (см. выше) состоит в том, чтобы сериализовать список и сохранить его в двоичном столбце.Но это также кажется неудобным, потому что это означает, что мне нужно беспокоиться о сериализации и десериализации.

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

... просто немного больше информации, чтобы сообщить вам, откуда я.Как только я только начал понимать SQL и базы данных в целом, я был включен в LINQ to SQL, и теперь я немного испорчен, потому что ожидаю разобраться с моей объектной моделью программирования, не думая о том, как объектызапрашиваются или хранятся в базе данных.

Спасибо всем!

Джон

ОБНОВЛЕНИЕ: Итак, в первом потоке ответов, которые я получаю, я вижу, «вы можете идтимаршрут CSV / XML ... но НЕ! "Так что теперь я ищу объяснения почему.Укажи мне несколько хороших ссылок.

Также, чтобы дать вам лучшее представление о том, чем я занимаюсь: В моей базе данных есть таблица Function, в которой будет список (x, y) пар.(Таблица также будет содержать другую информацию, которая не имеет значения для нашего обсуждения.) Мне никогда не нужно будет видеть часть списка (x, y) пар.Скорее я возьму их все и нанесу их на экран.Я позволю пользователю перетаскивать узлы вокруг, чтобы время от времени изменять значения или добавлять дополнительные значения в график.

Ответы [ 10 ]

152 голосов
/ 18 июня 2010

Нет, «лучшего» способа сохранить последовательность элементов в одном столбце нет. Реляционные базы данных предназначены , в частности , для хранения одного значения на комбинацию строки / столбца. Чтобы сохранить более одного значения, вы должны сериализовать свой список в одно значение для хранения, а затем десериализовать его при получении. Нет другого способа сделать то, о чем вы говорите (потому что то, о чем вы говорите, это плохая идея, которую, как правило, никогда не следует делать ).

Я понимаю, что вы думаете, что глупо создавать другую таблицу для хранения этого списка, но это именно то, что делают реляционные базы данных. Вы ведете тяжелую борьбу и нарушаете один из самых основных принципов проектирования реляционных баз данных без веской причины. Поскольку вы заявляете, что изучаете только SQL, я бы настоятельно посоветовал вам избежать этой идеи и придерживаться рекомендаций, рекомендованных вам более опытными разработчиками SQL.

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

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

По сути, первое правило (или форма) нормализации гласит, что ваша таблица должна представлять отношение. Это означает, что:

  • Вы должны быть в состоянии отличить одну строку от любой другой строки (другими словами, ваша таблица должна иметь то, что может служить первичным ключом. Это также означает, что ни одна строка не должна дублироваться.
  • Любое упорядочение данных должно определяться данными, а не физическим упорядочением строк (SQL основан на идее набора, что означает, что упорядочение only , на которое вы должны полагаться, то, что вы явно определяете в своем запросе)
  • Каждое пересечение строк / столбцов должно содержать одно и только одно значение

Последний пункт, очевидно, является существенным моментом здесь. SQL предназначен для хранения ваших наборов, а не для того, чтобы вы могли хранить наборы самостоятельно. Да, это возможно сделать. Нет, мир не закончится. Вы, однако, уже искалечили себя в понимании SQL и лучших практик, которые сопровождают его, сразу же приступив к использованию ORM. LINQ to SQL - это просто фантастика, как и графические калькуляторы. Однако в том же духе они должны , а не использоваться вместо знания того, как на самом деле работают процессы, которые они используют.

Ваш список может теперь быть полностью «атомным», и это может не измениться для этого проекта. Но, однако, вы привыкнете делать подобные вещи в других проектах, и вы в конечном итоге (скорее всего, быстро) столкнетесь со сценарием, в котором вы сейчас подгоняете свой быстрый и простой список в столбце подход там, где это совершенно неуместно. В создании правильной таблицы для того, что вы пытаетесь сохранить, не так много работы, и другие разработчики SQL не будут насмехаться над вами, когда увидят ваш дизайн базы данных. Кроме того, LINQ to SQL увидит ваше отношение и предоставит вам надлежащий объектно-ориентированный интерфейс для вашего списка , автоматически . Зачем вам отказываться от удобства, предлагаемого вам ORM, чтобы вы могли выполнять нестандартные и необдуманные хакерские действия с базой данных?

12 голосов
/ 18 июня 2010

Вы можете просто забыть SQL все вместе и использовать подход «NoSQL». RavenDB , MongoDB и CouchDB напоминают о возможных решениях. При использовании подхода NoSQL вы не используете реляционную модель. Вы даже не ограничены схемами.

8 голосов
/ 26 июля 2015

Я видел, как многие люди делают это (возможно, это не лучший подход, поправьте меня, если я ошибаюсь):

Таблица, которую я использую в примере, приведена ниже (таблица содержит псевдонимы, которые вы дали своим конкретным подругам. У каждой подруги есть уникальный идентификатор):

nicknames(id,seq_no,names)

Предположим, вы хотите хранить много псевдонимов под идентификатором. Вот почему мы включили поле seq_no.

Теперь заполните эти значения в вашей таблице:

(1,1,'sweetheart'), (1,2,'pumpkin'), (2,1,'cutie'), (2,2,'cherry pie')

Если вы хотите найти все имена, которые вы дали своей подруге с идентификатором 1, вы можете использовать:

select names from nicknames where id = 1;
3 голосов
/ 18 июня 2010

В дополнение к тому, что сказали все остальные, я бы посоветовал вам проанализировать свой подход в более долгосрочной перспективе, чем сейчас. Это в настоящее время случай, когда предметы являются уникальными. Это в настоящее время случай, когда для пересмотра предметов потребуется новый список. Почти требуется, чтобы список был в настоящее время коротким. Несмотря на то, что у меня нет специфики домена, думать, что эти требования могут измениться, не так уж и сложно. Если вы сериализуете свой список, вы выпекаете в негибкости, которая не нужна в более нормализованном дизайне. Между прочим, это не обязательно означает полное отношение «многие: многие». Вы можете просто иметь одну дочернюю таблицу с внешним ключом для родителя и символьным столбцом для элемента.

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

2 голосов
/ 25 мая 2017

Простой ответ: Если и только в том случае, если вы уверены, что список всегда будет использоваться в качестве списка, соедините этот список вместе с вашей стороны с помощью символа (такого как '\ 0'), который не будетиспользуется в тексте всегда, и сохраните это.Затем, когда вы получите его, вы можете разделить на '\ 0'.Конечно, есть и другие способы решения этой проблемы, но они зависят от вашего конкретного поставщика базы данных.

Например, вы можете хранить JSON в базе данных Postgres.Если ваш список текстовый, и вы просто хотите, чтобы этот список не вызывал лишних хлопот, это разумный компромисс.

Другие высказались за сериализацию, но я не думаю, что сериализация - это хорошая идея.Удобство работы с базами данных состоит в том, что несколько программ, написанных на разных языках, могут общаться друг с другом.И программы, сериализованные с использованием формата Java, не справились бы с этим хорошо, если бы программа на Лиспе захотела их загрузить.

Если вы хотите найти хороший способ сделать что-то подобное, обычно есть доступные массивы или подобные им типы. Например, Postgres, предлагает массив как тип и позволяет вам хранить массив текста, если это то, что вам нужно , и есть аналогичные приемы для MySql и MS SQL с использованием JSON и IBM DB2 также предлагает тип массива (в собственной полезной документации).Это было бы не так часто, если бы в этом не было необходимости.

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

2 голосов
/ 18 июня 2010

Если вам нужно выполнить запрос в списке, сохраните его в таблице.

Если вы всегда хотите список, вы можете сохранить его в виде списка с разделителями в столбце. Даже в этом случае, если у вас нет ОЧЕНЬ особых причин не хранить это в справочной таблице.

1 голос
/ 18 июня 2010

Только один вариант не упоминается в ответах. Вы можете отменить нормализацию дизайна вашей БД. Итак, вам нужно две таблицы. Одна таблица содержит правильный список, по одному элементу в строке, другая таблица содержит весь список в одном столбце (например, через запятую).

Вот это «традиционный» дизайн БД:

List(ListID, ListName) 
Item(ItemID,ItemName) 
List_Item(ListID, ItemID, SortOrder)

Вот это ненормализованная таблица:

Lists(ListID, ListContent)

Идея здесь - вы поддерживаете таблицу списков, используя триггеры или код приложения. Каждый раз, когда вы изменяете содержимое List_Item, соответствующие строки в списках обновляются автоматически. Если вы в основном читаете списки, это может работать вполне нормально. Плюсы - вы можете читать списки в одном утверждении. Минусы - обновления требуют больше времени и усилий.

1 голос
/ 18 июня 2010

Я бы просто сохранил его как CSV, если это простые значения, тогда это должно быть все, что вам нужно (XML очень многословен, и сериализация в / из него будет, вероятно, излишней, но это тоже будет вариант).

Вот хороший ответ о том, как извлекать CSV с помощью LINQ.

0 голосов
/ 18 октября 2016

Я думаю, что в некоторых случаях вы можете создать FAKE «список» предметов в базе данных, например, товар имеет несколько картинок, чтобы показать его детали, вы можете объединить все идентификаторы картинок, разделенные запятой и сохранить строка в БД, тогда вам просто нужно проанализировать строку, когда вам это нужно. Сейчас я работаю над сайтом и планирую использовать этот способ.

0 голосов
/ 18 июня 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...