数据库设计的5种常见关系,其中本文主要讲“多态”关系结构,以手机为例。 1,配置关系  --和其他表无任何关系的表。 
例如:webConfig里的东西你存储到表里。 2,一对多关系 ,一张表包含另外一个表的主键作为外键。 
例如:手机.品牌id=2, 这里的2是[品牌名称表]的id字段为2的纪录,品牌名称是"Nokia"。一个手机只能有一个品牌。 3,多对多,需要2张表,有一个包含两个外键的关系表。 
        例如: 手机1即属于"智能" 又属于"滑盖"组的, 一个组包含多个手机,一个手机可以属于多个组。 4,树型结构,常见的两钟:父ID设计和001002编码设计。 
例如:手机的经销商分为 省/市/县 5,“多态”结构和多对多略有不同,如果需求中某表字段多少类型有非常大的不确定性,可以采用3个表来完成: 一个[主表](ID), 
一个[属性名称表](属性ID.属性名称), 
一个[属性值表],包括3个字段: 
      属性值(属性Value varchar(500)) 
      主表ID 
      属性ID 这样可以作到最小冗余度。 
(和常见的多对多关系不同的是:值统一用varchar来存储,因为这类型的值一般不会用来计算)。 比如:手机型号有几千种,除了共同属性外还有不同属性有几百个,属性名和值类型都不一样,有的手机有这属性,有的没有。 
对于这样的“多态”,我们就采用上面的设计结构。 
其效果相当于: 某奇怪手机.属性集合["某某奇怪属性名"]="某某奇怪值"; 
某变态手机.属性集合["某某变态属性名"]="某某变态值"; 

