Снежинка: создать значение поля по умолчанию, которое автоматически увеличивается для каждого первичного ключа, сбрасывается для каждого первичного ключа - PullRequest
0 голосов
/ 20 ноября 2018

Я хотел бы создать таблицу для размещения данных следующего типа

+--------+-----+----------+
| 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 - поле, которое я хочу автоматически увеличивать на 1 для каждогоpk row

Я пробовал следующее

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: строка ошибки 6 в позиции 52 агрегатных функций неразрешено как часть спецификации предложения по умолчанию.

Таким образом, я бы использовал свойство автоинкремента / идентичности примерно так:

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

, но, похоже, он не можетдля поддержки сброса по уникальному pk

ищите какие-либо предложения о том, как решить эту проблему, спасибо за любую помощь заранее

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

Я понятия не имею, почему у вас будет столбец с именем 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, когда вам нужно его использовать, а не хранить его в таблице.

0 голосов
/ 20 ноября 2018

Вы не можете сделать это с помощью метода 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, но она медленная: триггер срабатывает один раз для всех строк, тогда как функциявызывается в каждом ряду.

...