SQL Server-仅当所有子项都可用时才返回项

SQL Server-仅当所有子项都可用时才返回项,sql,sql-server,sql-server-2016,Sql,Sql Server,Sql Server 2016,我有一个Item表(在本例中是非规范化的),其中包含项目、部件以及部件是否可用的列表。我想退回所有零件可用的所有项目。每个项目可以有不同数量的零件。例如: Item Part Available A 1 Y A 2 N A 3 N B 1 Y B 4 Y C 2 N C 5 Y D 4 Y D 6

我有一个Item表(在本例中是非规范化的),其中包含项目、部件以及部件是否可用的列表。我想退回所有零件可用的所有项目。每个项目可以有不同数量的零件。例如:

Item   Part   Available
 A      1      Y
 A      2      N
 A      3      N
 B      1      Y
 B      4      Y
 C      2      N
 C      5      Y
 D      4      Y
 D      6      Y
 D      7      Y
查询应返回以下内容:

Item  Part
 B     1
 B     4
 D     4    
 D     6    
 D     7    

提前感谢您的帮助。

这里有一个技巧,使用
Max()Over()
窗口聚合函数

SELECT Item,
       Part
FROM   (SELECT Max([Available])OVER(partition BY [Item]) m_av,*
        FROM   yourtable) a
WHERE  m_av = 'Y' 
或者使用
分组依据
具有
子句

在子句中使用

SELECT Item,
       Part
FROM   yourtable
WHERE  Item IN (SELECT Item
                FROM   yourtable
                GROUP  BY Item
                HAVING Count(*) = Sum(Iif(Available = 'Y', 1, 0)))
使用
存在

SELECT Item,
       Part
FROM   yourtable A
WHERE  EXISTS (SELECT 1
               FROM   yourtable B
               WHERE  A.Item = B.Item
               HAVING Count(*) = Sum(Iif(Available = 'Y', 1, 0))) 
使用
不存在

SELECT Item,
       Part
FROM   yourtable A
WHERE  NOT EXISTS (SELECT *
                   FROM   yourtable B
                   WHERE  A.Item = B.Item
                          AND B.Available = 'N') 

下面是使用
Max()Over()的一个技巧

SELECT Item,
       Part
FROM   (SELECT Max([Available])OVER(partition BY [Item]) m_av,*
        FROM   yourtable) a
WHERE  m_av = 'Y' 
或者使用
分组依据
具有
子句

子句中使用

SELECT Item,
       Part
FROM   yourtable
WHERE  Item IN (SELECT Item
                FROM   yourtable
                GROUP  BY Item
                HAVING Count(*) = Sum(Iif(Available = 'Y', 1, 0)))
使用
存在

SELECT Item,
       Part
FROM   yourtable A
WHERE  EXISTS (SELECT 1
               FROM   yourtable B
               WHERE  A.Item = B.Item
               HAVING Count(*) = Sum(Iif(Available = 'Y', 1, 0))) 
使用
不存在

SELECT Item,
       Part
FROM   yourtable A
WHERE  NOT EXISTS (SELECT *
                   FROM   yourtable B
                   WHERE  A.Item = B.Item
                          AND B.Available = 'N') 

我首先要重新表述需求——您希望返回没有任何可用部件的项目。一旦您这样说,就可以使用
notexists
操作符轻松地将需求转换为SQL:

SELECT item, part
FROM   parts a
WHERE  NOT EXISTS (SELECT *
                   FROM   parts b
                   WHERE  a.item = b.item AND b.available = 'N')

我首先要重新表述需求——您希望返回没有任何可用部件的项目。一旦您这样说,就可以使用
notexists
操作符轻松地将需求转换为SQL:

SELECT item, part
FROM   parts a
WHERE  NOT EXISTS (SELECT *
                   FROM   parts b
                   WHERE  a.item = b.item AND b.available = 'N')

