sql - PRIMARY KEY 实际上表示什么,我的表需要一个吗?

标签 sql database postgresql database-schema postgresql-9.3

我有一个带有用户表的 PostgreSQL 9.3 数据库,该表以保留大小写的格式存储用户名。所有查询都将不区分大小写,因此我应该有一个支持它的索引。此外,无论大小写如何,用户名都必须是唯一的。

这是我想出的:

forum=> \d users
                      Table "public.users"
   Column   |           Type           |       Modifiers
------------+--------------------------+------------------------
 name       | character varying(24)    | not null
Indexes:
    "users_lower_idx" UNIQUE, btree (lower(name::text))

以标准 SQL 语法表示:

CREATE TABLE users (
    name varchar(24) NOT NULL
);
CREATE UNIQUE INDEX "users_lower_idx" ON users (lower(name));

有了这个模式,我已经满足了我的所有约束,尽管没有主键。 SQL 标准不支持功能性主键,因此我无法提升索引:

forum=> ALTER TABLE users ADD PRIMARY KEY USING INDEX users_lower_idx;
ERROR:  index "users_lower_idx" contains expressions
LINE 1: ALTER TABLE users ADD PRIMARY KEY USING INDEX users_lower_id...
                              ^
DETAIL:  Cannot create a primary key or unique constraint using such an index.

但是,我已经有了 UNIQUE 约束,并且列已经标记为“NOT NULL”。如果我必须有一个主键,我可以像这样构建表:

CREATE TABLE users (
    name varchar(24) PRIMARY KEY
);
CREATE UNIQUE INDEX "users_lower_idx" ON users (lower(name));

但是我会有两个索引,这对我来说似乎是浪费和不必要的。那么,除了“UNIQUE NOT NULL”之外,PRIMARY KEY 对 postgres 意味着什么特别的东西吗?我是否因为没有 PRIMARY KEY 而错过了什么?

最佳答案

首先,实际上每个表都应该有一个主键。

citext

附加模块提供同名的数据类型。 “ci”不区分大小写。根据文档:

The citext module provides a case-insensitive character string type, citext. Essentially, it internally calls lower when comparing values. Otherwise, it behaves almost exactly like text.

它完全符合您描述的目的:

The citext data type allows you to eliminate calls to lower in SQL queries, and allows a primary key to be case-insensitive.

大胆强调我的。
请务必阅读 the manual about limitations第一的。每个数据库安装一次

CREATE EXTENSION citext;

文本

如果你不想走那条路,我建议你添加一个 serial作为代理主键

CREATE TABLE users (
    user_id serial PRIMARY KEY
  , username text  NOT NULL
);

我会使用 text 而不是 varchar(24)。如果您需要强制执行最大长度(稍后可能会更改),请使用 CHECK 约束。详情:

连同原始设计中的 UNIQUE 索引(没有类型转换):

CREATE UNIQUE INDEX users_username_lower_idx ON users (lower(username));

serial 的底层 integer 小而快,不必浪费时间在 lower() 或你的排序规则上数据库。这对于外键引用特别有用。与具有不同属性的一些自然主键相比,我更喜欢它。

这两种解决方案各有利弊。

关于sql - PRIMARY KEY 实际上表示什么,我的表需要一个吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25068868/

相关文章:

mysql - 如何将表格行数据显示为列?

sql - Apache Impala的迭代函数

python - SQLAlchemy,声明式,PostgreSQL : cannot create tables

postgresql - Postgres : Need distinct records count

mysql - 查询最多 'regular'消费客户的方法(AdventureWorks)

SQL select case when 子句

mysql - 从 mysql 表中的同一列获取计数?

java.lang.ClassCastException : org. apache.struts.validator.DynaValidatorForm 无法转换

php - 我有这个 Eloquent 文件,但我收到 undefined variable

sql - 是否可以在 Postgres 中仅在 2 列之一发生冲突时插入?