Как я могу объявить первичный ключ в Apache AGE

Здесь я создаю узел. Я хочу быть уверен, что только одинSoftwareEngineerможет существовать против одного. Как я могу достичь этой функциональности с помощью Apache AGE?

      test=# SELECT * FROM cypher('staff_details', $$
CREATE(e: SoftwareEngineer {
name: 'Muneeb',
SocialSecurityNumber: '12345',
date: pg_catalog.now()
}) RETURN e
$$) as (e agtype);

Когда я дважды запускаю приведенный выше запрос, я получил два созданных узла, которые содержат одни и те же данные.

      test=# Select * from cypher('staff_details', $$ MATCH (v:SoftwareEngineer) RETURN v $$) as (v agtype);

Дает:

       {"id": 1407374883553281, "label": "SoftwareEngineer", "properties": {"date": "2023-04-01T07:23:10.069163+05:00", "name"
: "Muneeb", "SocialSecurityNumber": "12345"}}::vertex
 {"id": 1407374883553282, "label": "SoftwareEngineer", "properties": {"date": "2023-04-01T07:28:39.245981+05:00", "name"
: "Muneeb", "SocialSecurityNumber": "12345"}}::vertex
(2 rows)

Хотя атрибут id отличается, но данные те же. Я хочу, чтобы Apache AGE ограничил создание двух узлов с одинаковымиSocialSecurityNumberнравитьсяPrimary Keyделает.

8 ответов

В Apache AGE можно добиться уникальности объекта недвижимостиSocialSecurityNumberс помощью триггеров . Сначала вам нужно будет создать триггерную функцию:

      CREATE OR REPLACE FUNCTION check_unique_ssn()
RETURNS TRIGGER AS $$
BEGIN
    IF EXISTS (
        SELECT 1 FROM SoftwareEngineer
        WHERE SocialSecurityNumber = NEW.SocialSecurityNumber
    ) THEN
        RAISE EXCEPTION 'A SoftwareEngineer with the same SocialSecurityNumber already exists';
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Затем вам нужно создать триггер и вставить в него значения:

      CREATE TRIGGER enforce_unique_ssn
BEFORE INSERT ON SoftwareEngineer
FOR EACH ROW
EXECUTE FUNCTION check_unique_ssn();

INSERT INTO SoftwareEngineer (name, SocialSecurityNumber, date)
VALUES ('Muneeb', '12345', NOW());

В Apache AGE (расширение Graph для PostgreSQL) вы можете обеспечить возможность существования только одного узла SoftwareEngineer для одного SocialSecurityNumber, используя ограничения и триггеры.

Ограничения . Вы можете создать ограничение уникальности для свойства SocialSecurityNumber метки SoftwareEngineer. Это обеспечит уникальность и предотвратит создание дубликатов узлов с одинаковым номером SocialSecurityNumber. Вот пример того, как создать ограничение уникальности с помощью Cypher:

      CREATE CONSTRAINT ON (se:SoftwareEngineer) ASSERT se.SocialSecurityNumber IS UNIQUE;

Триггеры . Вы также можете использовать триггеры для обеспечения соблюдения ограничения уникальности на уровне базы данных. Можно создать триггер, чтобы проверить, существует ли уже узел SoftwareEngineer с тем же номером SocialSecurityNumber, прежде чем вставлять новый узел. Вот пример того, как создать триггер с помощью Cypher:

      CREATE TRIGGER check_unique_social_security_number
BEFORE INSERT ON SoftwareEngineer
FOR EACH ROW
BEGIN
    IF EXISTS (
        MATCH (se:SoftwareEngineer {SocialSecurityNumber: NEW.SocialSecurityNumber})
        RETURN se
    )
    THEN
        RAISE EXCEPTION 'A SoftwareEngineer with the same SocialSecurityNumber already exists.';
    END IF;
END;

Если при наличии этих ограничений и триггеров вы попытаетесь вставить узел SoftwareEngineer с дубликатом SocialSecurityNumber, это приведет к возникновению исключения, предотвращающего создание дубликата узла.

