我有两个表(entity
和kind
)加上一个n:m表(entity_kind
)。
CREATE TABLE
entity
(
entity_id INT
, name NVARCHAR(100)
, PRIMARY KEY(entity_id)
)
CREATE TABLE
kind
(
kind_id INT
, name NVARCHAR(100)
, PRIMARY KEY(kind_id)
)
CREATE TABLE
entity_kind
(
entity_id INT
, kind_id INT
, PRIMARY KEY(entity_id, kind_id)
)
测试数据:
INSERT INTO
entity
VALUES
(1, 'Entity A')
, (2, 'Entity B')
, (3, 'Entity C')
INSERT INTO
kind
VALUES
(1, 'Kind 1')
, (2, 'Kind 2')
, (3, 'Kind 3')
, (4, 'Kind 4')
INSERT INTO
entity_kind
VALUES
(1, 1)
, (1, 3)
, (2, 1)
, (2, 2)
, (3, 4)
到目前为止我的代码:
DECLARE
@selected_entities
TABLE
(
entity_id INT
)
DECLARE
@same_kinds BIT;
INSERT INTO
@selected_entities
VALUES
(1), (2)
-- Missing code here
SELECT
@same_kinds AS "same_kinds"
表var @selected_entities
填充了应该进行比较的实体。
逻辑变量@same_kinds
应指示所选实体是否具有完全相同的分配类型。
我怎样才能做到这一点?
答案 0 :(得分:1)
这是比较两套东西类型的问题。我要显示的查询给出了所有对以及一个标志。通过将前两个entity
表更改为要比较的ID表,可以轻松地合并比较子查询。
此查询包含几个部分。首先,它从实体表中生成所有实体对。这很重要,因为即使是没有与它们相关联的“种类”的实体也会如此。你想要一个标志,而不仅仅是那些匹配的列表。
然后逻辑的核心是在实体种类表上进行自联接,匹配“种类”。然后由两个实体汇总。结果是两个实体共享的种类数。
最后的逻辑是将此计数与每个实体的“种类”计数进行比较。如果所有这些计数都相同,则实体匹配。如果没有,他们不会。这种方法确实假设entity_kinds
中没有重复。
select e1.entity_id as e1, e2.entity_id as e2,
(case when count(ek1.entity_id) = max(ek1.numkinds) and
count(ek2.entity_id) = count(ek1.entity_id) and
max(ek1.numkinds) = max(ek2.numkinds)
then 1
else 0
end) as IsSame
from entity e1 join
entity e2
on e1.entity_id < e2.entity_id left outer join
(select ek.*, count(*) over (partition by entity_id) as numkinds
from entity_kind ek
) ek1
on e1.entity_id = ek1.entity_id left outer join
(select ek.*, count(*) over (partition by entity_id) as numkinds
from entity_kind ek
) ek2
on e2.entity_id = ek2.entity_id and
ek2.kind_id = ek1.kind_id
group by e1.entity_id, e2.entity_id;
SQL小提琴是here。
答案 1 :(得分:1)
您可以通过两项检查来执行此操作:首先,如果每个实体上的种类数不相同,则它们无法匹配。其次,如果计数相同,您只需要找到一种与任意其他实体的列表不匹配的类型(我只需要在比较列表中选择第一个实体)。在代码中:
DECLARE @firstEntity int = (SELECT TOP 1 entity_id from @selected_entities)
IF EXISTS(SELECT TOP 1 se.entity_id FROM @selected_entities se
INNER JOIN entity_kind ek ON ek.entity_id = se.entity_id
WHERE ek.kind_id NOT IN (SELECT kind_id from entity_kind where entity_id = @firstEntity)
OR ((SELECT COUNT(1) FROM entity_kind WHERE entity_id = ek.entity_id)
<> (SELECT COUNT(1) FROM entity_kind WHERE entity_id = @firstEntity)))
SET @same_kinds = 0
ELSE
SET @same_kinds = 1
答案 2 :(得分:0)
DECLARE @first_entity_id INT;
SET @first_entity_id = (SELECT TOP(1) se.entity_id FROM @selected_entities se);
DECLARE @dummyvar INT;
SELECT DISTINCT @dummyvar = COUNT(ek.kind_id)
FROM dbo.entity_kind ek
LEFT JOIN (
SELECT ek.kind_id
FROM dbo.entity_kind ek
WHERE ek.entity_id = @first_entity_id
) k ON ek.kind_id = k.kind_id
WHERE ek.entity_id IN (SELECT se.entity_id FROM @selected_entities se)
GROUP BY ek.entity_id;
SET @same_kinds = CASE WHEN @@ROWCOUNT = 1 THEN 1 ELSE 0 END;
SELECT @same_kinds AS [@same_kinds];
注意:@selected_entities
应该声明:
DECLARE
@selected_entities
TABLE
(
entity_id INT PRIMARY KEY
)