web-dev-qa-db-ja.com

データベーステーブルの列にリストを保存する方法

したがって、 関連する質問に対するMehrdadの答え 、Iごとに「適切な」データベーステーブル列に保存されないリスト。むしろ、前述のリストの要素を効果的に保持する別のテーブルを作成してから、直接またはジャンクションテーブルを介してそれにリンクする必要があります。ただし、作成するリストのタイプは一意のアイテムで構成されます(リンクされた質問のfruitの例とは異なります)。さらに、リスト内のアイテムは明示的に並べ替えられます。つまり、要素を別のテーブルに保存すると、アクセスするたびに要素を並べ替える必要があります。最後に、リストは基本的にアトミックです。リストにアクセスしたいときはいつでも、リストの一部ではなくリスト全体にアクセスしたいので、データベースクエリを発行して、リスト。

AKXのソリューション(上記リンク)は、リストをシリアル化し、バイナリ列に保存することです。しかし、これはまた、シリアル化と逆シリアル化を心配する必要があることを意味するため、不便に思えます。

より良い解決策はありますか?そこにisより良い解決策がない場合、なぜですか?この問題は時々発生するようです。

...私がどこから来たのかを知らせるためのもう少し情報。 SQLとデータベース全般を理解し始めた直後に、LINQ to SQLに切り替えました。そのため、オブジェクトがどのように考えなくてもプログラミングオブジェクトモデルに対処することが期待されるため、少し甘やかされています。クエリまたはデータベースに保存されます。

皆さんありがとう!

ジョン

更新:だから、私が得ている最初の回答で、「CSV/XMLルートに行くことができます...でもいけない!」だから今、私は理由の説明を探しています。良い参考文献をいくつか教えてください。

また、私が何をしているのかをより良く理解するために、私のデータベースには、(x、y)ペアのリストを持つ関数テーブルがあります。 (この表には、議論に重要でない他の情報も含まれます。)(x、y)ペアのリストの一部を見る必要はありません。むしろ、それらすべてを画面にプロットします。ユーザーがノードをドラッグして値を時々変更したり、プロットに値を追加したりできるようにします。

96
JnBrymn

いいえ、一連のアイテムを単一の列に格納する「より良い」方法はありません。リレーショナルデータベースは、行と列の組み合わせごとに1つの値を格納するように設計されています具体的に。複数の値を保存するには、mustを使用してリストを単一の値にシリアル化して保存し、取得時に非シリアル化します。あなたが話していることを行う他の方法はありません(あなたが話していることは、一般に、やるべきではない悪い考えであるため)。

そのリストを保存するために別のテーブルを作成するのは馬鹿げていると思うと理解していますが、これはまさにリレーショナルデータベースが行うことです。あなたは困難な戦いをしていて、もっともな理由もなくリレーショナルデータベース設計の最も基本的な原則の1つに違反しています。あなたは単にSQLを学習していると述べているので、私は強く、この考えを避け、より経験豊富なSQLが推奨するプラクティスに従うことをお勧めします開発者。

違反している原則は最初の正規形と呼ばれ、データベースの正規化の最初のステップです。

物事を単純化しすぎてしまうリスクがありますが、データベースの正規化とは、データisに基づいてデータベースを定義するプロセスのことです。正規化は、データの論理的な不整合と破損を制限するように設計されており、多くのレベルがあります。 データベースの正規化 に関するウィキペディアの記事は、実際にはかなり良いものです。

