简体   繁体   中英

SQL Server- Return Items Only When All Sub-Items Are Available

I have an Item table (denormalized for this example) containing a list of items, parts and whether the part is available. I want to return all the items for which all the parts are available. Each item can have a varying number of parts. For example:

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

The query should return the following:

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

Thanks in advance for any assistance.

Here is one trick using Max() Over() Window aggregate Function

SELECT Item,
       Part
FROM   (SELECT Max([Available])OVER(partition BY [Item]) m_av,*
        FROM   yourtable) a
WHERE  m_av = 'Y' 

or using Group By and Having clause

Using IN clause

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

using Exists

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

using NOT EXISTS

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

I'd start with rephrasing the requirement - you want to return the items that don't have any parts that are not available. Once you put it like that, it's easy to translate the requirement to SQL using the not exists operator:

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

U can use NOT IN OR NOT EXISTS to achieve this

NOT EXISTS

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

NOT IN

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

Using window function does a single table read.

MIN and MAX window function

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';

COUNT window function:

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;

I want to point out that the question in the text is: "I want to return all the items for which all the parts are available". However, your example results include the parts.

If the question is indeed that you want the items only, then you can use simple aggregation:

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

If you indeed want the detail on the parts as well, then the other answers provide that information.

I do like it problems lend themselves well to being solved by infrequently used language features:

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
) 

Here, we use a correlated subquery and the all keyword to see if all of the parts are available. My understanding is that, like exists , this will stop if it finds a counter-example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM