简体   繁体   中英

Select MAX value from column and corresponding value from another

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

表格+数据

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"

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

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