【问题标题】:Combining rows of different tables into one row that can have a value将不同表的行组合成可以有值的一行
【发布时间】:2020-01-18 21:02:12
【问题描述】:

我正在尝试为以下问题找出数据模型:

我有一个energy sources

的列表
| name             |
|------------------|
| windmill         |
| oil              |
| water_powerplant |

attributes的列表:

| name    |
|---------|
| location|
| size    |
| oil_type|

属性列表values

| name    |attribute|
|---------|---------|
| offshore|location |
| onshore |location |
| big     |size     |
| small   |size     |
| crude   |oil_type |
| bunker  |oil_type |

以及energy sources可以拥有哪些attributes的列表:

| source          |attribute|
|-----------------|---------|
| windmill        |location |
| windmill        |size     |
| oil             |oil_type |
| water_powerplant|size     |

我现在需要的是一个表格,我可以在其中存储源值和属性值的每种组合的能量值。例如,我将如何存储small offshore windmill 的值?我能想到的最好的方法是提出一些自定义约定,将多个属性值组合成一个值......

| source          |attribute_values             |kwh_per_hour|
|-----------------|-----------------------------|------------|
| windmill        |size=small location=offshore |285         |

或为属性创建固定数量的列。然而,这会极大地限制灵活性。

| source          |att_1|att_val_1|attr_2  |attr_val_2|kwh_per_hour|
|-----------------|-----|---------|--------|----------|------------|
| windmill        |size |small    |location|offshore  |285         |

是否已经有一些好的解决方案来说明如何做到这一点?

【问题讨论】:

  • 这听起来很像EAV model。不,您绝对不应该使用固定数量的列并将其非规范化存储。
  • 您可以尝试使用jsonb 列作为属性。但是由于它被标记为 [relational database],听起来您实际上想使用外键对其进行建模以确保仅输入有效的组合?
  • jsonb 实际上可能是一个很好的解决方案。我并不担心有效的组合,因为它是一个小规模的项目,我自己输入数据。我会检查一下。谢谢!
  • 这取决于您的数据处理模式。对于 OLTP 案例,您可以使用 EAV 模型进行扩展。对于 OLAP,所有属性名称都成为维度。

标签: sql postgresql database-design


【解决方案1】:

entity-attribute-value model 中,您将拥有一个包含这三列的表,并且可以通过外键引用确保您的数据完整性:

CREATE TABLE powerplants (
  source text REFERENCES energy_sources(name),
  id integer,
  kwh_per_hour float,
  PRIMARY KEY (source, id)
);
CREATE TABLE powerplant_attribute_values (
  source text,
  id integer,
  attribute text,
  value text,
  PRIMARY KEY (source, id, attribute),
  FOREIGN KEY (source, id) REFERENCES powerplants,
  FOREIGN KEY (source, attribute) REFERENCES valid_attributes(source, attribute),
  FOREIGN KEY (attribute, value) REFERENCES valid_values(attribute, name)
);

valid_attributesvalid_values 表本身具有对 energy_sources(name)attributes(name) 的外键引用,您也可以使用 ENUMs)

要以漂亮的字符串查询您的植物,您可以使用

SELECT format("A %s %s with %sKW",
  (SELECT string_agg(eav.value, ' ')
    FROM powerplant_attribute_values eav
    WHERE eav.source = pp.source AND eav.id = pp.id
    -- ORDER BY eav.attribute for reproducible result?
  ),
  pp.source,
  pp.kwh_per_hour)
FROM powerplants pp;

或者,如果您不太关心数据库为您进行属性验证,只需使用jsonb 列:

CREATE TABLE powerplants (
  source text,
  attribute_values jsonb,
  kwh_per_hour float
);

SELECT format("A %s %s with %sKW",
  (SELECT string_agg(value, ' ')
    FROM jsonb_each_text(pp.attribute_values) AS kv(attribute, value)
  ),
  pp.source,
  pp.kwh_per_hour)
FROM powerplants pp;

【讨论】:

  • 非常感谢!我认为这可能会解决我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-30
  • 2021-08-17
  • 1970-01-01
  • 2022-09-23
相关资源
最近更新 更多