Snowflake:创建一个默认字段值,该值将为每个主键自动递增,并为每个主键重置

时间:2018-11-20 15:31:07

标签: sql database-design snowflake-datawarehouse

我想创建一个表来容纳以下类型的数据

+--------+-----+----------+
| pk     | ctr | name     |
+--------+-----+----------+
| fish   |  1  | herring  |
| mammal |  1  | dog      |
| mammal |  2  | cat      |
| mammal |  3  | whale    |
| bird   |  1  | penguin  |
| bird   |  2  | ostrich  |
+--------+----_+----------+

PK是主键字符串(100),不为null ctr是我要为每条pk行自动加1的字段

我尝试了以下

create or replace  table schema.animals (
pk string(100) not null primary key,
ctr integer not null default  ( select NVL(max(ctr),0) + 1 from schema.animals )
name string (1000) not null);

这产生了以下错误

  

SQL编译错误:第52位聚合函数的错误行6   不允许作为默认值规范的一部分   条款。

所以我应该像这样使用自动增量/ identity属性

AUTOINCREMENT | IDENTITY [ ( start_num , step_num ) | START num INCREMENT num ]

但它似乎无法支持每个唯一pk的重置

正在寻找有关如何解决此问题的建议,谢谢您的提前帮助

2 个答案:

答案 0 :(得分:0)

您无法使用IDENTITY方法执行此操作。建议的解决方案是使用INSTEAD OF触发器,该触发器将在ctr表的每一行上计算INSERTED的值。例如

CREATE TABLE dbo.animals ( 
   pk nvarchar(100) NOT NULL, 
   ctr integer NOT NULL,
   name nvarchar(1000) NOT NULL,
   CONSTRAINT PK_animals PRIMARY KEY (pk, ctr)
)
GO

CREATE TRIGGER dbo.animals_before_insert ON dbo.animals INSTEAD OF INSERT
AS
BEGIN
   SET NOCOUNT ON;
   INSERT INTO animals (pk, ctr, name)
   SELECT
      i.pk,
      (ROW_NUMBER() OVER (PARTITION BY i.pk ORDER BY i.name) + ISNULL(a.max_ctr, 0)) AS ctr,
      i.name
   FROM inserted i
        LEFT JOIN (SELECT pk, MAX(ctr) AS max_ctr FROM dbo.animals GROUP BY pk) a
           ON i.pk = a.pk;
END
GO

INSERT INTO dbo.animals (pk, name) VALUES 
('fish'   , 'herring'),
('mammal' , 'dog'),
('mammal' , 'cat'), 
('mammal' , 'whale'), 
('bird'   , 'pengui'),
('bird'   , 'ostrich');

SELECT * FROM dbo.animals;

结果

pk      ctr   name
------- ----- ---------
bird    1     ostrich
bird    2     pengui
fish    1     herring
mammal  1     cat
mammal  2     dog
mammal  3     whale

另一种方法是将标量用户定义的函数用作DEFAULT值,但它很慢:触发器在所有行上触发一次,而在每一行上调用该函数。

答案 1 :(得分:0)

我不知道您为什么会有一个名为pk的列,该列不是 主键。您不能(轻松)做您想做的事。我建议这样做:

create or replace table schema.animals (
    animal_id int identity primary key,
    name string(100) not null primary key,
);

create view schema.v_animals as
     select a.*, row_number() over (partition by name order by animal_id) as ctr
     from schema.animals a;

也就是说,在需要使用ctr而不是将其存储在表中时进行计算。