仅当相关实体列包含特定值时才选择

时间:2014-03-21 15:26:29

标签: sql database select sql-server-2008-r2

我很难搞清楚SQL查询。 我想选择所有只有名称包含“Test”的许可证的公司。

Company                     License
|pkId|Name      |           |pkId|CompanyId|Name        |
-----------------           -----------------------------
|1   |Microsoft |           |1   |1        |License Test|
|2   |Apple     |           |2   |1        |Commercial  |
                            |3   |2        |License Test|
                            |4   |2        |License Test|

因此,在示例中,Microsoft有2个许可证。一次测试和一次商业广告 所以我不想要那家公司。 但所有Apples许可证都是测试许可证,所以我想选择Apple。

我在想的是:

SELECT Company.Name, COUNT(Company.Name) 
FROM Company INNER JOIN  License ON License.CompanyId = Company.pkId
WHERE License.Name LIKE '%Test%'
GROUP BY Company.Name

获取每个公司包含“Test”的行数,并将其与

进行比较
SELECT Company.Name, COUNT(Company.Name) 
FROM Company INNER JOIN  License ON License.CompanyId = Company.pkId
GROUP BY Company.Name

如果计数没有差异,我的公司只有测试许可证。 但我不知道如何将它们放在一起或者是否有更好的方法。

4 个答案:

答案 0 :(得分:0)

你想要的是从另一个集合中减去一个集合(也就是说,返回一个集合,但没有出现在另一个集合中的行),这就是EXCEPT(或Oracle中的MINUS)运算符所做的事情。此查询应该为您提供所需内容:

SELECT c.pkId, c.Name FROM Company c
INNER JOIN License l ON c.pkId=l.CompanyId
WHERE l.Name LIKE '%Test%'
EXCEPT
SELECT c.pkId, c.Name FROM Company c
INNER JOIN License l ON c.pkId=l.CompanyId
WHERE l.Name NOT LIKE '%Test%'

还有其他方法,但这应该是最直接的。

Sample SQL Fiddle

答案 1 :(得分:0)

如果它是SQL Server数据库,则尝试此操作: -

declare @company table (pkid int, name varchar(20))

insert into @company values (1,'microsoft')
insert into @company values (2,'apple')

declare @license table (pkid int, companyid int, name varchar(20))

insert into @license values (1,1,'license test')
insert into @license values (2,1,'comm')
insert into @license values (3,2,'license test')
insert into @license values (4,2,'license test')

select * from @company
select * from @license

select c.name
from @license l
inner join @company c
on c.pkid = l.companyid
where l.companyid not in
(select companyid from @license l1
where l1.name not like '%test%')
group by c.name

答案 2 :(得分:0)

如果所有公司都拥有至少一个许可证,则以下内容将起作用。它检查是否有任何非“测试”的许可证:

SELECT c.Name 
FROM Company c LEFT JOIN
     License l
     ON l.CompanyId = c.pkId AND l.Name NOT LIKE '%Test%'
WHERE l.CompanyId IS NULL
GROUP BY c.Name;

我认为,我更喜欢使用existsnot exists条款执行此操作:

select c.*
from company c
where exists (select 1
              from License l
              where l.CompanyId = c.pkId and l.Name LIKE '%Test%'
             ) and
      not exists (select 1
                  from License l
                  where l.CompanyId = c.pkId and l.Name not LIKE '%Test%'
                 );

这表示至少有一行“test”存在,没有没有。

或者,您可以将其标记为聚合查询中的having子句:

select c.Name 
from Company c inner join
     License l
     ON l.CompanyId = c.pkId
group by c.Name
having sum(case when l.Name like '%Test%' then 1 else 0 end) > 0 and
       sum(case when l.Name not like '%Test%' then 1 else 0 end) = 0;

答案 3 :(得分:0)

我已经复制了你的例子,第一个查询的结果是(2,1),第二个查询的结果是(2,2)。

SELECT COUNT(License.Name) AS counter, Company.Name
FROM Company INNER JOIN License ON License.CompanyId = Company.pkId
WHERE License.Name LIKE '%Test%'
GROUP BY Company.Name
HAVING counter = (SELECT MAX(counted) FROM (SELECT COUNT(l.Name) AS counted FROM License AS l WHERE l.name LIKE '%Test%' GROUP BY l.companyid) AS co)