当前位置: 首页 > 知识库问答 >
问题:

后记:实现单个收藏夹标志的最佳方式

萧懿轩
2023-03-14

我有这张桌子:

CREATE TABLE public.data_source__instrument (
  instrument_id int4 NOT NULL,
  data_source_id int4 NOT NULL,
  CONSTRAINT data_source__instrument__pk PRIMARY KEY (data_source_id, instrument_id)
);

为清楚起见,以下是我可能在此表中拥有的数据示例:

我希望能够为每种乐器设置一个最喜欢的数据源。我还希望每种乐器都有且只有一个最喜欢的数据源。

我想到的解决方案如下:

CREATE TABLE public.data_source__instrument (
  instrument_id int4 NOT NULL,
  data_source_id int4 NOT NULL,
  fav_data_source boolean NULL, -- ### new column ###
  CONSTRAINT data_source__instrument__pk PRIMARY KEY (data_source_id, instrument_id),
  CONSTRAINT fav_data_source UNIQUE (instrument_id,fav_data_source) -- ### new constraint ###
);

我选择用值<code>true<code>标记收藏夹,并将非收藏夹元组设置为<code>null<code>(因为唯一约束不影响null)。

解决方案将允许每个仪器在< code>fav_data_source列中最多有一个真值。

示例:

然而,我对这个解决方案并不完全满意。首先,它允许仪器没有最喜欢的数据源。此外,fav_data_source的值可以设置为false,这很混乱,也不是很有用(因为它不能很好地使用唯一约束)。

有更好的方法吗?我忽略了什么吗?

编辑:理想情况下,我更喜欢这个问题的简单解决方案,并避免使用数据库触发器等功能。

共有2个答案

鲁阳焱
2023-03-14

我选择用值<code>true</code>标记最喜欢的元组,并将非最喜欢的元组设置为<code>null</code>(因为唯一约束不影响<code>null</code>s),但<code>fav_data_source

有两种方法可以改善这种情况:

