检查一对多表中是否存在特定记录

时间:2017-07-07 11:09:03

标签: sql oracle

我有两个与这种结构有一对多关系的表:

meeting              meeting_person
+--+------------+    +--+----------+-----------+---------+
|id|meeting_type|    |id|meeting_id|person_type|person_id|
+--+------------+    +--+----------+-----------+---------+
|1 |          1 |    |1 |         1|          1|     100 |
|2 |          2 |    |2 |         1|          1|     101 |
+--+------------+    |3 |         1|          2|     102 |
                     |4 |         2|          3|     103 |
                     +--+----------+-----------+---------+

我想要做的是在插入之前检查特定记录是否存在,如果是,则警告用户 问题是,我需要检查是否存在与meeting_typeperson_id person_type的会议,以及所有人的会议。
例如,如果使用给定的数据,我想插入meet_type = 1的会议和这样的meeting_persons:

  • person_type = 1 and person_id = 100
  • person_type = 1 and person_id = 101
  • person_type = 2 and person_id = 102
    然后用户应该看到警告 但是,如果我想插入meeting_type = 1和session_persons:
  • 的会议
  • person_type = 1且person_id = 100
    然后用户不应该看到警告并且应该插入记录 我想不出办法,怎么检查这个。

3 个答案:

答案 0 :(得分:1)

如上所述,您需要使用触发器。我可能会建议更改数据结构以在meeting_type中包含meeting_person。是的,我知道这违反了正常形式。但如果你拥有它,你可以用一个简单的约束强制执行你的逻辑:

alter table meeting_person add constraint unq_meetingperson_person_type
    unique (person_id, meeting_type);

你怎么能安全地做到这一点?使用外键关系:

alter table meeting add constraint unq_meeting_type_id
    unique (type, id);

alter table meeting_person add constraint fk_meetingperson_meetingtype_id
    foreign key (meeting_type, id) references meeting(meeting_type, id);

这会为额外的(不必要的)索引带来额外的空间。它需要在meeting_type中包含一个额外的列。但它确实允许您在不使用触发器的情况下实现此逻辑。

答案 1 :(得分:1)

您想知道会议类型和相关人员的会议是否已存在。所以加入并计算:

select count(*)
from
(
  select m.id
  from meeting m
  join meeting_persion mp on mp.meeting_id = m.id
  where m.meeting_type = 1 
    and (mp.person_type, mp.person_id) in ((1,100),(1,101),(2,102))
  group by m.id
  having count(*) = 3
);

此查询会产生匹配会议数(0或更多)。

但是,如果您只对那些人的会议感兴趣,即没有其他人,那么您必须将人员标准从WHERE移至HAVING

select count(*)
from
(
  select m.id
  from meeting m
  join meeting_persion mp on mp.meeting_id = m.id
  where m.meeting_type = 1 
  group by m.id
  having count(case when (mp.person_type, mp.person_id) in ((1,100),(1,101),(2,102))
                    then 1 end) = 3
     and count(*) = 3
);

此查询会产生匹配会议的数量(0或1)。

答案 2 :(得分:0)

怎么样:

WITH MEETING(ID, MEETING_TYPE) AS
 (SELECT 1, 1 FROM DUAL
  UNION SELECT 2, 2 FROM DUAL),
MEETING_PERSON(ID, MEETING_ID, PERSON_TYPE, PERSON_ID) AS
 (SELECT 1, 1, 1, 100 FROM DUAL
  UNION SELECT 2, 1, 1, 101 FROM DUAL
  UNION SELECT 3, 1, 2, 102 FROM DUAL
  UNION SELECT 4, 2, 3, 103 FROM DUAL)
SELECT CASE WHEN COUNT(*) = 0 THEN 'Yes' ELSE 'No' END AS show_warning FROM meeting, meeting_person 
WHERE meeting.id = meeting_person.meeting_id
AND meeting.meeting_type = 1 
AND (person_type, person_id) NOT IN ( (1,100),(1,101),(2,102) ); -- comment this and uncomment second line for second example to check
--AND (person_type, person_id) NOT IN ( (1,100) );