您可以使用
不在
不存在
来实现此目的

不存在

Select item, part 
from table as T1 
where not exists( select 1 from tbl where item = t1.item and available = 'N')
不在

Select item, part 
from table 
where item not in( select item from tbl where available = 'N')

您可以使用
不在
不存在
来实现此目的

不存在

Select item, part 
from table as T1 
where not exists( select 1 from tbl where item = t1.item and available = 'N')
不在

Select item, part 
from table 
where item not in( select item from tbl where available = 'N')

使用窗口函数读取单个表

MIN
MAX
窗口功能

select *
from (
    select
        t.*,
        max(available) over (partition by item) a,
        min(available) over (partition by item) b
    from your_table t
) t where a = b and a = 'Y';
计数
窗口功能:

select *
from (
    select
        t.*,
        count(*) over (partition by item) n1
        count(case when available = 'Y' then 1 end) over (partition by item) n2
    from your_table t
) t where n1 = n2;

使用窗口函数读取单个表

MIN
MAX
窗口功能

select *
from (
    select
        t.*,
        max(available) over (partition by item) a,
        min(available) over (partition by item) b
    from your_table t
) t where a = b and a = 'Y';
计数
窗口功能:

select *
from (
    select
        t.*,
        count(*) over (partition by item) n1
        count(case when available = 'Y' then 1 end) over (partition by item) n2
    from your_table t
) t where n1 = n2;

我想指出,文本中的问题是:“我想返回所有零件可用的所有项目”。但是,您的示例结果包括零件

如果问题确实是您只想要这些项目,那么您可以使用简单的聚合:

select item
from parts 
group by item
having min(available) = max(available) and min(available) = 'Y';

如果您确实希望了解零件的详细信息,那么其他答案将提供该信息。

我想指出,文本中的问题是:“我想返回所有零件可用的所有项目”。但是,您的示例结果包括零件

如果问题确实是您只想要这些项目,那么您可以使用简单的聚合:

select item
from parts 
group by item
having min(available) = max(available) and min(available) = 'Y';

如果您确实希望了解零件的详细信息,那么其他答案也会提供这些信息。

我很喜欢it问题,这些问题可以通过不常用的语言功能很好地解决:

with cte as (
    select * from (values
        ('A', 1, 'Y'),
        ('A', 2, 'N'),
        ('A', 3, 'N'),
        ('B', 1, 'Y'),
        ('B', 4, 'Y'),
        ('C', 2, 'N'),
        ('C', 5, 'Y'),
        ('D', 4, 'Y'),
        ('D', 6, 'Y'),
        ('D', 7, 'Y')
    ) as x(Item, Part, Available)
)
select *
into #t
from cte as c;

select *
from #t as c
where 'Y' = all (
    select Available
    from #t as a
    where c.Item = a.Item
) 

在这里,我们使用相关子查询和
all
关键字查看是否所有部分都可用。我的理解是,就像
存在一样
,如果找到反例,这将停止。

我确实喜欢it问题,因为它们很容易通过不常使用的语言功能来解决:

with cte as (
    select * from (values
        ('A', 1, 'Y'),
        ('A', 2, 'N'),
        ('A', 3, 'N'),
        ('B', 1, 'Y'),
        ('B', 4, 'Y'),
        ('C', 2, 'N'),
        ('C', 5, 'Y'),
        ('D', 4, 'Y'),
        ('D', 6, 'Y'),
        ('D', 7, 'Y')
    ) as x(Item, Part, Available)
)
select *
into #t
from cte as c;

select *
from #t as c
where 'Y' = all (
    select Available
    from #t as a
    where c.Item = a.Item
) 

在这里,我们使用相关子查询和
all
关键字查看是否所有部分都可用。我的理解是,就像
exists
,如果找到反例,这将停止。

第一个方法错误,当每个记录都
N
时,它将返回项第一个方法错误,当每个记录都
N
时,它将返回项