9

是否有任何内置方式(我的意思是,不需要触发器和/或函数)为每个多列增加索引?

所以执行后:

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
4

2 回答 2

11

您可以将 simlpeSERIAL列添加到您的表中(它会给您订单),然后使用类似:

SELECT *, row_number() OVER (PARTITION BY month ORDER BY serial_column)
FROM table

这会给你你想要的结果。

如果您不需要对行进行排序,您可以尝试:

SELECT *, row_number() OVER (PARTITION BY month)
FROM table

详情在这里:row_number() OVER(...)

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)的组

serial_column2) 按( ORDER BY serial_column)的值对它们进行排序

`row_number() OVER3) 在每个组中使用步骤 2 ( )中的排序分配一个行号

输出是:

| 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 monthFirst of second montha 之前会改变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 示例在这里

于 2012-12-05T15:46:50.333 回答
5

如果您愿意在INSERT每次插入时将语句分成一行数据,那么您可以使用PostgreSQL 规则。下面的示例有点令人费解,因为规则似乎不允许您将写入重定向到关系本身。这通常是通过触发器来完成的。但是我们正在看看这是否可能在没有触发器的情况下实现,所以这里是:

--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";

笔记

  • 如果您需要在“表”上支持 DELETE/UPDATE,那么您也可以为每个操作添加规则。
  • 上面的BEGINandCOMMIT块用于表明即使在同一个事务中,只要每一行都分成自己的INSERT.
  • 您使用了一些保留字,例如tableand desc。一定要像你做的那样双引号,你不会有任何问题。

是sqlfiddle中的上述代码

于 2012-12-05T16:35:45.467 回答