Примечание. В приведенных примерах предполагается, что вы уже создали метку SoftwareEngineer и соответствующие свойства в своей схеме графа. Откорректируйте операторы Cypher соответствующим образом в зависимости от конструкции вашей схемы.

Используйте этот запрос:

      CREATE OR REPLACE FUNCTION create_pk(properties agtype)
RETURNS agtype AS
$BODY$
SELECT agtype_access_operator($1, '"SocialSecurityNumber"');
$BODY$
LANGUAGE sql IMMUTABLE;

CREATE UNIQUE INDEX person_pk_idx ON staff_details."SoftwareEngineer" 
(create_pk(properties));
      SELECT * FROM cypher('staff_details', $$
    MATCH (existing:SoftwareEngineer { SocialSecurityNumber: '12345' })
    RETURN existing
$$) as (existing agtype);

попробуйте этот запрос!

Создайте уникальный номер SocialSecurityNumber для всех, чтобы два узла Softwareengineer имели одинаковый идентификатор (SocialSecurityNumber).

      CREATE CONSTRAINT ON (n:SoftwareEngineer) ASSERT n.SocialSecurityNumber IS UNIQUE;

Убедитесь, что у вас есть уникальный индекс свойства SocialSecurityNumber. Если вы еще не создали индекс, используйте приведенный ниже шифрованный запрос, чтобы создать уникальный индекс:

      CREATE INDEX ON :SoftwareEngineer(SocialSecurityNumber);

Теперь используйте предложение слияния вместо создания. merge создаст узел, только если он еще не существует, на основе уникального индекса, который мы определили в свойстве SocialSecurityNumber. В приведенном ниже запросе слияние гарантирует, что будет создан только один узел SoftwareEngineer с номером «12345». Если этот узел уже существует, он вернет существующий узел вместо создания нового.

      SELECT * FROM cypher('staff_details', $$
MERGE (e:SoftwareEngineer {
    name: 'Muneeb',
    SocialSecurityNumber: '12345',
    date: pg_catalog.now()
}) RETURN e
$$) AS (e agtype);

На Github есть обсуждение аналогичной проблемы . Пожалуйста, проверьте это. Из того, что я пробовал и что работает для вашей ситуации:

  1. Создайте функцию «get_ssn», которая будет возвращать свойство SocialSecurityNumber из столбца «свойства».

            CREATE OR REPLACE FUNCTION get_ssn(properties agtype) 
    RETURNS agtype
    AS
    $BODY$
    select agtype_access_operator($1, '"SocialSecurityNumber"');
    $BODY$
    LANGUAGE sql
    IMMUTABLE;
    
  2. Создайте уникальный индекс для свойства SocialSecurityNumber.

    CREATE UNIQUE INDEX person_ssn_idx ON staff_details."SoftwareEngineer"(get_ssn(properties)) ;

Возможно, вам придется сначала создать метку вершины (если она еще не создана) перед выполнением приведенного выше запроса CREATE INDEX как

SELECT * FROM create_vlabel('staff_details', 'SoftwareEngineer');

Теперь, когда вы пытаетесь добавить еще один узел с тем же номером SocialSecurityNumber, вы получаете ошибку:

ERROR: duplicate key value violates unique constraint "person_ssn_idx" DETAIL: Key (get_ssn(properties))=("12345") already exists.

Вы можете добиться этого, используя MERGE, как показано ниже, при условии, чтоSocialSecurityNumberявляется первичным ключом .

      SELECT * FROM cypher('staff_details', $$
    MERGE (e: SoftwareEngineer {
        SocialSecurityNumber: '12345'
    })
    SET e.name = 'Muneeb', e.date = COALESCE(e.date, timestamp())
    RETURN e
$$) as (e agtype);

SELECT * FROM staff_details."SoftwareEngineer";

Рекомендации

Другие вопросы по тегам