按子集SQL分组记录

时间:2010-05-17 17:25:25

标签: sql ms-access

我有一个PermitHolders(PermitNum = PK)的数据库和每个许可证持有人的详细功能。在tblPermitDetails表中有2列

  1. PermitNum(外键)
  2. FacilityID(Facility表的整数外键查找)。
  3. permitee的许可证上可以包含1-29项,e.i。许可证50可以有船坞(FacID 4),铺设走道(FacID 17)挡土墙(FacID 20)等。我需要一个SQL过滤器/显示任何,所有PERMIT #s只有Facids 19,20,或28,不是那些加上“x”其他的......,只是那个子集。我已经为此工作了4天,有人请帮帮我吗?我已经发布到其他BB但没有收到任何有用的建议。

    正如Oded所说,这里有更多细节。  tblPermitDetails表没有PK。

    假设我们有Permitees 1 - 10;许可证1是John Doe,他有一个船坞(FacID 1),走道(FacID 4),浮标(FacID 7)和Underbrushing(FacID 19)......这些是许可证1的3条记录。许可证2是Sus Brown,她只有刷下(FacID 19),Permit 3是Steve Toni,他有一个船坞(FacID 1),一个走道(FacID 4),一个浮标(FacID 7)和一个挡土墙(FacID 20) 。许可证4是Jill Jack,她有Underbrushing(FacID 19)和挡土墙(FacID 20)。我可以继续,但我希望你跟着我。我想要一个SQL(用于MS Access),它只会向我显示Permits 2& 4因为他们有Facidss 19和amp; 20 [两者之一,或者一个或另一个],但不是许可证,如许可证1,#19,但也有4& 7。

    我希望有所帮助,如果没有,请说出来。

    哦,是的,我知道ie和eg之间的区别。因为我40多岁时已经写了超过3000页的考古领域报告和一篇硕士论文,但是我真的很沮丧,因为我在努力学习这篇SQL并且不太关心在咨询芝加哥风格手册之前提出的请求。求助。所以,不要对我的构图错误感到羞耻!谢谢你!

7 个答案:

答案 0 :(得分:1)

未经测试,但这样的事情怎么样?

SELECT DISTINCT p.PermitNum
           FROM tblPermitDetails p
          WHERE EXISTS
                (SELECT '+'
                   FROM tblFacility f
                  WHERE p.FacilityID = f.FacilityID
                    AND f.facilityID = 19 )
            AND EXISTS
                (SELECT '+'
                   FROM tblFacility f
                  WHERE p.FacilityID = f.FacilityID
                    AND f.facilityID = 20 )
            AND EXISTS
                (SELECT '+'
                   FROM tblFacility f
                  WHERE p.FacilityID = f.FacilityID
                    AND f.facilityID = 28 )
            AND NOT EXISTS
                (SELECT '+'
                   FROM tblFacility f
                  WHERE p.FacilityID = f.FacilityID
                    AND f.facilityID NOT IN (19,20,28) )

答案 1 :(得分:0)

SELECT PermitNum
FROM tblPermitDetails
WHERE FacilityID IN (19, 20, 28)
GROUP BY PermitNum
HAVING COUNT(PermitNum)=3

答案 2 :(得分:0)

我不确定你是否想要19,20,28或19,20,28中的任何一个......而且,这是未经测试的,但如果你想要任何解决方案它应该相当接近

Select
    allowed.PermitNum
from
    DetailedFacilties allowed
    join DetailedFacilities disallowed on allowed.PermitNum != disallowed.PermitNum
where
    allowed.FacilityID in (19, 20, 28)
    and disallowed.FacilityID not in (19, 20, 28)

答案 3 :(得分:0)

SELECT DISTINCT PermitNum FROM tblPermitDetails t1
 WHERE FacilityID IN (19, 20, 28)
   AND NOT EXISTS (SELECT 1 FROM tblPermitDetails t2
                    WHERE t2.PermitNum = t1.PermitNum
                      AND FacilityId NOT IN (19, 20, 28));

