Как я могу объявить первичный ключ в 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 есть обсуждение аналогичной проблемы . Пожалуйста, проверьте это. Из того, что я пробовал и что работает для вашей ситуации:
Создайте функцию «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;
Создайте уникальный индекс для свойства 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";
Рекомендации