我想在我的Postgr数据库中代表一个团队. 这些团队总是有3名成员. 每个成员都有一个插槽,1代表领导者,2和3代表成员(也有助于显示良好顺序的成员) 每个成员都有一个等级,但只适用于这个团队(一个角色可以出现在不同的团队与不同的等级.

不过,我的一个特点是,我想 Select 所有具有不同组成的团队,这意味着,一个不同的领导者和成员.(有A、B和C成员的团队被视为与A、C和B成员相同,但与有C、A和B成员的团队不同)

在另一个特性中,我想 Select 所有包含完全相同组成的团队.

目前,我有三张桌子,

CREATE TABLE teams (
    "teamID" integer NOT NULL,
    "remainingTime" double precision NOT NULL,
    "desc" text NOT NULL,
    difficulty character varying NOT NULL
);

CREATE TABLE public.team_member (
    "teamID" smallint NOT NULL,
    "charID" smallint NOT NULL,
    "level" smallint NOT NULL,         /*can be from 1 to 5*/
    "slot" smallint DEFAULT 1 NOT NULL /*1, 2 or 3*/
);

CREATE TABLE public."character" (
    "charID" integer NOT NULL,
    name character varying NOT NULL,
    /* others attribute */
);

我现在的问题是,什么是编写与我的特性相对应的查询的最佳方式,即一个用于不同的团队,另一个用于具有相同组成的团队?

我想我可以 for each 团队创建一个表示其成员ID的数组,然后进行比较,但这不会在许多团队的性能方面造成问题吗?

有没有,也许,一个更优化的模式为这个案件? 我想创建一种表,在一行中存储其3个成员的ID,然后创建另一个表team_variation,存储3个成员的级别,以及相关的描述和时间,但我不知道这是否真的是一个好主意

final note, I use this database on a Javascript server so I can, if necessary, process the data received by a query that would have done a part of what I want

推荐答案

我提出这个关系设计:

CREATE TABLE team (
  team_id        int2 PRIMARY KEY
, remaining_time float NOT NULL  -- ?? use date/time type for temporal data!
, description    text NOT NULL   -- ? description?
, difficulty     text NOT NULL
);

CREATE TABLE person (
  pers_id   int2 PRIMARY KEY
, full_name text NOT NULL
  -- other attributes
);

CREATE TABLE team_member (
  team_id int2 NOT NULL REFERENCES team
, pers_id int2 NOT NULL REFERENCES person
, level   int2 NOT NULL CHECK (level BETWEEN 1::int2 AND 5::int2)  -- can be from 1 to 5
, slot    "char" NOT NULL DEFAULT 'l'::"char"
, pos     "char" NOT NULL DEFAULT '1'::"char"
, CONSTRAINT team_member_pkey PRIMARY KEY (team_id, pers_id)
  -- team can have 1 leader and 2 members
, CONSTRAINT chk_1lead_2members CHECK (slot = 'l' AND pos = '1'
                                    OR slot = 'm' AND pos IN ('2', '3'))
  -- 'l' ... leader, 'm' ... member
  -- leader must have pos '1', member must have pos '2' or '3'
, CONSTRAINT uni_team_slot_pos UNIQUE(slot, pos, team_id) INCLUDE (pers_id)
  -- team must have distinct persons; plus: provides useful index
);

-- add idx with reversed cols
CREATE UNIQUE INDEX team_member_pers_id_team_id ON team_member(pers_id, team_id);

fiddle

NOT NULLCHECKUNIQUEPRIMARY KEYFOREIGN KEY constraints的组合强制您的模型.你仍然可以输入不完整的团队(不是所有的插槽都被填满),允许中间状态.但这些都被排除在我下面的问题中.

team_member有充分的理由将限制因素和索引混合使用.参见:

我保留了你 Select 的100,但使表teamperson的PK匹配.不要在这里引入类型不匹配.我甚至将team_member行的最小有效负载大小保持在8个字节(也许这就是您优化的目的?)但是,除非你有good reasons,加上可以可靠地rule out overflow,否则用integer(甚至bigint)代替.不容易出错.只增加了很少的成本.

注意数据类型100用于廉价枚举.(可选)不要和charvarchar混淆!参见:

使用date/time data type表示日期/时间数据(列remaining_time).不是float.

不要在没有充分理由的情况下混合使用表名的单数和复数形式.

使用合法的、小写的、不带引号的标识符.特别是,要避免reserved words.请参见:

查询

已经对性能进行了一些优化.

Distinct teams

完整的团队名单.从骗局中挑选ID最小的队伍.不完整的团队.

SELECT DISTINCT ON (l.pers_id, m.m1, m.m2)
       team_id, l.pers_id AS lead, m.m1, m.m2
FROM   team_member l
JOIN  (
   SELECT team_id, min(pers_id) AS m1, max(pers_id) AS m2
   FROM   team_member m
   WHERE  m.slot = 'm'
   GROUP  BY 1
   HAVING count(*) = 2  -- exclude incomplete teams
   ) m USING (team_id)
WHERE  l.slot = 'l'
ORDER  BY l.pers_id, m.m1, m.m2, team_id;  -- pick team with smallest ID from dupes

参见:

Same teams

Select 与(1, 2, 3)1队相同的球队作为领先者.再次,排除不完整的团队.

SELECT team_id, l.pers_id AS lead, m1.pers_id AS m1, m2.pers_id AS m2
FROM   team_member l
JOIN   team_member m1 USING (team_id)
JOIN   team_member m2 USING (team_id)
WHERE  l.slot = 'l'
AND    l.pers_id = 1  -- lead
AND    m1.slot = 'm'
AND    m1.pers_id = LEAST (2,3)  -- member 1
AND    m2.slot = 'm'
AND    m2.pers_id = GREATEST (2,3)   -- member 2
ORDER  BY lead, m1, m2;

fiddle

Sql相关问答推荐

SQL Google Sheets:UNIQUE/DISTINCT和编码查询函数

SQL更新,在2个额外的表上使用内部连接

Postgres JSONB对象筛选

R中对Arrow duckdb工作流的SQL查询

如何根据特定的内部json元素值过滤postgres查询结果?

没有循环的SQL更新多个XML node 值

如何查找所提供日期范围的所有季度开始日期和结束日期

SQL到Snowflake-转换嵌套的SELECT(值

排除具有部分匹配条件的记录

使用 Oracle SQL Developer 将不同的列值转换为列会导致错误 ORA-01489

如何对 jsonb 中的字段执行求和,然后使用结果过滤查询的输出

计算 BigQuery 中列的中值差 - 分析函数不能作为聚合函数的参数

如何使用SELECT语句进行左连接,并根据右表中的特定值过滤结果?

使用其他表 SUM 的交换价格转换价格并获得 AVG

将有效数字作为 varchar 返回的 SQL 函数

每组跨行曲折?

在sql server中创建唯一标识符列

postgreSQL 中的循环表

如何比较同一张表中的行并进行相应更新

Oracle SQL 查询自行运行,但在包装到select count(*) from ()时失败