Запросы на основе набора именованных атрибутов / значений
Я работаю с набором пар "Атрибут / Значение" (на самом деле это немного больше, но я упрощаю ради этого вопроса). По сути, вы можете думать о таблицах так:
Entities (EntityID, AttributeName, AttributeValue) PK = EntityID, AttributeName
Targets (TargetID, AttributeName, AttributeValue) PK = TargetID, AttributeName
Как бы вы запросили с помощью SQL набор EntityID,TargetID, для которого у Entity есть все атрибуты для цели, а также соответствующее значение?
РЕДАКТИРОВАТЬ (DDL по запросу):
CREATE TABLE Entities(
EntityID INTEGER NOT NULL,
AttributeName CHAR(50) NOT NULL,
AttributeValue CHAR(50) NOT NULL,
CONSTRAINT EntitiesPK PRIMARY KEY (EntityID,AttributeName)
);
CREATE TABLE Targets(
TargetID INTEGER NOT NULL,
AttributeName CHAR(50) NOT NULL,
AttributeValue CHAR(50) NOT NULL,
CONSTRAINT TargetsPK PRIMARY KEY (TargetID,AttributeName)
);
4 ответа
Хорошо, я думаю, что после нескольких попыток и правок это решение наконец работает:
SELECT e1.EntityID, t1.TargetID
FROM Entities e1
JOIN Entities e2 ON (e1.EntityID = e2.EntityID)
CROSS JOIN Targets t1
LEFT OUTER JOIN Targets t2 ON (t1.TargetID = t2.TargetID
AND e2.AttributeName = t2.AttributeName
AND e2.AttributeValue = t2.AttributeValue)
GROUP BY e1.EntityID, t1.TargetID
HAVING COUNT(e2.AttributeValue) = COUNT(t2.AttributeValue);
Тестовые данные:
INSERT INTO Entities VALUES
-- exact same attributes, should match
(1, 'Foo1', '123'),
(1, 'Bar1', '123'),
-- same attributes but different values, should not match
(2, 'Foo2', '456'),
(2, 'Bar2', '456'),
-- more columns in Entities, should not match
(3, 'Foo3', '789'),
(3, 'Bar3', '789'),
(3, 'Baz3', '789'),
-- fewer columns in Entities, should match
(4, 'Foo4', '012'),
(4, 'Bar4', '012'),
-- same as case 1, should match Target 1
(5, 'Foo1', '123'),
(5, 'Bar1', '123'),
-- one attribute with different value, should not match
(6, 'A', 'one'),
(6, 'B', 'two');
INSERT INTO Targets VALUES
(1, 'Foo1', '123'),
(1, 'Bar1', '123'),
(2, 'Foo2', 'abc'),
(2, 'Bar2', 'abc'),
(3, 'Foo3', '789'),
(3, 'Bar3', '789'),
(4, 'Foo4', '012'),
(4, 'Bar4', '012'),
(4, 'Baz4', '012'),
(6, 'A', 'one'),
(6, 'B', 'twox');
Результаты теста:
+----------+----------+
| EntityID | TargetID |
+----------+----------+
| 1 | 1 |
| 4 | 4 |
| 5 | 1 |
+----------+----------+
Чтобы ответить на ваш комментарий, вот запрос с обратными таблицами:
SELECT e1.EntityID, t1.TargetID
FROM Targets t1
JOIN Targets t2 ON (t1.TargetID = t2.TargetID)
CROSS JOIN Entities e1
LEFT OUTER JOIN Entities e2 ON (e1.EntityID = e2.EntityID
AND t2.AttributeName = e2.AttributeName
AND t2.AttributeValue = e2.AttributeValue)
GROUP BY e1.EntityID, t1.TargetID
HAVING COUNT(e2.AttributeValue) = COUNT(t2.AttributeValue);
И вот вывод, учитывая те же входные данные выше.
+----------+----------+
| EntityID | TargetID |
+----------+----------+
| 1 | 1 |
| 3 | 3 |
| 5 | 1 |
+----------+----------+
SELECT *
FROM (
SELECT eo.total,
(
SELECT COUNT(*)
FROM Entities e, Targets t
WHERE e.EntityID = eo.EntityID
AND t.TargetID = e.EntityID
AND t.AttributeName = e.AttributeName
AND t.AttributeValue = e.AttributeValue
) AS equal
FROM (
SELECT e.EntityID, COUNT(*) as total
FROM Entities e
GROUP BY
e.EntityID
) eo
)
WHERE total = equal
Мне нравятся подобные вопросы, но я думаю, что не лишне смысла надеяться, что ОП предоставляет по крайней мере сценарии создания таблиц и, возможно, даже некоторые примеры данных.
Мне нравится слышать, кто согласен, а кто нет.
select distinct entityid,targetid
from entities ent
, targets tar
where not exists
( select attributename, AttributeValue
from targets tar2
where tar.targetid = tar2.targetid
minus
select attributename, AttributeValue
from entities ent2
where ent2.entityid = ent.entityid)
and not exists
( select attributename, AttributeValue
from entities ent2
where ent2.entityid = ent.entityid
minus
select attributename, AttributeValue
from targets tar2
where tar.targetid = tar2.targetid)
order by entityid,targetid
/
edit1:
Если в целевой таблице все в порядке, если в таблице сущностей нет совпадений, решение упрощается до:
select distinct entityid,targetid
from entities ent
, targets tar
where not exists
( select attributename, AttributeValue
from entities ent2
where ent2.entityid = ent.entityid
minus
select attributename, AttributeValue
from targets tar2
where tar.targetid = tar2.targetid)
order by entityid,targetid
/
редактировать 2:
Нелегко понять точные требования ФП.
Вот новое утверждение выбора. Я надеюсь, что он проверит все мои избранные утверждения, чтобы понять различия. Я надеюсь, что у него хорошие тестовые случаи и он знает, чего хочет.
select distinct entityid,targetid
from entities ent
, targets tar
where not exists
( select attributename, AttributeValue
from targets tar2
where tar.targetid = tar2.targetid
minus
select attributename, AttributeValue
from entities ent2
where ent2.entityid = ent.entityid)
order by entityid,targetid
/