或者,在散文中,获取具有任何所请求的许可证号码的PermitNums列表,只要该PermitNum不存在不在请求列表中的行。

同一查询的更优化版本如下:

SELECT PermitNum FROM (SELECT DISTINCT PermitNum FROM tblPermitDetails
                        WHERE FacilityID IN (19, 20, 28)) AS t1
 WHERE NOT EXISTS (SELECT 1 FROM tblPermitDetails t2
                    WHERE t2.PermitNum = t1.PermitNum
                      AND FacilityID NOT IN (19, 20, 28));

阅读起来有点困难,但首先执行“DISTINCT”部分会涉及更少的“NOT EXISTS”子查询。

<强>更新

David-W-Fenton提到,出于优化原因,应避免使用NOT EXISTS。对于一个小表,这可能无关紧要,但如果你需要避免NOT EXISTS,你也可以使用COUNT(*)进行查询:

SELECT DISTINCT PermitNum FROM tblPermitDetails t1
 WHERE (SELECT COUNT(*) FROM tblPermitDetails t2
         WHERE t1.PermitNum = t2.PermitNum
           AND FacilityID IN (19, 20, 28))
       =
       (SELECT COUNT(*) FROM tblPermitDetails t3
         WHERE t1.PermitNum = t3.PermitNum)

答案 4 :(得分:0)

(未经测试)

怎么样?
select permitnum 
from tblPermitDetails t1
left outer join
(Select distinct permitnum from tblPermitDetails where facilityId not in (19, 20, or 28)) t2
on t1.permitnum=t2.permitnum
where t2.permitnum is null

即。我们发现所有与您的标准不符的许可证(他们至少有一个外面您列出的那些),然后我们通过左连接和标准找到剩下的所有许可证。

索引设置正确,这应该很快。

答案 5 :(得分:-1)

快速方法可能只是查看具有三个匹配(具有内部查询)的那些,然后在那些仅包括具有19,20和28的那些。

当然,这是一种蛮力方法,并不是很优雅。但它具有可理解的小优点。我能想到的任何方法都不容易定制到各种其他值集。

答案 6 :(得分:-1)

好吧,我起初似乎并不理解这个问题。所以,再次:

我将在这里重新创建Stacy的例子:

DECLARE @PermitHolders TABLE 
(PermitNum INT NOT NULL,
PermitHolder VARCHAR(20))

DECLARE @tblPermitDetails TABLE
(PermitNum INT,
FacilityID INT)

INSERT INTO @PermitHolders VALUES (1, 'John Doe')
INSERT INTO @PermitHolders VALUES (2, 'Sus Brown')
INSERT INTO @PermitHolders VALUES (3, 'Steve Toni')
INSERT INTO @PermitHolders VALUES (4, 'Jill Jack')

INSERT INTO @tblPermitDetails VALUES (1, 1)
INSERT INTO @tblPermitDetails VALUES (1, 4)
INSERT INTO @tblPermitDetails VALUES (1, 7)
INSERT INTO @tblPermitDetails VALUES (1, 19)
INSERT INTO @tblPermitDetails VALUES (2, 19)
INSERT INTO @tblPermitDetails VALUES (3, 1)
INSERT INTO @tblPermitDetails VALUES (3, 4)
INSERT INTO @tblPermitDetails VALUES (3, 7)
INSERT INTO @tblPermitDetails VALUES (3, 20)
INSERT INTO @tblPermitDetails VALUES (4, 19)
INSERT INTO @tblPermitDetails VALUES (4, 20)

这就是解决方案:

SELECT * FROM @PermitHolders 
WHERE (PermitNum IN (SELECT PermitNum FROM @tblPermitDetails WHERE FacilityID IN (19, 20, 28)))
AND (PermitNum NOT IN (SELECT PermitNum FROM @tblPermitDetails WHERE FacilityID NOT IN (19, 20, 28)))

我有一个观察: 你没有提到tblPermitDetails的任何PK。如果不存在,则可能不利于性能。我建议您使用PermitNum和FacilityID(复合键)创建PK,因为这将作为您的PK和预期查询的有用索引。