データ・テーブル・ツリーの間にまず、関係
彼らは、このような一般的なカテゴリテーブルとして木のデータの関係を、発生したデータベース設計を行う多くのプログラマが、それはここでのサブクラスの特定のサブクラスがありますこのような状況のいくつかのサブカテゴリ、ある、カテゴリです。不確かなカテゴリは、ユーザーが任意の新しいサブクラスのカテゴリに追加、またはカテゴリとその下のすべてのサブカテゴリーを削除し、以降その数は徐々に増加すると予想され、その後、我々はデータテーブルの使用を検討していきますしたいときデータを保存します。
設計構造:
名前 | タイプ | 制約 | 説明 |
TYPE_ID | int型 | 繰り返しなしません | カテゴリ識別、主キー |
TYPE_NAME | CHAR(50) | NOT NULLを | タイプ名は一意である必要があります |
type_father | int型 | NOT NULLを | カテゴリの親カテゴリ識別、最上位ノードは、一意の値に設定されている場合 |
type_layer | CHAR(6) | 定義層3、初期値000000 | 先行順走査カテゴリは、主に検索可能なデータベースの数を減らすために |
複数必要な場合は、この設計の利点は、設定するtype_layerトラバーサル順序を提供することにより、横断を容易にするために、一方のみが取得できている、三層000000は、それぞれの層が99サブカテゴリまで許容され、増加させることができます。010101は、第三の層です。
検索:type_layer BY Type_table_2のORDER * FROMを選択
次のようにレコードセットリスト:
TYPE_ID TYPE_NAME type_father type_layer
。1総クラス0 000000
2クラス11 010000
3カテゴリー1.1 2 010100
カテゴリー3 1.2 2 010200
。5クラス2102万
。6カテゴリ2.15 020 100
。7クラス31 030000
。8カテゴリ3.1。7 030 100
。9種類3.2。7 030200
10 1.1.1カテゴリ3 010 101
......
第二に、製品設計情報テーブル(属性テーブルどのようにスケーラブル)
1日あなたの上司は、オンラインの電子商取引プラットフォームのセットを開発するために会社を要求し、あなたがコンピュータ部門のデパートの開発者であると仮定し、デパート販売する製品の数千は、しかし、オンライン販売の数十に輸送を容易にするために、現時点で唯一の意向商品はもちろん、将来的には、商品の販売に新しい電子商取引プラットフォームで増加し続けることができます。今、データベースプラットフォームの製品情報テーブルを設計し始めます。商品の各販売は、製品番号、製品名、製品カテゴリ、情報、サプライヤー、いくつかの部分が含まれ、在庫、購入価格、販売価格、価格と同じ属性を持つことになります。
製品のタイプ表(Wares_type)
名前 | タイプ | 制約 | 説明 |
TYPE_ID | int型 | 繰り返しなしません | カテゴリ識別、主キー |
TYPE_NAME | CHAR(50) | NOT NULLを | タイプ名は一意である必要があります |
type_father | int型 | NOT NULLを | カテゴリの親カテゴリ識別、最上位ノードは、一意の値に設定されている場合 |
type_layer | CHAR(6) | 定義層3、初期値000000 | 先行順走査カテゴリは、主に検索可能なデータベースの数を減らすために |
仕入先]テーブル(Wares_provider)
名前 | タイプ | 制約 | 説明 |
PROVIDER_ID | int型 | 繰り返しなしません | サプライヤーの識別、主キー |
PROVIDER_NAME | CHAR(100) | NOT NULLを | サプライヤーの名前 |
製品情報表(Wares_info)
名前 | タイプ | 制約 | 説明 |
wares_id | int型 | 繰り返しなしません | プロダクトID、主キー |
wares_name | CHAR(100) | NOT NULLを | 製品名 |
wares_type | int型 | NOT NULLを | 商品タイプ識別、結合およびWares_type.type_id |
wares_info | CHAR(200) | 空を許可 | 関連情報 |
プロバイダ | int型 | NOT NULLを | 納入業者の識別、結合およびWares_provider.provider_id |
置換 | int型 | 1の初期値 | いくつかの部分を含む、デフォルトは1です |
株式 | int型 | 0の初期値 | インベントリ、デフォルトは0 |
buy_price | お金 | NOT NULLを | 買収価格 |
販売価格 | お金 | NOT NULLを | 販売価格 |
ディスカウント | お金 | NOT NULLを | 価格 |
あなたが上司に3つの検査テーブルを取った、ボスは、商品フィールドの画像を追加したいと考えているが、唯一のいくつかの製品は写真を持っています。OK、あなたは(Wares_info)製品情報テーブルにBOOLタイプフィールドのhaspicを追加し、新しいテーブルを構築しました - ピクチャーテーブル(Wares_pic):
ピクチャーテーブル(Wares_pic)
名前 | タイプ | 制約 | 説明 |
pic_id | int型 | 繰り返しなしません | ピクチャーID、主キー |
wares_id | int型 | NOT NULLを | 所有商品識別、および関連Wares_info.wares_id |
pic_address | CHAR(200) | NOT NULLを | 写真保存されたパス |
開発プログラムの完了後、完全にボスの現在の要件を満たし、その後、正式にオープンしました。時間が経つにつれて、上司は特定の商品のすべてのプロパティの「長さ」を追加する必要のある、このプラットフォーム上で販売のための新しい商品を導入したいと考えています。(Wares_lengthをコモディティ長テーブル - 最初のラウンドは......投げる来たもちろん、あなたが製品イメージテーブルを追加するための古い方法に従って、商品情報テーブル内(Wares_info)にBOOLタイプフィールドのhaslengthを追加し、新しいテーブルを構築しました):
製品の長テーブル(Wares_length)
名前 | タイプ | 制約 | 説明 |
length_id | int型 | 繰り返しなしません | ピクチャーID、主キー |
wares_id | int型 | NOT NULLを | 所有商品識別、および関連Wares_info.wares_id |
長さ | CHAR(20) | NOT NULLを | 製品の説明の長さ |
刚刚改完没多久,老板又打算上一批新的商品,这次某类商品全部需要添加“宽度”的属性。你咬了咬牙,又照方抓药,添加了商品宽度表(Wares_width)。又过了一段时间,老板新上的商品中有一些需要添加“高度”的属性,你是不是开始觉得你所设计的数据库按照这种方式增长下去,很快就能变成一个迷宫呢?那么,有没有什么办法遏制这种不可预见性,但却类似重复的数据库膨胀呢?我在阅读《敏捷软件开发:原则、模式与实践》中发现作者举过类似的例子:7.3 “Copy”程序。其中,我非常赞同敏捷软件开发这个观点:在最初几乎不进行预先设计,但是一旦需求发生变化,此时作为一名追求卓越的程序员,应该从头审查整个架构设计,在此次修改中设计出能够满足日后类似修改的系统架构。下面是我在需要添加“长度”的属性时所提供的修改方案:
去掉商品信息表(Wares_info)中的haspic字段,添加商品额外属性表(Wares_ex_property)和商品额外信息表(Wares_ex_info)2个表来完成添加新属性的功能。
商品额外属性表(Wares_ex_property)
名称 | 类型 | 约束条件 | 说明 |
ex_pid | int | 无重复 | 商品额外属性标识,主键 |
p_name | char(20) | 不允许为空 | 额外属性名称 |
商品额外信息表(Wares_ex_info)
名称 | 类型 | 约束条件 | 说明 |
ex_iid | int | 无重复 | 商品额外信息标识,主键 |
wares_id | int | 不允许为空 | 所属商品标识,和Wares_info.wares_id关联 |
property_id | int | 不允许为空 | 商品额外属性标识,和Wares_ex_property.ex_pid关联 |
property_value | char(200) | 不允许为空 | 商品额外属性值 |
在商品额外属性表(Wares_ex_property)中添加2条记录:
ex_pid p_name
1 商品图片
2 商品长度
再在整个电子商务平台的后台管理功能中追加一项商品额外属性管理的功能,以后添加新的商品时出现新的属性,只需利用该功能往商品额外属性表(Wares_ex_property)中添加一条记录即可。
三、多用户及其权限管理的设计
要求:该数据库管理软件的系统管理员可以自行添加新用户,修改已有用户的权限,删除已有用户。
首先,分析用户需求,列出该数据库管理软件所有需要实现的功能;然后,根据一定的联系对这些功能进行分类,即把某类用户需使用的功能归为一类;
功能表(Function_table)
名称 | 类型 | 约束条件 | 说明 |
f_id | int | 无重复 | 功能标识,主键 |
f_name | char(20) | 不允许为空 | 功能名称,不允许重复 |
f_desc | char(50) | 允许为空 | 功能描述 |
用户组表(User_group)
名称 | 类型 | 约束条件 | 说明 |
group_id | int | 无重复 | 用户组标识,主键 |
group_name | char(20) | 不允许为空 | 用户组名称 |
group_power | char(100) | 不允许为空 | 用户组权限表,内容为功能表f_id的集合 |
用户表(User_table)
名称 | 类型 | 约束条件 | 说明 |
user_id | int | 无重复 | 用户标识,主键 |
user_name | char(20) | 无重复 | 用户名 |
user_pwd | char(20) | 不允许为空 | 用户密码 |
user_type | int | 不允许为空 | 所属用户组标识,和User_group.group_id关联 |
采用这种用户组的架构设计,当需要添加新用户时,只需指定新用户所属的用户组;当以后系统需要添加新功能或对旧有功能权限进行修改时,只用操作功能表和用户组表的记录,原有用户的功能即可相应随之变化。
四、简洁的批量m:n设计
碰到m:n的关系,一般都是建立3个表,m一个,n一个,m:n一个。但是,m:n有时会遇到批量处理的情况,例如到图书馆借书,一般都是允许用户同时借阅n本书,如果要求按批查询借阅记录,即列出某个用户某次借阅的所有书籍,该如何设计呢?让我们建好必须的3个表先:
书籍表(Book_table)
名称 | 类型 | 约束条件 | 说明 |
book_id | int | 无重复 | 书籍标识,主键 |
book_no | char(20) | 无重复 | 书籍编号 |
book_name | char(100) | 不允许为空 | 书籍名称 |
…… |
借阅用户表(Renter_table)
名称 | 类型 | 约束条件 | 说明 |
renter_id | int | 无重复 | 用户标识,主键 |
renter_name | char(20) | 不允许为空 | 用户姓名 |
…… |
借阅记录表(Rent_log)
名称 | 类型 | 约束条件 | 说明 |
rent_id | int | 无重复 | 借阅记录标识,主键 |
r_id | int | 不允许为空 | 用户标识,和Renter_table.renter_id关联 |
b_id | int | 不允许为空 | 书籍标识,和Book_table.book_id关联 |
batch_no | int | 不允许为空 | 批量借阅编号,同一批借阅的batch_no相同 |
rent_date | datetime | 不允许为空 | 借阅时间 |
…… |
其中,同一次借阅的batch_no和该批第一条入库的rent_id相同。举例:假设当前最大rent_id是64,接着某用户一次借阅了3本书,则批量插入的3条借阅记录的batch_no都是65。之后另外一个用户租了一套碟,再插入出租记录的rent_id是68。采用这种设计,查询批量借阅的信息时,只需使用一条标准T_SQL的嵌套查询即可。
五、冗余数据的取舍
我原先所在的公司为了解决员工的工作餐,和附近的一家小餐馆联系,每天吃饭记账,费用按人数平摊,月底由公司现金结算,每个人每个月的工作餐费从工资中扣除。当然,每天吃饭的人员和人数都不是固定的,而且,由于每顿工作餐的所点的菜色不同,每顿的花费也不相同。例如,星期一中餐5人花费40元,晚餐2人花费20,星期二中餐6人花费36元,晚餐3人花费18元。为了方便计算每个人每个月的工作餐费,我写了一个简陋的就餐记账管理程序,数据库里有3个表:
员工表(Clerk_table)
名称 | 类型 | 约束条件 | 说明 |
clerk_id | int | 无重复 | 员工标识,主键 |
clerk_name | char(10) | 不允许为空 | 员工姓名 |
每餐总表(Eatdata1)
名称 | 类型 | 约束条件 | 说明 |
totle_id | int | 无重复 | 每餐总表标识,主键 |
persons | char(100) | 不允许为空 | 就餐员工的员工标识集合 |
eat_date | datetime | 不允许为空 | 就餐日期 |
eat_type | char(1) | 不允许为空 | 就餐类型,用来区分中、晚餐 |
totle_price | money | 不允许为空 | 每餐总花费 |
persons_num | int | 不允许为空 | 就餐人数 |
就餐计费细表(Eatdata2)
名称 | 类型 | 约束条件 | 说明 |
id | int | 无重复 | 就餐计费细表标识,主键 |
t_id | int | 不允许为空 | 每餐总表标识,和Eatdata1.totle_id关联 |
c_id | int | 不允许为空 | 员工标识标识,和Clerk_table.clerk_id关联 |
price | money | 不允许为空 | 每人每餐花费 |
其中,就餐计费细表(Eatdata2)的记录就是把每餐总表(Eatdata1)的一条记录按就餐员工平摊拆开,是个不折不扣的冗余表。当然,也可以把每餐总表(Eatdata1)的部分字段合并到就餐计费细表(Eatdata2)中,这样每餐总表(Eatdata1)就成了冗余表,不过这样所设计出来的就餐计费细表重复数据更多,相比来说还是上面的方案好些。但是,就是就餐计费细表(Eatdata2)这个冗余表,在做每月每人餐费统计的时候,大大简化了编程的复杂度,只用类似这么一条查询语句即可统计出每人每月的寄餐次数和餐费总帐:
SELECT clerk_name AS personname,COUNT(c_id) as eattimes,SUM(price) AS ptprice FROM Eatdata2 JOIN Clerk_tabsle ON (c_id=clerk_id) JOIN eatdata1 ON (totleid=tid) WHERE eat_date>=CONVERT(datetime,'"&the_date&"') AND eat_date<DATEADD(month,1,CONVERT(datetime,'"&the_date&"')) GROUP BY c_id
想象一下,如果不用这个冗余表,每次统计每人每月的餐费总帐时会多麻烦,程序效率也够呛。那么,到底什么时候可以增加一定的冗余数据呢?我认为有2个原则:
1、用户的整体需求。当用户更多的关注于,对数据库的规范记录按一定的算法进行处理后,再列出的数据。如果该算法可以直接利用后台数据库系统的内嵌函数来完成,此时可以适当的增加冗余字段,甚至冗余表来保存这些经过算法处理后的数据。要知道,对于大批量数据的查询,修改或删除,后台数据库系统的效率远远高于我们自己编写的代码。
2、简化开发的复杂度。现代软件开发,实现同样的功能,方法有很多。尽管不必要求程序员精通绝大部分的开发工具和平台,但是还是需要了解哪种方法搭配哪种开发工具的程序更简洁,效率更高一些。冗余数据的本质就是用空间换时间,尤其是目前硬件的发展远远高于软件,所以适当的冗余是可以接受的。不过我还是在最后再强调一下:不要过多的依赖平台和开发工具的特性来简化开发,这个度要是没把握好的话,后期维护升级会栽大跟头的。
参考:https://www.cnblogs.com/hoojjack/p/4705830.html