数据库设计,不同列中的许多不同项目(项目a可以在a或b列中)

时间:2015-01-08 20:49:04

标签: mysql sql sqlite

所以,由于设计我的数据库,我很头疼。我列出了含有其成分的饮料,即:

name:Tea
ingredient1:teabag
ingredient2:water

name:Glass of water
ingredient1:water

name:Frozen Tea
ingredient1:ice
ingredient2:teabag
ingredient3:water

因此,正如您所看到的,列数可能会有所不同,每种成分的索引也是如此。这是唯一的例子,数据库可能包含大约100-1000行。你能帮我讲一下设计我的数据库的最好(或者只是一个好的)方法吗?我必须能够根据一些或每种成分进行选择,因此选择成分=水的位置给出3个结果(但在这种情况下,我必须发送三次查询)。我真的不知道如何使它工作正常

2 个答案:

答案 0 :(得分:3)

我会创建三个表:DrinkIngredientDrinkIngredients。从那里你可以根据需要在DrinkIngredients表中插入许多成分。

以下是一个例子(请记住,这是为SQL Server编写的,因为我的MySQL知识有限)

Create Table Drink
(
    DrinkId     Int             Not Null Identity(1,1) Primary Key,
    Name        Varchar (30)    Null
)

Create Table Ingredient
(
    IngredientId    Int             Not Null Identity(1,1) Primary Key,
    Name            Varchar (30)    Null
)

Create Table DrinkIngredients
(
    DrinkId         Int     Not Null,
    IngredientId    Int     Not Null
)

Alter Table DrinkIngredients Add Constraint FK_DrinkIngredients_DrinkId Foreign Key (DrinkId) References Drink (DrinkId)
Alter Table DrinkIngredients Add Constraint FK_DrinkIngredients_IngredientId Foreign Key (IngredientId) References Ingredient (IngredientId)

Insert Drink (Name) Values ('Tea'), ('Glass of Water'), ('Frozen Tea')
Insert Ingredient (Name) Values ('Ice'), ('Tea bag'), ('Water')

Insert  DrinkIngredients (DrinkId, IngredientId)
Values  (1, 2), (1, 3), (2, 3), (3, 1), (3, 2), (3, 3)


Select  D.Name As Drink, I.Name As Ingredient
From    DrinkIngredients    DI
Join    Drink               D   On  D.DrinkId = DI.DrinkId
Join    Ingredient          I   On  I.IngredientId = DI.IngredientId
Where   D.Name = 'Frozen Tea'

您可以使用上一个查询查询数据,以查看指定名称的所有成分。这应该给你一个不错的起点。

答案 1 :(得分:2)

使用成分列的数据库设计称为非标准化。通常应避免使用非规范化的数据库结构,因为它们难以维护和使用。

请参阅:Database normalization

而是使用两个表:一个“饮料”表和一个“成分”表。

CREATE TABLE Drink (
    DrinkID INT AUTO_INCREMENT NOT NULL,
    Name VARCHAR(50) NOT NULL,
    PRIMARY KEY (DrinkID)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

CREATE TABLE Ingredient (
    IngredientID INT AUTO_INCREMENT NOT NULL,
    DrinkID INT NOT NULL,
    Name VARCHAR(50) NOT NULL,
    PRIMARY KEY (IngredientID),
    INDEX IX_DrinkID (DrinkID),
    FOREIGN KEY (DrinkID) 
        REFERENCES Drink(DrinkID)
        ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1

现在您插入如下记录:

INSERT INTO Drink (Name) VALUES ('Tea');
INSERT INTO Drink (Name) VALUES ('Glass of water');
INSERT INTO Drink (Name) VALUES ('Frozen Tea');

假设自动生成的DrinkID为1,2和3

INSERT INTO Ingredient (DrinkID, Name) VALUES (1, 'teabag');
INSERT INTO Ingredient (DrinkID, Name) VALUES (1, 'water');

INSERT INTO Ingredient (DrinkID, Name) VALUES (2, 'water');

INSERT INTO Ingredient (DrinkID, Name) VALUES (3, 'ice');
INSERT INTO Ingredient (DrinkID, Name) VALUES (3, 'teabag');
INSERT INTO Ingredient (DrinkID, Name) VALUES (3, 'water');

您可以返回含有水的饮料及其成分列表

SELECT
    d.Name AS drink_name, i.Name AS ingredient_name
FROM
    Drink d
    INNER JOIN Ingredient i
        ON d.DrinkID = i.DrinkID
WHERE
    i.Name = 'water'
ORDER BY
    d.Name, i.Name

或者,如果您只想要饮料

SELECT
    Name
FROM
    Drink
WHERE
    DrinkID IN (
        SELECT DrinkID
        FROM Ingredient
        WHERE Name = 'water'
    )
ORDER BY
    Name

您可以将子查询中的WHERE子句更改为WHERE Name IN ('water', 'wodka', 'ice')。这将返回所有含有至少一种这些成分的饮料。

如果您需要查找具有所有这些成分的饮品,您必须将查询更改为

SELECT
    d.Name
FROM
    Drink d
    INNER JOIN Ingredient i
        ON d.DrinkID = i.DrinkID
WHERE
    i.Name IN ('water', 'wodka', 'ice')
GROUP BY
    d.Name
HAVING
    COUNT(*) = 3
ORDER BY
    d.Name