基本的に、正規化の最初のルール(または形式)は、テーブルがリレーションを表す必要があることを示しています。この意味は:

  • 1つの行を他の行と区別できる必要があります(つまり、テーブルにはcanがプライマリキーとして機能する必要があります。これは、行を複製しないことも意味します。
  • データの順序は、行の物理的な順序ではなくデータによって定義する必要があります(SQLはセットの概念に基づいています。つまり、onlyに依存する順序は次のとおりです。クエリで明示的に定義します)
  • すべての行/列の交差には1つおよび1つのみ valueを含める必要があります

最後の点は明らかにここの顕著な点です。 SQLは、セットを自分で保存するための「バケット」を提供するのではなく、セットを保存するように設計されています。はい、それは可能です。いいえ、世界は終わりません。ただし、すぐにORMの使用にジャンプすることで、SQLとそれに伴うベストプラクティスを理解する上ですでに障害があります。 LINQ to SQLは、グラフ電卓と同じように素晴らしいです。ただし、同じように、notは、使用するプロセスが実際にどのように機能するかを知るための代替として使用する必要があります。

リストは完全に「アトミック」になり、このプロジェクトでは変更されない場合があります。しかし、あなたは他のプロジェクトで同様のことをする習慣を身につけ、最終的に(おそらく)すぐにあなたのクイック・アンド・イージー・リスト・イン・ア・コラムをフィッティングするシナリオにぶつかるでしょう完全に不適切なアプローチ。格納しようとしているものに適したテーブルを作成するための追加作業はあまりありません。また、他のSQL開発者がデータベースの設計を見たときにだまされることはありません。さらに、LINQ to SQLは関係を確認し、リストへの適切なオブジェクト指向インターフェイスを提供します自動的に。 ORMが提供する利便性を放棄して、非標準で不適切なデータベースハッカーを実行できるようにするのはなぜですか?

158
Adam Robinson

SQLをすべて忘れて、「NoSQL」アプローチを使用できます。 RavenDBMongoDB 、および CouchDB 可能な解決策として心に飛び込んでください。 NoSQLアプローチでは、リレーショナルモデルを使用していません。スキーマに制約されることもありません。

13
jaltiere

私が多くの人々がしているのを見たことはこれです(それは最良のアプローチではないかもしれません、私が間違っているなら私を修正してください):

この例で使用している表を以下に示します(表には、特定のガールフレンドに付けたニックネームが含まれています。各ガールフレンドには一意のIDがあります)。

nicknames(id,seq_no,names)

IDの下に多くのニックネームを保存するとします。これがseq_noフィールドを含めた理由です。

次に、これらの値をテーブルに入力します。

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

ガールフレンドID 1に付けた名前をすべて検索する場合は、次を使用できます。

select names from nicknames where id = 1;
8
user5157248

他の皆が言ったことに加えて、私はあなたが今よりも長い期間であなたのアプローチを分析することを提案します。 現在アイテムが一意である場合。 現在の場合、アイテムを再分類するには新しいリストが必要です。リストは現在短いことがほとんど必要です。ドメインの詳細はありませんが、これらの要件が変更される可能性があると考えるのはそれほど簡単ではありません。リストをシリアル化すると、より正規化されたデザインでは必要のない柔軟性が失われます。ところで、それは必ずしも完全な多対多の関係を意味するわけではありません。親への外部キーとアイテムの文字列を持つ単一の子テーブルを作成できます。

それでもリストをシリアル化するというこの道を進みたい場合は、リストをXMLで保存することを検討してください。 SQL Serverなどの一部のデータベースには、XMLデータ型さえあります。私がXMLを提案する唯一の理由は、ほとんどの定義上、このリストは短くする必要があるということです。リストが長い場合、一般にリストをシリアライズするのはひどいアプローチです。 CSVルートを使用する場合、区切り文字を含む値を考慮する必要があります。つまり、引用識別子を使用する必要があります。リストが短いと仮定すると、CSVを使用する場合でもXMLを使用する場合でも、おそらく大きな違いはありません。

3
Thomas

簡単な答え:リストが常にリストとして使用されることが確実である場合にのみ、リストで使用されない文字( '\ 0'など)でリストを結合しますテキスト、そしてそれを保存します。次に、それを取得するときに、「\ 0」で分割できます。もちろん、このようなことについて他の方法もありますが、それらは特定のデータベースベンダーに依存しています。

例として、PostgresデータベースにJSONを保存できます。リストがテキストであり、さらに面倒なことなくリストが必要な場合は、妥当な妥協案です。

他の人はシリアル化の提案を敢行しましたが、シリアル化は良いアイデアだとは本当に思いません。データベースについての素晴らしいことの一部は、異なる言語で書かれたいくつかのプログラムが互いに通信できることです。また、Javaの形式を使用してシリアル化されたプログラムは、LISPプログラムがそれをロードしたい場合、それほどうまくいきません。

この種のことを行う良い方法が必要な場合は、通常、配列または類似のタイプが使用可能です。 たとえば、Postgresは、配列をタイプとして提供し、必要に応じてテキストの配列を保存できますMySql および MS SQL JSONを使用し、 IBMのDB2 も配列型を提供します(独自に役立つドキュメント)。これが必要なければ、これはそれほど一般的ではありません。

その道を行くことで失うのは、リストを一連の物としてリストするという概念です。少なくとも名目上、データベースはフィールドを単一の値として扱います。しかし、それがあなたが望むすべてであるならば、あなたはそれのために行くべきです。それはあなたがあなた自身のためにしなければならない価値判断です。

2
Haakon Løtveit

リストを照会する必要がある場合は、テーブルに保存します。

常にリストが必要な場合は、区切りリストとして列に保存できます。この場合でも、非常に特別な理由がない限り、ルックアップテーブルに保存します。

2
hometoast

回答に記載されていないオプションは1つだけです。 DB設計を非正規化できます。したがって、2つのテーブルが必要です。 1つのテーブルには適切なリスト、行ごとに1つのアイテムが含まれ、別のテーブルには1つの列にリスト全体が含まれます(たとえば、カンマ区切り)。

これが「従来の」DB設計です。

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

これは非正規化されたテーブルです。

Lists(ListID, ListContent)

ここでのアイデア-トリガーまたはアプリケーションコードを使用してListsテーブルを維持します。 List_Itemのコンテンツを変更するたびに、リストの適切な行が自動的に更新されます。あなたがほとんどリストを読むなら、それは非常にうまくいくでしょう。長所-リストを1つのステートメントで読むことができます。短所-更新にはより多くの時間と労力がかかります。

1
Alsin

私はそれをCSVとして保存しますが、単純な値であればそれで十分です(XMLは非常に冗長であり、XMLへの/からのシリアル化はおそらくやり過ぎでしょうが、それもオプションです)。

LINQでCSVを取り出す方法については、 良い答え をご覧ください。

1
David Neale

特定のケースでは、データベース内のアイテムの偽の「リスト」を作成できると思います。たとえば、商品には詳細を示すいくつかの写真があり、コンマで分割された写真のすべてのIDを連結して文字列を格納できますDBの場合は、必要なときに文字列を解析するだけです。私は現在ウェブサイトに取り組んでおり、この方法を使用する予定です。

0
Nen

列に保存してクエリ可能にしたい場合は、多くのデータベースがXMLをサポートしています。クエリを実行しない場合は、コンマ区切り値として保存し、必要なときに関数で解析できます。リレーショナルデータベースの使用を検討している場合、正規化の重要な部分はそのようなデータの分離です。ただし、すべてのデータがリレーショナルデータベースに適合するとは言いません。大量のデータがモデルに適合しない場合は、常に他の種類のデータベースを調べることができます。

0
David Daniel