是否有任何内置方式(我的意思是,不需要触发器和/或函数)每个多列都有递增索引?
执行完毕后:
INSERT INTO "table"
("month", "desc")
VALUES
(1, 'One thing')
, (1, 'Another thing')
, (1, 'Last task of the month')
, (2, 'Last task of the month')
, (2, 'Last task of the month')
, (3, 'First of third month')
我的表最终会像这样(注意“任务”栏):
month task desc
1 1 One thing
1 2 Another thing
1 3 Last task of the month
2 1 First of second month
2 2 Second and last of second month
3 1 First of third month
答案 0 :(得分:12)
您可以在表格中添加simlpe SERIAL
列(它会为您提供订单),然后使用以下内容:
SELECT *, row_number() OVER (PARTITION BY month ORDER BY serial_column)
FROM table
这将为您提供所需的结果。
如果您不需要订购行,可以尝试:
SELECT *, row_number() OVER (PARTITION BY month)
FROM table
UPD工作原理:
类型为SERIAL
的列本质上是“自动增量”字段。它会自动从序列中获取值。向表中插入行时,它们将如下所示:
| MONTH | SERIAL_COLUMN | DESCRIPTION |
-----------------------------------------------------------
| 1 | 1 | One thing |
| 1 | 2 | Another thing |
| 1 | 3 | Last task of the month |
| 2 | 4 | First of second month |
| 2 | 5 | Second and last of second month |
| 3 | 6 | First of third month |
关键是 - 每个下一个添加的行都比SERIAL_COLUMN
更高的值高于之前的所有行。
下一步。 row_number() OVER (PARTITION BY month ORDER BY serial_column)
确实:
1)将所有行分成相等month
(PARTITION BY month
)
2)按serial_column
(ORDER BY serial_column
)
3)在每个小组中使用步骤2中的排序(`row_number() OVER
)
输出结果为:
| MONTH | SERIAL_COLUMN | DESCRIPTION | ROW_NUMBER |
------------------------------------------------------------------------
| 1 | 1 | One thing | 1 |
| 1 | 2 | Another thing | 2 |
| 1 | 3 | Last task of the month | 3 |
| 2 | 4 | First of second month | 1 |
| 2 | 5 | Second and last of second month | 2 |
| 3 | 6 | First of third month | 1 |
要更改row_number()
的输出,您需要更改SERIAL_COLUMN
中的值。例如,在Second and last of second month
之前放置First of second month
会改变SERIAL_COLUMN
的值,如下所示:
UPDATE Table1
SET serial_column = 5
WHERE description = 'First of second month';
UPDATE Table1
SET serial_column = 4
WHERE description = 'Second and last of second month';
它将更改查询的输出:
| MONTH | SERIAL_COLUMN | DESCRIPTION | ROW_NUMBER |
------------------------------------------------------------------------
| 1 | 1 | One thing | 1 |
| 1 | 2 | Another thing | 2 |
| 1 | 3 | Last task of the month | 3 |
| 2 | 4 | Second and last of second month | 1 |
| 2 | 5 | First of second month | 2 |
| 3 | 6 | First of third month | 1 |
SERIAL_COLUMN
中的确切值无关紧要。 他们只在一个月内为任务设置订单。
我的SQLFiddle示例是here。
答案 1 :(得分:4)
如果您愿意将每个插入的INSERT
语句分成一行数据,则可以使用PostgreSQL rules。下面的示例有点令人费解,因为规则似乎不允许您将写入重定向到关系本身。这通常是通过触发器来完成的。但是我们看到这是否可能没有触发器,所以这里是:
--drop table table_data cascade;
CREATE TABLE table_data (
month integer not null,
task integer not null,
"desc" text
);
ALTER TABLE table_data add primary key (month, task);
CREATE VIEW "table" as
select month, task, "desc" from table_data;
CREATE OR REPLACE RULE calculate_task AS ON INSERT TO "table"
DO INSTEAD
INSERT into table_data (month, task, "desc")
VALUES (
NEW.month,
(select coalesce(max(task),0) + 1 from table_data where month = NEW.month),
NEW."desc");
BEGIN;
INSERT INTO "table" ("month", "desc") VALUES (1, 'One thing');
INSERT INTO "table" ("month", "desc") VALUES (1, 'Another thing');
INSERT INTO "table" ("month", "desc") VALUES (1, 'Last task of the month');
INSERT INTO "table" ("month", "desc") VALUES (2, 'Last task of the month');
INSERT INTO "table" ("month", "desc") VALUES (2, 'Last task of the month');
INSERT INTO "table" ("month", "desc") VALUES (3, 'First of third month');
COMMIT;
select * from "table";
备注的
BEGIN
和COMMIT
块用于表示即使在同一个事务中,只要每一行被分解为自己的INSERT
,此方法就会起作用。table
和desc
之类的reserved words。请务必双重引用它们,并且不会有任何问题。Here是sqlfiddle中的上述代码