解决方案 »

  1.   

    To:dawugui 潇洒老乌龟(爱新觉罗.毓华)你跑题了,我题目里说的是关系型数据库的“关系”类型。不要再讲什么1,2,3NF的小儿科了,就算讲泛式,我以前总结的: 1,原子性(不可分,例如:1,3,4这样就是错误的) 
    2,依赖性 (必须依赖主键) 
    3,非依赖性(除主键外都不依赖)比你拷贝来罗嗦一堆话经济实用。
      

  2.   

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="dataBaseInfo.aspx.cs" Inherits="dataBaseInfo" %><html xmlns:v='urn:schemas-microsoft-com:vml'>
    <head>
        <style type="text/css">
            v\:*
            {
                behavior: url(#default#VML);
            }
            td
            {
                font-size: 12px;
                cursor: move;
                background-color: white;
            }
            th
            {
                font-size: 12px;
                background-color: #cccccc;
                cursor: move;
            }
            table
            {
                border-collapse: collapse;
                border: 4px #999999 double;
                position: absolute;
                 
            }
            body
            {
                cursor: move;
            }
            span #aaa
            {
            }
        </style>     <title>察看表结构</title>
    </head>
    <body onmousedown='BodyMouseDown()' onmousemove='BodyMouseMove()' onmouseup='BodyMouseUp()'>
        <%=SBTable %>
        <span id="aaa" style='position: absolute; top: <%=WorkAreaNum*WorkAreaWidth %>; left: <%=WorkAreaNum*WorkAreaWidth %>;'>
            超级大笨狼</span>    <script type="text/jscript" language="javascript">
        //定义区开始
                var workPlaceSize=<%=WorkAreaWidth %>;
                var workPlaceHeight= (<%=WorkAreaNum %> +1)* workPlaceSize ;//工作区大小  
                var workPlaceWidth= workPlaceHeight;     
                 var currrentViewX= workPlaceWidth/2;
                 var currrentViewY=workPlaceHeight/2;
                var lastMouseX=-1; 
                var lastMouseY=-1; 
                window.scrollTo(currrentViewX,currrentViewY);
               document.onselectionchange=function(){document.selection.empty();} 
                var Obj;
                var isBodyCapture=false;
                    
     //  定义区结束
    function BodyMouseDown(){                
                    if(event.srcElement.tagName=="BODY")
                    {
                        isBodyCapture=true;  
                    
                    }
                     lastMouseX=event.x; 
                     lastMouseY=event.y;
     
    }
                //alert(window.screen.availWidth);
    function BodyMouseMove(){
                    window.status=event.srcElement.tagName;
                    if(event.srcElement.tagName!="BODY" )
                    {            
                        lostCaptrue();
                    }
                    if(isBodyCapture)
                    {            
                        currrentViewX+=lastMouseX-event.x;
                        currrentViewY+=lastMouseY- event.y;
                        window.scrollTo(currrentViewX ,currrentViewY);
                        
                    }
                    lastMouseX=event.x; 
                    lastMouseY=event.y;                
    }
    function BodyMouseUp(){
                lostCaptrue();
    }
                 
    function lostCaptrue(){
                    isBodyCapture=false;
                
    }
    var badTB=0;
    function drawLine(  tb1,  td1,tb2,td2)
    {
            var table1=document.getElementById("Tb" + tb1);
            var table2=document.getElementById("Tb" + tb2);
            if(table1==undefined || table2==undefined)
            {   badTB++;      
            return;}
            var  x1 = parseInt(table1.style.left);
            var  x2 = parseInt(table2.style.left);
            var y1= parseInt(table1.style.top) +18+td1*18; 
            var y2= parseInt(table2.style.top)+18+td2*18; 
            var w1=parseInt(table1.offsetWidth);
            var w2=parseInt(table2.offsetWidth);
            
            var x3;var x4;
            //如果两者差距不超过一个表格
            if(Math.abs(x1-x2)<Math.min(w1,w2))
            {
                //向后深出50;
                x1+=w1;
                x2+=w2;
                x3=x4=x1+50;
            }
            else
            {
                 //如果从左往右。
                if ((x1+w1) < x2)
                {
                    x1 += w1;
                }
                if ((x2+w2) < x1)
                {
                    x2 += w2;
                }
                        //计算两个中间点的位置;各8分之一处。
                x3 = parseInt((7 * x1 + x2) /8);
                x4 = parseInt((x1 + 7 * x2) / 8);
            }
             
            var HTML="<v:PolyLine filled='false' strokeWeight=2pt  Points='";
            HTML+=x1 + "," + y1 + " " ;       
            HTML+=x3 + "," + y1 + " " ;
            HTML+= x4 + "," + y2 + " " ;
            HTML+=x2 + "," + y2;    
            HTML+="' StrokeColor='"+rndColor()+"'>" ;
            HTML+="<v:stroke  EndArrow='Classic' StartArrow='Oval'   dashstyle='ShortDot' />" ;
            HTML+="</v:PolyLine>" ;
            //alert(HTML);
            document.body.insertAdjacentHTML("beforeEnd",HTML);
        }
     
         function rndColor(){
                    var r=Math.floor((Math.random()*256)).toString(16);
                    var g=Math.floor((Math.random()*256)).toString(16);
                    var b=Math.floor((Math.random()*256)).toString(16);
                    return( colorString="#"+r+g+b);
                }
                            
                function MouseDown(obj){
                window.status=event.srcElement.tagName;            
                Obj=obj;                            
                Obj.setCapture();
                Obj.l=event.x-Obj.style.pixelLeft;
                Obj.t=event.y-Obj.style.pixelTop;
                }
                function MouseMove(){
                
                if(Obj!=null &&  (event.srcElement.tagName=="TH" || event.srcElement.tagName=="TABLE" ) ){                            
                    Obj.style.left = event.x-Obj.l;
                    Obj.style.top = event.y-Obj.t;                
                    }
                }
                function MouseUp(){
                lostCaptrue();
                if(Obj!=null){                           
                    Obj.releaseCapture();
                    Obj=null;
                    }
                }
     
     <%=SBJs.ToString()%>
     
    alert(badTB);
                
              
        </script></body>
    </html>
      

  3.   

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Text;
    using Kuqu.Component;
    public partial class dataBaseInfo : BasePage
    {
        #region    protected string SQL1 = @"SELECT  O.object_id AS TableId,TableName=O.name,TableDesc= PTB.[value]  FROM sys.objects O LEFT JOIN sys.extended_properties PTB ON PTB.class=1 AND PTB.minor_id=0 AND O.object_id=PTB.major_id WHERE  O.type='U' ORDER BY TableName";    protected string SQL2 = @" 
    SELECT 
        TableName=CASE WHEN C.column_id=1 THEN O.name ELSE N'' END,
        TableDesc=ISNULL(CASE WHEN C.column_id=1 THEN PTB.[value] END,N''),
        Column_id=C.column_id,
        ColumnName=C.name,
        PrimaryKey=ISNULL(IDX.PrimaryKey,N''),
        [IDENTITY]=CASE WHEN C.is_identity=1 THEN N'√'ELSE N'' END,
        Computed=CASE WHEN C.is_computed=1 THEN N'√'ELSE N'' END,
        Type=T.name,
        Length=C.max_length,
        Precision=C.precision,
        Scale=C.scale,
        NullAble=CASE WHEN C.is_nullable=1 THEN N'√'ELSE N'' END,
        [Default]=ISNULL(D.definition,N''),
        ColumnDesc=ISNULL(PFD.[value],N''),
        IndexName=ISNULL(IDX.IndexName,N''),
        IndexSort=ISNULL(IDX.Sort,N''),
        Create_Date=O.Create_Date,
        Modify_Date=O.Modify_date
    FROM sys.columns C
        INNER JOIN sys.objects O
            ON C.[object_id]=O.[object_id]
                AND O.type='U'
                AND O.is_ms_shipped=0
        INNER JOIN sys.types T
            ON C.user_type_id=T.user_type_id
        LEFT JOIN sys.default_constraints D
            ON C.[object_id]=D.parent_object_id
                AND C.column_id=D.parent_column_id
                AND C.default_object_id=D.[object_id]
        LEFT JOIN sys.extended_properties PFD
            ON PFD.class=1 
                AND C.[object_id]=PFD.major_id 
                AND C.column_id=PFD.minor_id
                AND PFD.name='MS_Description'  -- 字段说明对应的描述名称(一个字段可以添加多个不同name的描述)
        LEFT JOIN sys.extended_properties PTB
            ON PTB.class=1 
                AND PTB.minor_id=0 
                AND C.[object_id]=PTB.major_id
                AND PTB.name='MS_Description'  -- 表说明对应的描述名称(一个表可以添加多个不同name的描述)     LEFT JOIN                       -- 索引及主键信息
        (
            SELECT 
                IDXC.[object_id],
                IDXC.column_id,
                Sort=CASE INDEXKEY_PROPERTY(IDXC.[object_id],IDXC.index_id,IDXC.index_column_id,'IsDescending')
                    WHEN 1 THEN 'DESC' WHEN 0 THEN 'ASC' ELSE '' END,
                PrimaryKey=CASE WHEN IDX.is_primary_key=1 THEN N'√'ELSE N'' END,
                IndexName=IDX.Name
            FROM sys.indexes IDX
            INNER JOIN sys.index_columns IDXC
                ON IDX.[object_id]=IDXC.[object_id]
                    AND IDX.index_id=IDXC.index_id
            LEFT JOIN sys.key_constraints KC
                ON IDX.[object_id]=KC.[parent_object_id]
                    AND IDX.index_id=KC.unique_index_id
            INNER JOIN  -- 对于一个列包含多个索引的情况,只显示第1个索引信息
            (
                SELECT [object_id], Column_id, index_id=MIN(index_id)
                FROM sys.index_columns
                GROUP BY [object_id], Column_id
            ) IDXCUQ
                ON IDXC.[object_id]=IDXCUQ.[object_id]
                    AND IDXC.Column_id=IDXCUQ.Column_id
                    AND IDXC.index_id=IDXCUQ.index_id
        ) IDX
            ON C.[object_id]=IDX.[object_id]
                AND C.column_id=IDX.column_id WHERE O.name=N'{0}'       -- 如果只查询指定表,加上此条件
    ORDER BY O.name,C.column_id
     ";
        #endregion
        protected List<Table> MyTables = new List<Table>();
        protected List<Relation> MyRelations = new List<Relation>();
        protected WorkPlace[,] MyWorkPlace;
        protected int WorkAreaNum;//工作区数量
        protected int WorkAreaWidth = 400;//工作区大小
        protected System.Text.StringBuilder SBJs = new StringBuilder();
        protected System.Text.StringBuilder SBTable = new StringBuilder();    protected void Page_Load(object sender, EventArgs e)
        {        //得到全部表信息,加入内存
            makeTables();
            //得到关系
            getCoreRelation();
            //放置表
            placeTables();        //显示表
            for (int i = 0; i < MyTables.Count; i++)
            {
                if (MyTables[i].WorkPlace != null)
                {
                    RenderTable(MyTables[i]);            }
            }
            //DrawLine( MyTables[7].findFiledByName("userid"), MyTables[0].PK);
            //写脚本
        }
        private void getCoreRelation()
        {
            //得到核心关系,把所有表按照外键关系多少排序。
            //得到表的外键集合PK_FKs        for (int i = 0; i < MyTables.Count; i++)
            {
                if (MyTables[i].PK != null)//如果包含主键
                {
                    //遍历所有字段
                    for (int j = 0; j < MyTables.Count; j++)
                    {
                        //排除掉自己表本身
                        if (MyTables[j].Id != MyTables[i].Id)
                        {
                            for (int k = 0; k < MyTables[j].Fileds.Count; k++)
                            {
                                //如果不是主键也不是ID字段   
                                if ((!MyTables[j].Fileds[k].IsID) && (!MyTables[j].Fileds[k].IsPK) && MyTables[j].Fileds[k].Name == MyTables[i].PK.Name)
                                {
                                    //加入主-外键集合
                                    MyTables[i].PK_FKs.Add(MyTables[j].Fileds[k]);
                                    MyTables[j].Fileds[k].FK = MyTables[i].PK;
                                    //加入关系集合。
                                    MyRelations.Add(new Relation(MyTables[j].Fileds[k], MyTables[i].PK));
                                }
                            }
                        }
                    }
                }        }
            //按照关系数量拓扑排序。
            MyTables.Sort(delegate(Table tb1, Table tb2)
            {
                return (tb2.PK_FKs.Count - tb1.PK_FKs.Count);
            }
                );
            //纪录顺序;
            for (int i = 0; i < MyTables.Count; i++)
            {
                MyTables[i].Order = i + 1;
                //便历工作区。
            }
            for (int i = 0; i < MyRelations.Count; i++)
            {
                ////drawLine(i,0,1,0);
                SBJs.Append("drawLine(");
                SBJs.Append(MyRelations[i].FromField.Table.Order);
                SBJs.Append(",");
                SBJs.Append(MyRelations[i].FromField.Id);
                SBJs.Append(",");
                SBJs.Append(MyRelations[i].ToField.Table.Order);
                SBJs.Append(",");
                SBJs.Append(MyRelations[i].ToField.Id);
                SBJs.Append(");\n");
            }    }
      

  4.   

      private void placeTables()
        {
            //放置表格,设置X,Y
            //得到单数个工作区数量,110-11-21
            WorkAreaNum = 2 * (Convert.ToInt32(Math.Sqrt(MyTables.Count))) - 1;        MyWorkPlace = new WorkPlace[WorkAreaNum, WorkAreaNum];
            for (int x = 0; x < WorkAreaNum; x++)
            {
                for (int y = 0; y < WorkAreaNum; y++)
                {
                    MyWorkPlace[x, y] = new WorkPlace(x, y);
                }
            }
            //找到中间那个区
            int centerArea = getHalfInt(1, WorkAreaNum);
            //从中间开始放,按照9宫格的位置
            //得到核心的9个
            WorkPlace[] WorkPlaceCenter9 = new WorkPlace[9];
            WorkPlaceCenter9[0] = new WorkPlace(centerArea, centerArea);
            WorkPlaceCenter9[1] = new WorkPlace(getHalfInt(centerArea, WorkAreaNum), centerArea);
            WorkPlaceCenter9[2] = new WorkPlace(getHalfInt(1, centerArea), centerArea);
            WorkPlaceCenter9[3] = new WorkPlace(centerArea, getHalfInt(1, centerArea));
            WorkPlaceCenter9[4] = new WorkPlace(centerArea, getHalfInt(centerArea, WorkAreaNum));
            WorkPlaceCenter9[5] = new WorkPlace(getHalfInt(centerArea, WorkAreaNum), getHalfInt(1, centerArea));
            WorkPlaceCenter9[6] = new WorkPlace(getHalfInt(1, centerArea), getHalfInt(1, centerArea));
            WorkPlaceCenter9[7] = new WorkPlace(getHalfInt(1, centerArea), getHalfInt(centerArea, WorkAreaNum));
            WorkPlaceCenter9[8] = new WorkPlace(getHalfInt(centerArea, WorkAreaNum), getHalfInt(centerArea, WorkAreaNum));
            //先放9个
            for (int i = 0; i < 9; i++)
            {
                if (MyTables.Count > i)
                {
                    placeTable(MyTables[i], WorkPlaceCenter9[i]);
                }
            }        for (int j = 0; j < 9; j++)
            {
                for (int k = 1; k < 3; k++)
                {
                    //寻找9个表每个中间表周围的空地   
                    List<WorkPlace> WorkPlaceAroundCenter = WorkPlaceCenter9[j].getNearWorkPlace(this.MyWorkPlace, k);
                    for (int i = 0; i < WorkPlaceAroundCenter.Count; i++)
                    {
                        //找到一个可以放的表。
                        Table t = WorkPlaceCenter9[0].Table.findTableWithoutPlace();
                        if (!string.IsNullOrEmpty(t.Name))
                        {
                            placeTable(t, WorkPlaceAroundCenter[i]);
                        }
                        else
                        {
                            break;
                        }                }
                }
            }    }    private void placeTable(Table tb, WorkPlace w)
        {
            //放一个表格
            tb.X = w.X * WorkAreaWidth;
            tb.Y = w.Y * WorkAreaWidth;
            w.Table = tb;
            tb.WorkPlace = w;    }
        private int getHalfInt(int min, int max)
        {
            if (max > min)
            {
                return (Convert.ToInt32(Math.Ceiling((double)((max + min) / 2))));
            }
            else
            {
                return 0;
            }
        }
        private void makeTables()
        {
            //得到全部表
            DataTable dt1 = SqlHelper.ExecuteDataset(DataHelper.ConnectionString, CommandType.Text, SQL1).Tables[0];        int tableId = 1;
            for (int i = 0; i < dt1.Rows.Count; i++)
            {
                string tableName = dt1.Rows[i]["TableName"].ToString();
                Table newTable = new Table(tableName);
                newTable.Id = tableId;
                newTable.Description = dt1.Rows[i]["TableDesc"].ToString();
                //得到字段
                string sql = string.Format(SQL2, tableName);
                DataTable dt2 = SqlHelper.ExecuteDataset(DataHelper.ConnectionString, CommandType.Text, sql).Tables[0];
                for (int j = 0; j < dt2.Rows.Count; j++)
                {
                    Filed newFiled = new Filed(dt2.Rows[j]);
                    if (newFiled.IsID || newFiled.IsPK)
                    {
                        newTable.PK = newFiled;
                    }
                    newTable.Fileds.Add(newFiled);
                    newFiled.Id = j;
                    newFiled.Table = newTable;            }
                newTable.Width = 250;
                //18 * n +26
                newTable.Height = newTable.Fileds.Count * 18 + 26;
                MyTables.Add(newTable);
                tableId++;
                //RenderTable( newTable);        }
            if (MyTables.Count < 1)
            {
                Response.Write("没有表,请重新设置数据库连接");
                Response.End();
            }    }
        private void RenderTable(Table tb)
        {        SBTable.Append(@"
     <TABLE id='Tb" + tb.Order + "' title='" + tb.Id + "'");
            string str = "  border='1' bordercolor='#999999'style='top:{0};left:{1}' onmousedown='MouseDown(this)' onmousemove='MouseMove()' onmouseup='MouseUp()'>";
            int X = tb.X;
            int Y = tb.Y;
            str = string.Format(str, Y, X);
            SBTable.Append(str);
            SBTable.Append(@"<TR ><th colspan=3 >");
            SBTable.Append("[" + tb.Id + "]" + tb.Name + "(" + tb.Description + tb.Fileds.Count + "个字段" + tb.PK_FKs.Count + "个关系");
            SBTable.Append(@"</th></TR>");
            for (int i = 0; i < tb.Fileds.Count; i++)
            {
                tb.Fileds[i].X = tb.X;
                tb.Fileds[i].Y = tb.Y + 26 + 18 * i - 9;
                RenderField(tb.Fileds[i]);
            }
            SBTable.Append(@"</TABLE>");
        }
        private void RenderField(Filed f)
        {
            SBTable.Append(@"<TR>");
            SBTable.Append(@"<TD style='padding-left:20px;");
            if (f.IsID || f.IsPK)
            {
                SBTable.Append("color:red;");
                //font-family:wingdings;
                SBTable.Append("' onmousedown='return(false);'>");
                SBTable.Append("<B>");
                SBTable.Append(f.Name);
                SBTable.Append("</B>");
            }
            else
            {
                SBTable.Append("' onmousedown='return(false);'>" + f.Name);
            }        SBTable.Append(@"</TD>");
            SBTable.Append(@"<TD>" + f.Type);
            SBTable.Append(@"</TD>");
            SBTable.Append(@"<TD>" + f.Description);
            SBTable.Append(@"</TD>");
            SBTable.Append(@"</TR>");    }}
      

  5.   

    public class Point
    {
        public Point(int x, int y) { this.X = x; this.Y = y; }
        public int X;
        public int Y;
    }
    public sealed class WorkPlace
    {
        public WorkPlace(int x, int y) { this.X = x; this.Y = y; }
        public int X;
        public int Y;
        public Table Table;
        public List<WorkPlace> getNearWorkPlace(WorkPlace[,] ws, int d)
        {
            //得到周围邻近的空地
            List<WorkPlace> re = new List<WorkPlace>();
            for (int x = this.X - d; x < this.X + d; x++)
            {
                for (int y = this.Y - d; y < this.Y + d; y++)
                {
                    if (x >= 0 && y >= 0 && x != this.X && y != this.Y && x < ws.GetUpperBound(1) && y < ws.GetUpperBound(1))
                    {
                        if (ws[x, y].Table == null)
                        {
                            re.Add(ws[x, y]);
                        }
                    }
                }
            }
            return (re);
        }
    }
    public sealed class Relation
    {
        public Relation(Filed fromField, Filed toField)
        {
            this.FromField = fromField;
            this.ToField = toField;    }
        public Filed FromField;
        public Filed ToField;}
    public sealed class Table
    {
        public Table(string name) { this.Name = name; }
        public int Id;
        public int Order;
        public int X;
        public int Y;
        public int Width;
        public int Height;
        public string Name;
        public Filed PK;
        public string Description;
        public WorkPlace WorkPlace;
        public List<Filed> Fileds = new List<Filed>();
        //我的主键有多少外键,XX表的xx字段
        public List<Filed> PK_FKs = new List<Filed>();
        public Table findTableWithoutPlace()
        {
            //找到一个没放置的表;
            Table re=new Table("");
            for (int i = 0; i < PK_FKs.Count; i++)
            {
                
                if (PK_FKs[i].Table.WorkPlace == null)
                {
                    re = PK_FKs[i].Table;
                    break;
                }
            }
            return re;
        }
        public List<Table> getTablesWithoutPlace()
        {
            List<Table> re = new List<Table>();
            for (int i = 0; i < PK_FKs.Count; i++)
            {            if (PK_FKs[i].Table.WorkPlace == null)
                {
                    re.Add(PK_FKs[i].Table);
                }
            }
            return re;
        }
        public Filed findFiledByName(string FiledName)
        {
            for (int i = 0; i < this.Fileds.Count; i++)
            {
                if (this.Fileds[i].Name.ToLower() == FiledName.ToLower())
                {
                    return this.Fileds[i];
                }
            }
            return null;
        }
    }
    public sealed class Filed
    {
        public Filed(DataRow row)
        {
            this.Name = row["ColumnName"].ToString();
            this.IsPK = (row["PrimaryKey"].ToString() == "√") ? true : false;
            this.IsID = (row["IDENTITY"].ToString() == "√") ? true : false;
            this.Type = row["Type"].ToString();
            this.Length = row["Length"].ToString();
            this.NullAble = (row["NullAble"].ToString() == "√") ? true : false;
            this.Default = row["Default"].ToString();
            this.Description = row["ColumnDesc"].ToString();    }    public string Name;
        public int Id;
        public bool IsPK;
        public bool IsID;
        public string Type;
        public string Length;
        public bool NullAble;
        public string Default;
        public string Description;
        public int X;
        public int Y;
        public Filed FK;
        public Table Table;
    }
      

  6.   

    To:byygyy你的设计要是我打分是不及格的,每个表都有问题,下边列有10个问题,其中7,8问题比较严重,涉及到了多对多关系的理解。jwwUser(教务网用户表) 1,缺少userId (int identity)student (学生表) 2,同上缺少studentId(int identity)
    2命名不规范:
    stuNo这样的缩写是不提倡的
    ZZMM 政治面貌,KSLB 考生类别 这样的命名是被鄙视的
    3,nationality  民族 这个一对多关系建议用一个表来存储名字字典,采用NationId关联
       政治面貌 也同上class(班级表)4,classID varchar行政班级ID  这个应该用int类型
    5,录取专业,学制,辅导员姓名,班主任姓名 这些一对多关系都应该另外建表,用ID字段关联department (院(系)/部表)
    6,departHeadName  系主任,应该用ID字段和老师表关联 course(课程表) 
    7,classID   行政班级ID 课程和班级是“多对多”的关系,应该加一个关系表(班级选课表2个主要字段,包含另外两个表的主健),这个字段不应该出现在这里。
    8,teacherID 任课教师和课程也是“多对多”关系,应该加一个关系表(教师任课表2个主要字段,包含另外两个表的主健),这个字段不应该出现在这里。score (成绩表) 
    9,关系字段都应该用int型teacher(教师表) 
    10,教师学历 ,教师职称 应该另外建表,用ID字段关联
      

  7.   

    4,树型结构,常见的两钟:父ID设计和001002编码设计。  
    例如:手机的经销商分为 省/市/县  5,“多态”结构和多对多略有不同,如果需求中某表字段多少类型有非常大的不确定性,可以采用3个表来完成:  
    这两种关系结构还是第一次看到,又孤陋寡闻了一次。lz
      

  8.   

    数据库设计多对多关系的几种形态
    前言:多对多关系至少需要3个表,我们把一个表叫做主表,一个叫做关系表,另外一个叫做字典表或者副表(字典表是纪录比较少,而且基本稳定的,例如:版块名称;副表是内容比较多,内容变化的,例如)。
    按照数据库的增删查改操作,多对多关系的查找都可以用inner join或者select * from 主表 where id in (select 主表id from 关系表)1,角色任命型特点:关系表两外键组合无重复纪录,关系表一般不需要时间字段和主键,有一个表是字典类型的表。
    界面特点:显示主表,用checkbox或多选select设置多选关系。
    例如:任命版主(用户表-关系表-版块名称表),角色权限控制等,用户是5个版块版主,只要关系表5行纪录就可以确立,关系表的两个外键具有联合主键性质。
    增加关系:如果没有组合纪录,insert之。
    删除关系:如果有组合纪录,删除之。2,集合分组型特点:同角色任命型类似,关系表两外键组合无重复纪录,关系表一般不需要时间字段和主键。区别是主副表都不是字典表,可能都很大不固定。
    界面特点:显示主表,用搜索代替简单的checkbox或多选select,或者一条一条的添加。
    例如:歌曲专集(专集表-关系表-歌曲表)。手机分组(分组表-关系表-手机表)。用户圈子(圈子表-关系表-用户表)。文章标签(文章表-关系表-标签表)
    增加关系:同版主任命型。
    删除关系:同版主任命型。
    3,明细帐型特点:关系表可以有重复纪录,关系表一般有时间字段,有主键,可能还有文字型的字段用来说明每次发生关系的原因(消费)。
    界面特点:显示关系表,用radio或下拉设置单选关系。
    例如:现金消费明细帐或订单(用户表-订单表-消费原因表),用户可能多次在同一事情上重复消费。积分变化纪录也属于这类。
    增加关系:不管有没有组合纪录,insert之,纪录时间。
    删除关系:根据关系表PK删除。
    4,评论回复型特点:同明细帐型关系表一般有时间字段,有主键,区别是重点在文字型的字段用来说明每次发生关系的内容(评论回复)。
    界面特点:回复文本框。
    例如:论坛回复(用户表-回复表-帖子表),用户可能多次在不同帖子上评论回复费。
    增加关系:不管有没有组合纪录,insert之,纪录时间和文字。
    删除关系:根据关系表(回复表)PK删除。5,站内短信型特点:主副表是同一个,关系表一般有时间字段,有主键,重点在关系表文字型的字段用来说明每次发生关系的内容(消息)或者其他标记位来表示文字已读状态时间等。
    界面特点:回复文本框。
    例如:站内短信(用户表-短信表-用户表),用户可能给用户群发或者单发,有标记位来表示文字已读状态时间等。
    增加关系:不管有没有组合纪录,insert之,纪录时间和文字。
    删除关系:根据关系表(回复表)PK删除。6,用户好友型特点:主副表是同一个,同集合分组型,关系表两外键组合无重复纪录,关系表一般不需要时间字段和主键。
    界面特点:同集合分组型,显示主表,用搜索代替简单的checkbox或多选select,或者一条一条的添加。
    例如:下载站点的文件,(文件表-关系表-文件表)可以被软件工具打开,软件工具本身也是一种文件,可以被下载。用户的好友,也是用户(用户表-好友关系表-用户表)
    增加关系:同版主任命型。
    删除关系:同版主任命型。
    7,未知属性型特点:在设计初期,主表的某些字段类型和名称是不确定的时候,关系表实际上是主表的可扩展字段,
    一个[主表](ID),
    一个[属性名称表](属性ID.属性名称),
    一个[属性值表],包括3个字段:
          属性值(属性Value varchar(500))
          主表ID
          属性ID这样可以作到最小冗余度。
    (和常见的多对多关系不同的是:值统一用varchar来存储,因为这类型的值一般不会用来计算)。比如:军队的数据库设计中有种物资叫做“战缴物资”,就是打仗的时候缴获的,军队自己都不知道这些物资有什么属性。 比如缴获的化学品有化学名,通用名,是否有辐射,计量单位,包装规格,数量等等,或者不是化学品是其他任何未知的东西。 
    这样东西就可以 某奇怪东西.属性集合["某某奇怪属性名"]="某某奇怪值";   
    某变态东西.属性集合["某某变态属性名"]="某某变态值";   这样存储。再比如:手机型号有几千种,除了共同属性外还有不同属性有几百个,属性名和值类型都不一样,有的手机有这属性,有的没有。
    对于这样的“多态”,我们就采用上面的设计结构。
    其效果相当于:某奇怪手机.属性集合["某某奇怪属性名"]="某某奇怪值";
    某变态手机.属性集合["某某变态属性名"]="某某变态值";界面特点:设置主表一行纪录的属性时候,要列出所有可能的属性名称,每个对应一个文本框。