SQL 同一属性的数据库多个值 - 最佳做法?
SQL Database multiple values for same attribute - Best practices?
我自己发现我的个人 table 的某些属性需要保存多个 values/choices,这不是一个好的 SQL 做法,所以我创建了第二个 table,像这样:
之前:
Person table
-ID (ex. 101)
-Name (ex. John)
-Accessories (ex. Scarf, Mask, Headband, etc..) - One person can have a combination of this
之后:
Person Table
-ID
-Name
PersonDetails Table
-PersonID (FK to Person table)
-Attribute type
-Attribute value
还有一个例子:
Person:
ID:13; Name: John Snow
PersonDetails:
PersonID: 13; Attribute type: Accessories; Attribute value: Scarf
PersonID: 13; Attribute type: Accessories; Attribute value: Mask
可以看到ID为13的人有围巾和面具。
这是一个好习惯吗?还有哪些其他方法可以最有效地做到这一点?
还有,如果有更新,Person with 13 没有围巾和面具,只有眼镜,有什么办法? (单独删除2个并插入一个新的?这意味着3个查询只有一个修改请求)
我认为这与 n:m 相关。您需要一个 table Person
持有身份证、姓名和其他人的详细信息。另一个 table Accessory
带有 ID、名称和更多配件的详细信息。第三个 table PersonAccessory
用于存储 PersonID 和 AccessoryID 对(这称为 映射 table)
工作示例(SQL-Server 语法)
CREATE TABLE Person(ID INT IDENTITY PRIMARY KEY,Name VARCHAR(100));
INSERT INTO Person VALUES('John'),('Jim');
CREATE TABLE Accessory(ID INT IDENTITY PRIMARY KEY,Name VARCHAR(100));
INSERT INTO Accessory VALUES('Scarf'),('Mask');
CREATE TABLE PersonAccessory(PersonID INT NOT NULL FOREIGN KEY REFERENCES Person(ID)
,AccessoryID INT NOT NULL FOREIGN KEY REFERENCES Accessory(ID));
INSERT INTO PersonAccessory VALUES(1,1),(2,1),(2,2);
SELECT p.Name
,a.Name
FROM PersonAccessory AS pa
INNER JOIN Person AS p ON pa.PersonID=p.ID
INNER JOIN Accessory AS a ON pa.AccessoryID=a.ID;
GO
--DROP TABLE PersonAccessory;
--DROP TABLE Accessory;
--DROP TABLE Person
结果
John Scarf
Jim Scarf
Jim Mask
这是一个工作示例。检查一下
;with tmp(Personid, name,AttributeType, DataItem, Data) as (
select Personid, name,'Accessories' AttributeType, LEFT(Accessories, CHARINDEX(',',Accessories +',')-1),
STUFF(Accessories , 1, CHARINDEX(',',Accessories +','), '')
from Person
union all
select Personid, name,'Accessories' AttributeType, LEFT(Data, CHARINDEX(',',Data+',')-1),
STUFF(Data, 1, CHARINDEX(',',Data+','), '')
from tmp
where Data > ''
)
select Personid, name,AttributeType, DataItem
from tmp
order by Personid
我自己发现我的个人 table 的某些属性需要保存多个 values/choices,这不是一个好的 SQL 做法,所以我创建了第二个 table,像这样:
之前:
Person table
-ID (ex. 101)
-Name (ex. John)
-Accessories (ex. Scarf, Mask, Headband, etc..) - One person can have a combination of this
之后:
Person Table
-ID
-Name
PersonDetails Table
-PersonID (FK to Person table)
-Attribute type
-Attribute value
还有一个例子:
Person:
ID:13; Name: John Snow
PersonDetails:
PersonID: 13; Attribute type: Accessories; Attribute value: Scarf
PersonID: 13; Attribute type: Accessories; Attribute value: Mask
可以看到ID为13的人有围巾和面具。
这是一个好习惯吗?还有哪些其他方法可以最有效地做到这一点?
还有,如果有更新,Person with 13 没有围巾和面具,只有眼镜,有什么办法? (单独删除2个并插入一个新的?这意味着3个查询只有一个修改请求)
我认为这与 n:m 相关。您需要一个 table Person
持有身份证、姓名和其他人的详细信息。另一个 table Accessory
带有 ID、名称和更多配件的详细信息。第三个 table PersonAccessory
用于存储 PersonID 和 AccessoryID 对(这称为 映射 table)
工作示例(SQL-Server 语法)
CREATE TABLE Person(ID INT IDENTITY PRIMARY KEY,Name VARCHAR(100));
INSERT INTO Person VALUES('John'),('Jim');
CREATE TABLE Accessory(ID INT IDENTITY PRIMARY KEY,Name VARCHAR(100));
INSERT INTO Accessory VALUES('Scarf'),('Mask');
CREATE TABLE PersonAccessory(PersonID INT NOT NULL FOREIGN KEY REFERENCES Person(ID)
,AccessoryID INT NOT NULL FOREIGN KEY REFERENCES Accessory(ID));
INSERT INTO PersonAccessory VALUES(1,1),(2,1),(2,2);
SELECT p.Name
,a.Name
FROM PersonAccessory AS pa
INNER JOIN Person AS p ON pa.PersonID=p.ID
INNER JOIN Accessory AS a ON pa.AccessoryID=a.ID;
GO
--DROP TABLE PersonAccessory;
--DROP TABLE Accessory;
--DROP TABLE Person
结果
John Scarf
Jim Scarf
Jim Mask
这是一个工作示例。检查一下
;with tmp(Personid, name,AttributeType, DataItem, Data) as (
select Personid, name,'Accessories' AttributeType, LEFT(Accessories, CHARINDEX(',',Accessories +',')-1),
STUFF(Accessories , 1, CHARINDEX(',',Accessories +','), '')
from Person
union all
select Personid, name,'Accessories' AttributeType, LEFT(Data, CHARINDEX(',',Data+',')-1),
STUFF(Data, 1, CHARINDEX(',',Data+','), '')
from tmp
where Data > ''
)
select Personid, name,AttributeType, DataItem
from tmp
order by Personid