views:

183

answers:

5

I have a table called Item with columns ItemID (PK), ItemName, ExpectedSubItems and another table called SubItem with columns SubItemID (PK), ItemID (FK), SubItemName.

I want to return all rows from Item where the number of SubItems is different from ExpectedSubItems.

I tried to use something like:-

Select * From Item
Join SubItem on Item.ItemID = SubItem.ItemID
Where ExpectedSubItems = Count(SubItem.ItemID)

but that gives me the error:-

An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.

Any ideas from the SQL guru's out there?

+1  A: 

you need a sub-query

select *
  from item
  where expectedsubtems <> (
    select count(*)
      from subitem
      where subitem.itemid = item.itemid
    )
Ray
+1  A: 

try:

Select i.ItemId, i.ItemName
From Item i
  Left Join SubItem s
     On s.ItemID  = i.ItemId
Group By i.ItemId, i.ItemName, i.ExpectedSubItems
Having Count(*) <> i.ExpectedSubitems
Charles Bretana
You'll need a GROUP BY in there somewhere
Tom H.
gawd, this forum is quick...
Charles Bretana
Yeah, I'm convinced that some of the responders are actually bots that monitor the forum 24/7 and immediately answer any question :)
Tom H.
could be, I make mistake of using the forum itself as an editor, I post initial response and then edit it over and over until I'm happy with the result.. But lately it seems I get response comments so quickly... So initial answer has to be exactly right (cover ALL the caveats/edge cases etc.) or wait until i've finished editing beefore I post...
Charles Bretana
Actually I've bribed one of the `SO` staff members and they send me a notification when someone *starts* to type the question. `AJAX`, you know.
Quassnoi
@Quassnoi: I *knew* it!
OMG Ponies
+1  A: 

This should do it:

SELECT
     I.item_id,
     I.item_name,
     I.expected_subitems
FROM
     Items I
LEFT OUTER JOIN Sub_Items SI ON
     SI.item_id = I.item_id
GROUP BY
     I.item_id,
     I.item_name,
     I.expected_subitems
HAVING
     COUNT(SI.item_id) <> I.expected_subitems
Tom H.
Left Outer join to also get items with no subitems
Charles Bretana
Yeah, I was just trying to come up with any easy method that would avoid the problem of an expected_subitems of 1 with no actual subitems. The COUNT(*) would still end up coming back as 1 giving a false positive.
Tom H.
`Tom H.`: you could use `COUNT(SubItem.ID)` and a `LEFT JOIN`.
Quassnoi
Heh... I knew that as I was making the change I would come back to see that someone had left this comment. :)
Tom H.
+1  A: 
SELECT  ItemID
FROM    Item
JOIN    SubItem
ON      SubItem.ItemID = Item.ItemID
GROUP BY
        ItemID, ExpectedSubItems 
HAVING  ExpectedSubItems <> COUNT(*)

or this (so that you don't have to group by all Item fields and which also works for 0 expected subitems)

SELECT  Item.*
FROM    Item
CROSS APPLY
        (
        SELECT  NULL
        FROM    SubItem
        WHERE   SubItem.ItemID = Item.ItemID
        HAVING  ExpectedSubItems <> COUNT(*)
        ) S
Quassnoi
A: 

Try the following:

select *
  from Item I
  LEFT OUTER JOIN (select ItemID, COUNT(*) as ActualSubItemCount
                     from SubItem
                     group by ItemID) S
    ON (I.ItemID = S.ItemID)
  where (S.ItemID IS NULL AND NVL(I.ExpectedSubItems, 0) <> 0) OR
        I.ExpectedSubItems <> S.ActualSubItemCount;
Bob Jarvis