データベースの設計についてサポートが必要です。
疑似コード:
Table order_status {
id int[pk, increment]
name varchar
}
Table order_status_update {
id int[pk, increment]
order_id int[ref: > order.id]
order_status_id int[ref: > order_status.id]
updated_at datetime
}
Table order_category {
id int[pk, increment]
name varchar
}
Table file {
id int[pk, increment]
order_id int[ref: > order.id]
key varchar
name varchar
path varchar
}
Table order {
id int [pk] // primary key
order_status_id int [ref: > order_status.id]
order_category_id int [ref: > order_category.id]
notes varchar
attributes json // no of attributes is not fixed, hence needed a json column
}
すべてが大丈夫でしたが、今度はorder_category_id
列の各タイプの自動インクリメントIDが必要です。
たとえば、私が2つのカテゴリの電子機器とおもちゃを持っている場合、私は電子機器1、おもちゃ1、おもちゃ2、電子機器2、電子機器3、おもちゃ3、おもちゃ4、おもちゃ5に関連付けられた値が必要になりますorder
テーブルの行。ただし、列のタイプではなく、新しい行ごとに自動インクリメントが行われるため、これは不可能です。
つまり、テーブルorder
の代わりに
id order_category_id
---------------------
1 1
2 1
3 1
4 2
5 1
6 2
7 1
フォローする必要があります
id order_category_id pretty_ids
----------------------------
1 1 toy-1
2 1 toy-2
3 1 toy-3
4 2 electronics-1
5 1 toy-4
6 2 electronics-2
7 1 toy-5
私が試したもの:
注文カテゴリごとに個別のテーブルを作成しました(理想的なソリューションではありませんが、現在6つの注文カテゴリがあるため、今のところ機能します)
これで、electronics_order
とtoys_order
のテーブルができました。カラムは反復的ですが、機能します。しかし、今、私は別の問題を抱えています。他のテーブルとのすべての関係が台無しになりました。 electronics_order
とtoys_orders
は同じIDを持つことができるため、id列を使用してorder_status_update
、order_status
、file
テーブルを参照することはできません。これらの各テーブルに別の列order_category
を作成できますが、それは正しい方法ですか?私はデータベース設計の経験がありませんので、他の人がどうやってそれをやっているのか知りたいです。
私も副質問があります
名前を保存するためだけにorder_category
とorder_status
のテーブルが必要ですか?これらの値はあまり変化せず、コードに格納してorder
テーブルの列に保存できるためです。
個別のテーブルは柔軟性に優れていることはわかっていますが、order
テーブルに新しい行を挿入する前に、データベースを2回クエリしてorder_status
およびorder_category
を名前でフェッチする必要がありました。そして後で、order
テーブルをクエリするための複数結合になります。
-
それが役に立った場合、私はデータベースサーバーとしてフラスコとsqlalchemyを使用し、postgresqlを使用しています。
Toys-1 toys-2 toys-3を実行するには、_order_status update
_のロジックを繰り返す必要があります。時間またはカウントによって、いくつかのstatus
を追跡するのに違いはありません。 _order_status update
_の場合、now()
をupdated_atに入れるだけで簡単です。たとえば、_order_category_track
_を使用すると、最後の値+ 1を取得するか、それぞれ異なるシーケンスを使用します(推奨されません)。これは、データベースオブジェクトとDB内のデータをバインドするためです。スキーマを次のように変更します
このスキーマでは、矛盾した状態になっている可能性があります。しかし、あなたのアプリケーションでは、私の意見では、3つの異なるエンティティ「order」、「order_status」、「order category track」があり、それらは自分の生活を送っています。
そしてそれでも、たとえばロックなしでこのタスクの一貫した状態を達成することはほとんど不可能です。このタスクは、次の行がSQLと矛盾する以前の行に依存するという条件によって複雑になります。
カテゴリを2レベルの階層に分割することをお勧めします:カテゴリ(おもちゃ、電子)とサブカテゴリ(おもちゃ1、おもちゃ2、電子1など):
したがって、列order_subcategory.full_nameを使用して、コンパイルされた「toy-1」値を含めるか、ビューを作成してこのフィールドをオンザフライで作成できます。
select oc.name || "-" || os.number
from order_category as oc
join order_subcategory as os on oc.id = os.category_id
https://dbdiagram.io/d/5dd6a132edf08a25543e34f8
「名前を保存するためだけにorder_categoryとorder_statusのテーブルが必要ですか?」という質問について:この種のデータを別のディクショナリテーブルとして保存することをお勧めします。一貫性と信頼性を提供します。これらのテーブルのクエリは、RDBMSにとって非常に高速で簡単なので、自由に使用してください。
ここでは、order
、order_status
、order_category
の3つのテーブルのみに焦点を当てます。新しいレコードの新しいテーブルを作成するのは正しい方法ではありません。説明として、order
テーブルとorder_category
テーブルを多対多の関係で使用しようとしていると思います。その場合、必要なのは次のようなピボットテーブルです。
現在、注文テーブルにorder_status
列を追加しています。必要に応じて、これらのテーブルの1つにこの列を追加できます。
副質問:order_status
の場合、注文ステータスが固定されている場合、(ACTIVE
、INACTIVE
のように、それができない将来的にはより多くの値になる)ENUMタイプの列を使用する方が良いでしょう。
簡単な答えは、質問に直接答えることです。しかし、私はそれがこの場合良いことだとは思いません。だから私はそうしません。多分全体の概念が間違っていると思います。
まず最初に、ビジネスニーズとアサーションを明確にします。
1つのカテゴリが複数の注文に関係する場合があります
1つの注文は一度に1つのステータスしか持てませんが、複数のステータスがあります。
1つのステータスを複数の注文で使用できます
1つの注文がファイルに対応している(おそらく請求証明)
第二:アドバイス
これは通常、良いスタートを切るのに十分です。でももう少し楽しみたい:)だから...
第4:必要なパフォーマンスに関する質問
第5:物理的なソリューションの提案
最終的なコードダウン! (良い音楽で)
-- as a postgres user
CREATE DATABASE command_system;
CREATE SCHEMA in_prgoress_command;
CREATE SCHEMA archived_command;
--DROP SCHEMA public;
-- create tablespaces on other location than below
CREATE TABLESPACE command_indexes_tbs location 'c:/Data/indexes';
CREATE TABLESPACE archived_command_tbs location 'c:/Data/archive';
CREATE TABLESPACE in_progress_command_tbs location 'c:/Data/command';
CREATE TABLE in_prgoress_command.command
(
id bigint /*or bigserial if you use a INSERT RETURNING clause*/ primary key
, notes varchar(500)
, fileULink varchar (500)
)
TABLESPACE in_progress_command_tbs;
CREATE TABLE archived_command.command
(
id bigint /*or bigserial if you use a INSERT RETURNING clause*/ primary key
, notes varchar(500)
, fileULink varchar (500)
)
TABLESPACE archived_command_tbs;
CREATE TABLE in_prgoress_command.category
(
id int primary key
, designation varchar(45) NOT NULL
)
TABLESPACE in_progress_command_tbs;
INSERT INTO in_prgoress_command.category
VALUES (1,'Toy'), (2,'Electronic'), (3,'Leather'); --non-exaustive list
CREATE TABLE in_prgoress_command.status
(
id int primary key
, designation varchar (45) NOT NULL
)
TABLESPACE in_progress_command_tbs;
INSERT INTO in_prgoress_command.status
VALUES (1,'Shipping'), (2,'Cancel'), (3,'Terminated'), (4,'Payed'), (5,'Initialised'); --non-exaustive list
CREATE TABLE in_prgoress_command.command_category
(
id bigserial primary key
, idCategory int
, idCommand bigint
)
TABLESPACE in_progress_command_tbs;
ALTER TABLE in_prgoress_command.command_category
ADD CONSTRAINT fk_command_category_category FOREIGN KEY (idCategory) REFERENCES in_prgoress_command.category(id);
ALTER TABLE in_prgoress_command.command_category
ADD CONSTRAINT fk_command_category_command FOREIGN KEY (idCommand) REFERENCES in_prgoress_command.command(id);
CREATE INDEX idx_command_category_category ON in_prgoress_command.command_category USING BTREE (idCategory) TABLESPACE command_indexes_tbs;
CREATE INDEX idx_command_category_command ON in_prgoress_command.command_category USING BTREE (idCommand) TABLESPACE command_indexes_tbs;
CREATE TABLE archived_command.command_category
(
id bigserial primary key
, idCategory int
, idCommand bigint
)
TABLESPACE archived_command_tbs;
ALTER TABLE archived_command.command_category
ADD CONSTRAINT fk_command_category_category FOREIGN KEY (idCategory) REFERENCES in_prgoress_command.category(id);
ALTER TABLE archived_command.command_category
ADD CONSTRAINT fk_command_category_command FOREIGN KEY (idCommand) REFERENCES archived_command.command(id);
CREATE INDEX idx_command_category_category ON archived_command.command_category USING BTREE (idCategory) TABLESPACE command_indexes_tbs;
CREATE INDEX idx_command_category_command ON archived_command.command_category USING BTREE (idCommand) TABLESPACE command_indexes_tbs;
CREATE TABLE in_prgoress_command.command_status
(
id bigserial primary key
, idStatus int
, idCommand bigint
, change_timestamp timestamp --anticipate if you can the time-zone problematic
)
TABLESPACE in_progress_command_tbs;
ALTER TABLE in_prgoress_command.command_status
ADD CONSTRAINT fk_command_status_status FOREIGN KEY (idStatus) REFERENCES in_prgoress_command.status(id);
ALTER TABLE in_prgoress_command.command_status
ADD CONSTRAINT fk_command_status_command FOREIGN KEY (idCommand) REFERENCES in_prgoress_command.command(id);
CREATE INDEX idx_command_status_status ON in_prgoress_command.command_status USING BTREE (idStatus) TABLESPACE command_indexes_tbs;
CREATE INDEX idx_command_status_command ON in_prgoress_command.command_status USING BTREE (idCommand) TABLESPACE command_indexes_tbs;
CREATE UNIQUE INDEX idxu_command_state ON in_prgoress_command.command_status USING BTREE (change_timestamp, idStatus, idCommand) TABLESPACE command_indexes_tbs;
CREATE OR REPLACE FUNCTION sp_trg_archiving_command ()
RETURNS TRIGGER
language plpgsql
as $function$
DECLARE
BEGIN
-- Copy the data
INSERT INTO archived_command.command
SELECT *
FROM in_prgoress_command.command
WHERE new.idCommand = idCommand;
INSERT INTO archived_command.command_status (idStatus, idCommand, change_timestamp)
SELECT idStatus, idCommand, change_timestamp
FROM in_prgoress_command.command_status
WHERE idCommand = new.idCommand;
INSERT INTO archived_command.command_category (idCategory, idCommand)
SELECT idCategory, idCommand
FROM in_prgoress_command.command_category
WHERE idCommand = new.idCommand;
-- Delete the data
DELETE FROM in_prgoress_command.command_status
WHERE idCommand = new.idCommand;
DELETE FROM in_prgoress_command.command_category
WHERE idCommand = new.idCommand;
DELETE FROM in_prgoress_command.command
WHERE idCommand = new.idCommand;
END;
$function$;
DROP TRIGGER IF EXISTS t_trg_archiving_command ON in_prgoress_command.command_status;
CREATE TRIGGER t_trg_archiving_command
AFTER INSERT
ON in_prgoress_command.command_status
FOR EACH ROW
WHEN (new.idstatus = 2 or new.idStatus = 3)
EXECUTE PROCEDURE sp_trg_archiving_command();
CREATE TABLE archived_command.command_status
(
id bigserial primary key
, idStatus int
, idCommand bigint
, change_timestamp timestamp --anticipate if you can the time-zone problematic
)
TABLESPACE archived_command_tbs;
ALTER TABLE archived_command.command_status
ADD CONSTRAINT fk_command_command_status FOREIGN KEY (idStatus) REFERENCES in_prgoress_command.category(id);
ALTER TABLE archived_command.command_status
ADD CONSTRAINT fk_command_command_status FOREIGN KEY (idCommand) REFERENCES archived_command.command(id);
CREATE INDEX idx_command_status_status ON archived_command.command_status USING BTREE (idStatus) TABLESPACE command_indexes_tbs;
CREATE INDEX idx_command_status_command ON archived_command.command_status USING BTREE (idCommand) TABLESPACE command_indexes_tbs;
CREATE UNIQUE INDEX idxu_command_state ON archived_command.command_status USING BTREE (change_timestamp, idStatus, idCommand) TABLESPACE command_indexes_tbs;
結論: