我有一个PostgreSQL数据库,它有一个表,主键应用于三列.根据数据库,密钥上有一个索引:
Indexes:
"full_log_pkey" PRIMARY KEY, btree (server_name, line_number, log_generation)
Run Code Online (Sandbox Code Playgroud)
然而一些简单的测试表明我有重复的键:
select count(*) from full_log;
count
----------
60644405
select count(*) from
(select distinct server_name,
line_number,
log_generation
from full_log) as foo;
count
----------
60636564
Run Code Online (Sandbox Code Playgroud)
显然,与行相比,不同的行(基于主键)更少.我的问题是,这怎么可能?
编辑:完整的表定义是这样的:
Table "public.full_log"
Column | Type | Modifiers
----------------+-----------------------------+-----------
activity | character(1) |
archivaldate | timestamp without time zone |
media_type | character varying(5) |
vsn | text |
archive_set | character varying(20) |
copy | smallint |
file_start | integer |
file_offset | integer |
fs_name …Run Code Online (Sandbox Code Playgroud) 要在第二个表中自动添加列以通过唯一索引将其绑定到第一个表,我有一个如下规则:
CREATE OR REPLACE RULE auto_insert AS ON INSERT TO user DO ALSO
INSERT INTO lastlogin (id) VALUES (NEW.userid);
Run Code Online (Sandbox Code Playgroud)
如果user.userid是一个整数,这可以正常工作.但是,如果它是一个序列(例如,类型为serial或bigserial),那么插入到lastlogin表中的是下一个序列id.所以这个命令:
INSERT INTO user (username) VALUES ('john');
Run Code Online (Sandbox Code Playgroud)
将列[1,'john',...]插入用户,但将列[2,...]插入lastlogin.以下2个解决方法确实有效,但第二个解决方案消耗了两倍的序列号,因为序列仍然是自动递增的:
CREATE OR REPLACE RULE auto_insert AS ON INSERT TO user DO ALSO
INSERT INTO lastlogin (id) VALUES (lastval());
CREATE OR REPLACE RULE auto_insert AS ON INSERT TO user DO ALSO
INSERT INTO lastlogin (id) VALUES (NEW.userid-1);
Run Code Online (Sandbox Code Playgroud)
不幸的是,如果我插入多行,解决方法不起作用:
INSERT INTO user (username) …Run Code Online (Sandbox Code Playgroud) 这是我的情况。我有一个带有一堆URL和与之关联的爬网日期的表。当我的程序处理URL时,我想插入一个具有爬网日期的新行。如果URL已经存在,我想将爬网日期更新为当前日期时间。对于MS SQL或Oracle,我可能为此使用MERGE命令。对于mySQL,我可能会使用ON DUPLICATE KEY UPDATE语法。
我可以在程序中执行多个查询,这些查询可能是线程安全的,也可能不是线程安全的。我可以编写一个具有各种IF ... ELSE逻辑的SQL函数。但是,为了试用以前从未使用过的Postgres功能,我正在考虑创建INSERT规则-类似于以下内容:
CREATE RULE Pages_Upsert AS ON INSERT TO Pages
WHERE EXISTS (SELECT 1 from Pages P where NEW.Url = P.Url)
DO INSTEAD
UPDATE Pages SET LastCrawled = NOW(), Html = NEW.Html WHERE Url = NEW.Url;
Run Code Online (Sandbox Code Playgroud)
这实际上看起来很棒。从“代码可读性”的角度来看,它可能会失去一些意义,因为初次查看我的代码的人必须神奇地知道此规则,但是我想可以通过良好的代码注释和文档来解决。
此想法是否还有其他缺点,或者“您的想法糟透了,您应该/ this /方式代替”注释?如果那很重要,我将使用PG 9.0。
更新:查询计划,因为有人想要它:)
"Insert (cost=2.79..2.81 rows=1 width=0)"
" InitPlan 1 (returns $0)"
" -> Seq Scan on pages p (cost=0.00..2.79 rows=1 width=0)"
" Filter: ('http://www.foo.com'::text = lower((url)::text))"
" -> Result (cost=0.00..0.01 rows=1 width=0)"
" …Run Code Online (Sandbox Code Playgroud) 这是场景:
create table a (
id serial primary key,
val text
);
create table b (
id serial primary key,
a_id integer references a(id)
);
create rule a_inserted as on insert to a do also insert into b (a_id) values (new.id);
Run Code Online (Sandbox Code Playgroud)
b我正在尝试创建一条引用a插入表时的记录a。但我得到的是new.idnull,因为它是从序列自动生成的。我也尝试了触发器AFTER插入FOR EACH ROW,但结果是相同的。有办法解决这个问题吗?