>

  • 在列上设置检查约束以防止<code>false</code>值:

    fav_data_source boolean NULL check (fav_data_source IS TRUE or fav_data_source IS NULL)
    

    使用部分索引仅检查具有真实值的行(另请参阅此处):

    fav_data_source boolean NOT NULL
    …
    CREATE UNIQUE INDEX unique_fav_data_source ON data_source__instrument (instrument_id) WHERE (fav_data_source);
    

    它允许仪器没有最喜欢的数据源。

    我认为,在没有触发器的关系数据库中,不可能表达这样一个“x中,至少有一个y必须存在”约束。(假设您仍然希望允许仪器完全没有任何数据源)。

    我还希望每种乐器都有且只有一个最喜欢的数据源。

    您可以考虑将收藏的数据源存储在仪器表本身中,作为不可为空的外来参考列。

    为避免重复,仅将非偏好的(附加/替代)数据源放入关系表,然后提供< code > data _ source _ _ instrument 作为视图:

    CREATE VIEW data_source__instrument(instrument_id, data_source_id, is_favourite) AS
    SELECT id, fav_data_source_id, true FROM instrument
    UNION ALL
    SELECT instrument_id, data_source_id, false FROM alternate_data_source__instrument;
    

    此方法的缺点是无法创建对视图的外键引用(如果需要这样做),并且更新数据源变得非常复杂。同样,这只适用于M:N关系,而不是1:N关系,你需要一种方法来断言一个工具最喜欢的源实际上属于该工具(技术上可以使用额外的外键,但真的很丑陋),并且你会引入循环引用,这只是一团糟。

  • 应嘉容
    2023-03-14

    您需要考虑数据库规范化和实体及其关系。具体说来

    • 在联合表中使用布尔标志违反了正常形式(对其他行的函数依赖)
    • “最喜欢的数据源”是一个独立的实体,您拥有的标志是在描述一个关系时描述一个实体

    我假设您有单独的仪器表和数据源表,为了简化您的问题,我们省略了这些表。

    这是你需要的:

    create table instrument
    (
      id serial primary key
    );
    
    create table data_source
    (
      id serial primary key
    );
    
    create table data_source__instrument
    (
      data_source_id integer references data_source on delete cascade on update cascade,
      instrument_id integer references instrument on delete cascade on update cascade,
      constraint data_source__instrument_pk primary key (data_source_id, instrument_id)
    );
    
    create table favourite_data_source
    (
      data_source_id integer not null,
      instrument_id integer not null unique,
      constraint favourite_data_source_pk foreign key (data_source_id, instrument_id) references data_source__instrument (data_source_id, instrument_id) on update cascade on delete cascade
    );
    
    

    现在来复制您的示例

    
    insert into instrument
    values (1),
      (2);
    
    insert into data_source
    values (1),
      (2),
      (3);
    
    insert into data_source__instrument (instrument_id, data_source_id)
    values (1, 1),
      (1, 2),
      (1, 3),
      (2, 2),
      (2, 3);
    
    insert into favourite_data_source (instrument_id, data_source_id)
    values (1, 1),
      (2, 3);
    

    使用此方案

    • 每个仪器可以有 0 到 1 个喜欢的数据源
    • 您必须单独插入喜欢的数据源数据
    • FK将通过级联和检查来处理完整性
     类似资料:
    • 在 Favorites(收藏夹)中,您可以储存并管理 Flow 网络服务中您最喜欢的训练目标。在手表上,您可以将您最喜爱的目标用作指定目标。有关更多信息,请参见 Flow 网络服务中的训练规划。 Flow 网络服务中的收藏数量没有限制。如果 Flow 网络服务中收藏夹数量超过 100 个,同步时列表中的前 100 个会传输到手表中。您可以通过拖放操作改变我的最爱的顺序。选择您要移动的“我的最爱”,

    • 在 Favorites(收藏夹)中,可在 Flow 网络服务及 Flow 移动应用中储存并管理您收藏的训练目标。您可以将收藏项目在手表上用作预定目标。有关更多信息,请参见在 Flow 网络服务中规划训练。 您可以看到手表中的数目上限。Flow 网络服务中的收藏项目数量没有限制。如果 Flow 网络服务中收藏项目数量超过 100 个,在同步时,列表中的前 100 个收藏项目会传输到手表中。您可以通过

    • 在 Favorites(我的最爱)中,您可以储存并管理 Polar Flow 网络服务中您最喜爱的训练目标。您的 M600 上的 Polar 应用程式一次最多可储存 20 个“我的最爱”。您可通过从Training(训练)下方的运动内容列表向左滑动来找到 Polar 应用程式上“我的最爱”训练目标。如果您的网络服务中收藏的最爱项目数量超过 20 个,则前 20 项会在同步时转移至 Polar 应用

    • 问题内容: 我最近获得了最新版本的Hibernate,并且注意到我的UserTypes现在有警告,关于不赞成AbstractStandardBasicType的nullSafeGet(ResultSet,String)和nullSafeSet(PreparedStatement,T,int)方法,建议使用带有SessionImplementor参数的相应方法。问题在于,当您实现UserType时,

    • 问题内容: 我出于好奇而问这个问题。基本上,我的问题是,当您拥有一个需要行条目才能具有像标志作用的事物的数据库时,最佳实践是什么?一个很好的例子就是堆栈溢出的标志,或者是bugzilla中的操作系统字段。可以为给定条目设置标志的任何子集。 通常,我会进行c和c ++的工作,因此我的直觉反应是将无符号整数字段用作一组可以翻转的位…但是我知道,由于多种原因,这不是一个好的解决方案。其中最明显的是可伸缩

    • 我正在Android应用程序中创建我的第一个Kotlin类。通常出于日志记录的目的,我有一个名为的常量。在Java中我要做的是: