Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql 在postgres的同一列中存储不同数据类型的合理方法?_Postgresql_Database Design - Fatal编程技术网

Postgresql 在postgres的同一列中存储不同数据类型的合理方法?

Postgresql 在postgres的同一列中存储不同数据类型的合理方法?,postgresql,database-design,Postgresql,Database Design,我目前正试图修改与postgres数据库交互的现有API。长话短说,它本质上是存储描述符/元数据,以确定实际“资产”(通常是某种文件)存储在服务器硬盘上的位置 目前,可以使用任意数量的未定义键值对(即uploadedBy、addedOn、assetType等)对这些“资产”进行“标记”。这些标记存储在一个单独的表中,其结构类似于以下内容: +---------------+----------------+-------------+ |assetid (text) | tagid(intege

我目前正试图修改与postgres数据库交互的现有API。长话短说,它本质上是存储描述符/元数据,以确定实际“资产”(通常是某种文件)存储在服务器硬盘上的位置

目前,可以使用任意数量的未定义键值对(即uploadedBy、addedOn、assetType等)对这些“资产”进行“标记”。这些标记存储在一个单独的表中,其结构类似于以下内容:

+---------------+----------------+-------------+
|assetid (text) | tagid(integer) | value(text) |
|---------------+----------------+-------------|
|someStringValue| 1234           | someValue   |
|---------------+----------------+-------------|
|aDiffStringKey | 1235           | a username  |
|---------------+----------------+-------------|
|aDiffStrKey    | 1236           | Nov 5, 1605 |
+---------------+----------------+-------------+
assetid和tagid是来自其他表的外键。想象一下表示文件的assetid和tagid/值对是描述符的映射

现在,API(Java)将所有这些键值对创建为映射对象。这包括时间戳/日期之类的内容。我们希望能够以某种方式为键值对中的值存储不同类型的数据。或者至少,在数据库中以不同的方式存储它,这样,如果需要,我们可以在这些标记上运行查询,检查日期范围等。但是,如果它们作为文本项存储在数据库中,那么我们必须a.)知道这实际上是一个日期/时间/时间戳项,b.)转换为我们可以实际运行此类查询的内容

到目前为止,我只想到了一个想法,没有完全改变数据库的布局太多

这是为了扩展assettag表(如上所示),为各种类型(数字、文本、时间戳)增加列,允许它们为null,然后在插入时检查相应的“键”,以确定它实际上是什么类型的数据。然而,我可以看到这种实现存在很多问题


有任何PostgreSQL忍者能就如何解决这个问题提供建议吗?我最近才回到数据库交互的最底层,所以我承认我有点生疏。

你基本上有两个选择:

选项1:稀疏表 每个数据类型有一列,但只使用与要存储的数据类型匹配的列。当然,这会导致大多数列为null——这是一种浪费空间的行为,但是纯粹主义者喜欢它,因为它具有很强的类型性。必须检查每一列是否为null以确定应用哪种数据类型有点笨拙。另外,如果您真的想要存储一个空值,那么您必须选择一个“意味着空值”的特定值,这就太糟糕了——更笨重了

选项2:两列-一列用于内容,一列用于类型 所有内容都可以表示为文本,因此有一个文本列作为值,另一个列(int或text)作为类型,这样应用程序代码就可以在正确的类型对象中恢复正确的值。好的方面是您没有太多的空值,但重要的是,您可以轻松地将类型扩展到SQL数据类型以外的应用程序类,方法是将它们的值存储为json,将它们的类型存储为类名


在我的职业生涯中,我曾多次使用选项2,它总是非常成功。

我不是PostgreSQL忍者,但我认为,与其使用两列(一列表示名称,一列表示类型),不如看:

用于在单个数据库中存储键/值对集的数据类型 PostgreSQL值。这在各种场景中都很有用,例如 具有许多很少检查的属性或半结构化属性的行 数据。键和值只是文本字符串


当然,您必须检查日期/时间戳如何转换成这种类型,并查看它是否适合您。

您可以使用两种不同的技术:

  • 如果每个tagid都有浮动类型
  • 为每个tagid assetid组合和实际数据表定义表和ID:

    maintable:
    +---------------+----------------+-----------------+---------------+
    |assetid (text) | tagid(integer) | tablename(text) | table_id(int) |
    |---------------+----------------+-----------------+---------------|
    |someStringValue| 1234           | tablebool       | 123           |
    |---------------+----------------+-----------------+---------------|
    |aDiffStringKey | 1235           | tablefloat      | 123           |
    |---------------+----------------+-----------------+---------------|
    |aDiffStrKey    | 1236           | tablestring     | 123           |
    +---------------+----------------+-----------------+---------------+
    
    tablebool
    +-------------+-------------+
    | id(integer) | value(bool) |
    |-------------+-------------|
    | 123         | False       |
    +-------------+-------------+
    
    tablefloat
    +-------------+--------------+
    | id(integer) | value(float) |
    |-------------+--------------|
    | 123         | 12.345       |
    +-------------+--------------+
    
    tablestring
    +-------------+---------------+
    | id(integer) | value(string) |
    |-------------+---------------|
    | 123         | 'text'        |
    +-------------+---------------+
    
  • 如果每个tagid都有固定的类型
  • 创建tagid描述表

    tag descriptors
    +---------------+----------------+-----------------+
    |assetid (text) | tagid(integer) | tablename(text) |
    |---------------+----------------+-----------------|
    |someStringValue| 1234           | tablebool       |
    |---------------+----------------+-----------------|
    |aDiffStringKey | 1235           | tablefloat      |
    |---------------+----------------+-----------------|
    |aDiffStrKey    | 1236           | tablestring     |
    +---------------+----------------+-----------------+
    
    和相应的数据表

    tablebool
    +-------------+----------------+-------------+
    | id(integer) | tagid(integer) | value(bool) |
    |-------------+----------------+-------------|
    | 123         | 1234           | False       |
    +-------------+----------------+-------------+
    
    tablefloat
    +-------------+----------------+--------------+
    | id(integer) | tagid(integer) | value(float) |
    |-------------+----------------+--------------|
    | 123         | 1235           | 12.345       |
    +-------------+----------------+--------------+
    
    tablestring
    +-------------+----------------+---------------+
    | id(integer) | tagid(integer) | value(string) |
    |-------------+----------------+---------------|
    | 123         | 1236           | 'text'        |
    +-------------+----------------+---------------+
    

    所有这些只是为了总的想法。您应该根据自己的需要对其进行调整。

    另一种选择,取决于您所做的工作,可能是只使用一个值列,但在值周围存储一些json

    这可能看起来像:

      {
        "type": "datetime",
        "value": "2019-05-31 13:51:36" 
      } 
    

    甚至可以更进一步,使用or列。

    这就是为什么使用EAV表存储数据通常是个坏主意的原因之一。我同意。我想,继承现有设计的乐趣。这就是生活,波西米亚人,谢谢你的回复。如果使用选项2,我将如何对类型标记为日期/时间类型的值执行日期范围类型查询?最好编写一个与postgresql等价的存储过程来执行这种类型的查询?将日期存储为1979年以来的天数,或者如果是时间戳类型,则存储为1970年以来的秒数。谷歌大纪元时间或unix时间。回答不错,正是这个问题,我有,不能决定。即使在我的例子中,“postgres”非常有效地存储“null”值,但您对单个类型的论证也让我信服。谢谢选项2中范围查询的索引如何?我认为使用选项2,你最终会得到一些你无法有效查询的东西。。。