如何比较n:m作业?

时间:2014-02-02 12:29:07

标签: sql sql-server

我有两个表(entitykind)加上一个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应指示所选实体是否具有完全相同的分配类型。

我怎样才能做到这一点?

3 个答案:

答案 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 
)