0

This might be a relatively simple question but I am struggling to work it out. I have three tables all listed below (owners, pets, petTypes) and trying to extract the following data all in one query. The first two are not difficult but the 3rd and 4th is where I am struggling.

Table data if you want to replicate: https://pastebin.com/veXHwcMc

The questions:

  1. Owner Id

  2. Owner name

  3. Owners oldest pet age
  4. Owners oldest pet type name
  5. Number of other pets

What I have tried

Selecting the oldest age SELECT MAX(age) FROM pets

Joining the tables to show both SELECT pets.ownerId, MAX(pets.age), petTypes.name FROM pets INNER JOIN petTypes ON pets.petTypeId = petTypes.id GROUP BY pets.ownerId;

But this is wrong. Because they are all showing cat when they should be showing the correct name for the oldest cat.

I cam upon this question: How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?

So I attempted: SELECT petTypes.id, petTypes.name FROM petTypes INNER JOIN (SELECT MAX(age) FROM pets GROUP BY ownerId) pets ON petTypes.id = pets.petTypeId;

But the error thrown is ERROR 1054 (42S22): Unknown column 'petTypes.id' in 'on clause'

Any help please

tables + the data

Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
Nouman
  • 585
  • 1
  • 11
  • 24
  • Can you get a set of data that has the oldest pet age for each owner? Can you then use this to join in the data to limit the results of what pets are displayed by joining on the owner and pet age? If you do what happens if multiple pets have the same age? do you want all of them or just 1? how do you determine which one? – xQbert Nov 10 '17 at 17:29
  • I am trying to retrieve the oldest pet AND name. If the owner has more than one which are the same age, I only need one (any one) – Nouman Nov 10 '17 at 17:31
  • If you're still struggling, see: [Why should I provide an MCVE for what seems to me to be a very simple SQL query?](https://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-a-very-simple-sql-query) – Strawberry Nov 10 '17 at 17:41

2 Answers2

0

Working demo:

SELECT O.ID, O.FirstName, O.LastName, P.Age, min(PT.Name) as TypeName, OPets.CntOfOtherPets
FROM Owners O
INNER JOIN (SELECT OwnerID, max(Age) MA, count(*)-1 as CntOfOtherPets 
            FROM Pets 
            GROUP BY OwnerID) OPets
 on  OPets.OwnerID = O.ID
INNER JOIN Pets P
 on P.Age = OPets.MA
and P.OwnerID = OPets.OwnerID
INNER JOIN PetTypes PT
 on P.PetTypeID = PT.ID
GROUP BY  O.ID, O.FirstName, O.LastName, P.Age, OPets.CntOfOtherPets ;

The derived table OPets gets a count of all the pets by owner less 1 since we know this represents the "other pet" count. The max pet age is returned via aggregation grouped owner. By joining this data set back to the pet set we get only the pets for that owner having the max age. We then join to petType to get the name of that type of pet (or pets if multiple share same max age).

Finally, group by all the fields except the PT.Name, and select the min(PetType.Name). That way if multiple animals exist with the same oldest age, we pick the one with TypeName with the earliest name alphabetically. This approach only works given the data being returned. If a petname, or the petID had to be returned, a different approach would be needed; but this was by far the simplest approach given the desired results (columns returned)

The count-1 seems a bit hackish since count(*) returns a count of all pets -1 simply subtracts out the 1 we know we had for the #5 requirement: Number of other pets. Even in the case of ties on age this # will be correct. Since count-1 will always be the "other pets"

xQbert
  • 34,733
  • 2
  • 41
  • 62
  • Thank you for such a lenghtly answer and explaining what you did but unfortunately, ERROR 1054 (42S22): Unknown column 'Opets.CntOfOtherPets' in 'field list'. I assumed 'CntOfOtherPEts' was capped by accident so changed it to 'CntOfOtherPets' but it did not fix the error – Nouman Nov 10 '17 at 17:52
  • I can't see what's wrong. I'll have to mockup the tables/data. I did add an "as" and ensured spelling consistency; but I don't know if that solved the issue. – xQbert Nov 10 '17 at 17:54
  • Added the table data if you want to test it: https://pastebin.com/veXHwcMc – Nouman Nov 10 '17 at 17:58
  • Odd it worked for me: http://sqlfiddle.com/#!9/cfd54/1/0 Note in my test I add the SO47228127 to table name so as to reduce risk of conflict with other user's tables – xQbert Nov 10 '17 at 18:05
  • That is weird. It worked for me as well :/ I must've have been typing the field names incorrectly on my side. Thank you for the thorough explanation on the -1. But can you explain min(PT.Name) to me please? – Nouman Nov 10 '17 at 18:14
  • Sure. it's how we handle the situation when multiple animals have the same max age. The only thing that's different in the desired returned results would be the type of animal (petType.Name). So by selecting the min(Pt.Name) and grouping by the other selected fields, we ensure we eliminate the multiple record situation if 2 different pets have the same oldest age for a owner. There would be other ways to handle this as well (say if you needed to return the pet ID, or if a pets actually had a pet name, needing to be returned, we may need to devise a different method) – xQbert Nov 10 '17 at 18:19
0

this should work, cant test it, but if owner has two or more pets same age it will show multiple records.

   Select ow.Firstname, ow.lastname ,petinfo.Age, petinfo.Name, petcount.TotalPets
    from #owners ow
    join ( Select age, p.petTypeId, p.OwnerID, pt.name From 
               (select max(age) as age, petTypeId, OwnerID 
                from #pets p 
                Group by  OwnerID,petTypeId
                ) p
            Join #petTypes pt on pt.ID = p.petTypeId
           ) petinfo 
           on petinfo.OwnerID = ow.id
    Join (
          Select Count(*) TotalPets, ownerID 
          From #Pets 
          group by OwnerID
          ) petcount
         on petcount.ownerID = ow.ID
  • Unknown column 'age' in 'field list'. Also all the tables name begin lowercase so I have changed where applicable. Not sure which table TypeId originates from? – Nouman Nov 10 '17 at 17:48