如何在SQL中处理多维矩阵?

时间:2019-01-22 09:33:02

标签: sql relational-database database-normalization

我正在学习使用关系数据库,因此我的知识有限。我有依赖于3个值的数据点:产品类型,年龄和x值。 因此,对于每种产品类型,都有一个矩阵,可以从中得出价格,该价格取决于年龄和价值x。

产品A

         Value x
Age                 0 - 18    19 - 64    65 - 150
         50          5.6        6.3        3.5
         100         5.2        3.5        6.3
         200         6.4        3.7       12.3
         500         3.9        2.3        5.5

其中有几种产品。 x的值和年龄范围可以变化。

因此,产品的价格取决于产品类型,年龄和价值x。我要如何设计表格以提供规范化?

谢谢。

3 个答案:

答案 0 :(得分:1)

这些关系可能适合:

Product(name,*ID*) 
Relation (*product_ID,type_id,age_id,value_X_id*) FK product_id references product, type references types, age references ages, valueX references value_2s
ValueXs(*ID*, value)
Type2(*ID*, value)
Age(*ID*, value)

这是完全规范化的形式,请注意:错开的qoutas强调了什么是ID

答案 1 :(得分:1)

您可能需要4张桌子。

1个存储最小和最大年龄(实际上每个范围)的表

1个存储值x的表

1个存储产品名称(和其他信息)的表

表年龄,值x和产品名称之间的

1个关系表,存储它们的外键和价格。该表的主键是确保所有数据唯一的FK的组成。

我实际上是在编写SQL代码为您提供示例。

模式(MySQL v5.7)

 if (cursor.getCount() > 0) {
                    while (cursor.moveToNext()) {
                        ContactModel cm = new ContactModel();
                        cm.id = cursor.getString(cursor.getColumnIndex(_ID));
                        cm.names = cursor.getString(cursor.getColumnIndex(DISPLAY_NAME));
                        int hasPhoneNumber = Integer.parseInt(cursor.getString(cursor.getColumnIndex(HAS_PHONE_NUMBER)));
                        if (hasPhoneNumber > 0) {

                            Cursor phoneCursor = contentResolver.query(PhoneCONTENT_URI, null, Phone_CONTACT_ID + " = ?", new String[]{cm.id}, null);


                            while (phoneCursor.moveToNext()) {
                                phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(NUMBER));
                                cm.mobileNumber = phoneNumber;


                            }
                            phoneCursor.close();
                            Map<String, Object> contactList = new HashMap<>();
                            contactList.put("contact_id", cm.id);
                            contactList.put("contact_name", cm.names);
                            contactList.put("contact_mobileNumber", cm.mobileNumber);
                            db.collection("Contacts").add(contactList);


                        }
                        contacts.add(cm);


                    }

                    cursor.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
            return contacts;

    }

查询#1

CREATE TABLE age
(
  id INT(6) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  min_age INT(6) NOT NULL,
  max_age INT(6) NOT NULL
);

CREATE TABLE valuex
(
  id INT(6) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  val INT(6) NOT NULL
);

CREATE TABLE products
(
  id INT(6) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(255) NOT NULL
);

CREATE TABLE pricing
(
  age_id INT(6) NOT NULL,
  valuex_id INT(6) NOT NULL,
  products_id INT(6) NOT NULL,
  price DECIMAL(5, 2) NOT NULL,
  FOREIGN KEY (age_id) REFERENCES age(id),
  FOREIGN KEY (valuex_id) REFERENCES valuex(id),
  FOREIGN KEY (products_id) REFERENCES products(id),
  PRIMARY KEY (age_id, valuex_id, products_id)
);

INSERT INTO age VALUES (default, 0, 18), (default, 19, 64 ), (default, 65, 150);
INSERT INTO valuex VALUES (default, 5), (default, 100), (default, 200), (default, 500);
INSERT INTO products VALUES (default, "A");

INSERT INTO pricing VALUES (1, 1, 1, 5.6),
                           (2, 2, 1, 6.3),
                           (3, 3, 1, 3.5),
                           (1, 4, 1, 5.2),
                           (2, 1, 1, 3.5),
                           (3, 2, 1, 6.3),
                           (1, 3, 1, 6.4),
                           (2, 4, 1, 3.7),
                           (3, 1, 1, 12.3),
                           (1, 2, 1, 3.9),
                           (2, 3, 1, 2.3),
                           (3, 4, 1, 5.5);

输出

-- Get all prices for product A
SELECT CONCAT(a.min_age, ' - ',a.max_age) AS "Age range",
       v.val AS "Value x",
       pr.name AS "Product Name",
       p.price AS "Price"
FROM pricing p
LEFT JOIN age a
ON a.id = p.age_id
LEFT JOIN valuex v
ON v.id = p.valuex_id
LEFT JOIN products pr
ON pr.id = p.products_id
WHERE pr.name = "A";

列出所有表格内容

查询#2

| Age range | Value x | Product Name | Price |
| --------- | ------- | ------------ | ----- |
| 0 - 18    | 5       | A            | 5.6   |
| 0 - 18    | 100     | A            | 3.9   |
| 0 - 18    | 200     | A            | 6.4   |
| 0 - 18    | 500     | A            | 5.2   |
| 19 - 64   | 5       | A            | 3.5   |
| 19 - 64   | 100     | A            | 6.3   |
| 19 - 64   | 200     | A            | 2.3   |
| 19 - 64   | 500     | A            | 3.7   |
| 65 - 150  | 5       | A            | 12.3  |
| 65 - 150  | 100     | A            | 6.3   |
| 65 - 150  | 200     | A            | 3.5   |
| 65 - 150  | 500     | A            | 5.5   |

查询#3

SELECT * FROM age;

| id  | min_age | max_age |
| --- | ------- | ------- |
| 1   | 0       | 18      |
| 2   | 19      | 64      |
| 3   | 65      | 150     |

查询#4

SELECT * FROM valuex;

| id  | val |
| --- | --- |
| 1   | 5   |
| 2   | 100 |
| 3   | 200 |
| 4   | 500 |

查询#5

SELECT * FROM products;

| id  | name |
| --- | ---- |
| 1   | A    |

View on DB Fiddle

答案 2 :(得分:1)

基本上,您将有4张桌子。

其中将包含产品信息,
一个将包含年龄范围(注意:这假设每种产品的年龄范围相同)
一个将包含X个值,
最后一个包含价格,使用外键指向我之前列出的3个表。

由于每种产品的年龄范围和x值不同,因此这些表中还应具有引用产品表的外键。

这样的事情应该让您入门:

create table products 
(
    id int primary key,
    name varchar(100)
    -- other product related details such as description ans stuff
);

create table ageRanges
(
    product_id int foreign key references products(id),
    id int primary key,
    name varchar(100)
)

create table X
(
    product_id int foreign key references products(id),
    value int
)

create table prices
(
    product_id int foreign key references products(id),
    ageRange_id int foreign key references ageRanges(id), 
    x_id int foreign key references X(id), 
    price numeric(10, 2)
)