TB16 är nöjd med hjälpen!
TB16 151
Postad: 17 maj 2019

PostgreSQL - Räkna alla personer som är lika gamla och lista resultaten efter ålder

Uppgift:

For this challenge you need to create a simple GROUP BY statement, you want to group all the people by their age and count the people who have the same age.

people table schema

  • id
  • name
  • age

select table schema
age [group by]
people_count (people count)

NOTE: Your solution should use pure SQL. Ruby is used within the test cases to do the actual testing.

Källa: https://www.codewars.com/kata/sql-basics-simple-group-by/train/sql

Mitt försök att lösa uppgiften (PostgreSQL 9.6):

select age, count(age) as people_count from people
group by age
having age = people.age

Output:
Fråga: 
Enligt felmeddelandet så skiljer sig mina utvärden med förväntade utvärden. Jag har kikat på förväntade utvärden, och jag kan inte se att några av mina utvärden skiljer sig åt. Någon som vet vad jag gjort för fel? 

Laguna 4970
Postad: 17 maj 2019

Hur ser de förväntade utvärdena ut?

Behövs förresten "having age = people.age"?

TB16 151
Postad: 17 maj 2019
Laguna skrev:

Hur ser de förväntade utvärdena ut?

Behövs förresten "having age = people.age"?

Behöver jag inte använda having för att jämföra de personer som är lika gamla? 

Här följer de förväntade resultaten tillsammans med mina resultat:


Test Failed expected: [{:age=>8, :people_count=>12}, {:age=>4, :people_count=>15}, {:age=>1, :people_count=>9}, {:age=>5, :..._count=>9}, {:age=>6, :people_count=>8}, {:age=>2, :people_count=>12}, {:age=>7, :people_count=>10}] got: [{:age=>0, :people_count=>4}, {:age=>1, :people_count=>9}, {:age=>2, :people_count=>12}, {:age=>3, :p..._count=>8}, {:age=>7, :people_count=>10}, {:age=>8, :people_count=>12}, {:age=>9, :people_count=>9}] (compared using ==) Diff: @@ -1,11 +1,11 @@ -[{:age=>8, :people_count=>12}, - {:age=>4, :people_count=>15}, +[{:age=>0, :people_count=>4}, {:age=>1, :people_count=>9}, - {:age=>5, :people_count=>12}, + {:age=>2, :people_count=>12}, {:age=>3, :people_count=>9}, - {:age=>0, :people_count=>4}, - {:age=>9, :people_count=>9}, + {:age=>4, :people_count=>15}, + {:age=>5, :people_count=>12}, {:age=>6, :people_count=>8}, - {:age=>2, :people_count=>12}, - {:age=>7, :people_count=>10}] + {:age=>7, :people_count=>10}, + {:age=>8, :people_count=>12}, + {:age=>9, :people_count=>9}]

Laguna 4970
Postad: 17 maj 2019

Jag tycker GROUP borde räcka. Men behövs det så behövs det.

Det du får och det som förväntas är inte alls lika. Det är lika många rader, men vissa finns bara i den ena listan.

TB16 151
Postad: 19 maj 2019
Laguna skrev:

Jag tycker GROUP borde räcka. Men behövs det så behövs det.

Det du får och det som förväntas är inte alls lika. Det är lika många rader, men vissa finns bara i den ena listan.

Koden klarade alla test när jag tog bort "having age = people.age" :)

Är det så att GROUP BY körs före själva uträkningen i SELECT?

Laguna 4970
Postad: 19 maj 2019
TB16 skrev:
Laguna skrev:

Jag tycker GROUP borde räcka. Men behövs det så behövs det.

Det du får och det som förväntas är inte alls lika. Det är lika många rader, men vissa finns bara i den ena listan.

Koden klarade alla test när jag tog bort "having age = people.age" :)

Är det så att GROUP BY körs före själva uträkningen i SELECT?

Det här HAVING känner jag inte igen. Antingen är det nåt man använder relativt sällan, eller så är det specifikt för PostgreSQL (som jag inte har använt). 

Om man alltid kan se GROUP BY som något som görs efter SELECT vågar jag inte svara på. Varför frågar du det? 

TB16 151
Postad: 20 maj 2019
Laguna skrev:
TB16 skrev:
Laguna skrev:

Jag tycker GROUP borde räcka. Men behövs det så behövs det.

Det du får och det som förväntas är inte alls lika. Det är lika många rader, men vissa finns bara i den ena listan.

Koden klarade alla test när jag tog bort "having age = people.age" :)

Är det så att GROUP BY körs före själva uträkningen i SELECT?

Det här HAVING känner jag inte igen. Antingen är det nåt man använder relativt sällan, eller så är det specifikt för PostgreSQL (som jag inte har använt). 

Om man alltid kan se GROUP BY som något som görs efter SELECT vågar jag inte svara på. Varför frågar du det? 

Okej, anledningen till att jag frågade var för att jag inte riktigt förstod hur man kunde lösa uppgiften utan ett villkor som jämför om person x har samma ålder som person y.  

jek7 29
Postad: 20 maj 2019

Man kan i princip säga att först körs WHERE, sedan GROUP BY och sist HAVING.

Nu har du ingen WHERE, så alla rader kommer med till grupperingen, men säg att du bara ville räkna ut tabellen på personer som hette något på A så kunde du haft WHERE name LIKE 'A%'. Här väljer man alltså vilka poster i tabellen som ska vara med till sammanslagningen/grupperingen.

GROUP BY slår ihop alla rader (som matchade where) som har samma värde i de angivna fälten, i ditt fall age. Då den slår ihop exempelvis raden "1,Nisse,7" med "2,Anna,7" så kan man inte längre använda fälten id och name, för det fanns (kanske) olika värden där, och en strikt SQL-motor ger ett fel ifall man gör t.ex "SELECT name,age FROM pople GROUP BY age" av den anledningen. Man kan således normalt bara selecta de fält som finns med i group-by, samt så kallade aggregerings-funktioner, som COUNT, MAX och liknande, som gör en funktion på alla raderna som ingår i den gruppen, vilket i ditt fall blir alla rader som har samma age. Du kan alltså lika gärna skriva COUNT(*) AS people_count. 

HAVING används sedan om man vill göra ytterligare urval på det sammaslagna resultatet, för saker som man inte kan kolla redan i WHERE. Exempelvis kanske du bara vill se antalet i åldrarna som har minst tio personer, då kan man lägga på HAVING people_count>=10. (I HAVING kan man alltså använda alias-namnet efter AS, vilket man inte kan i WHERE.)

Vad som händer när man tar med en tabell-kolumn i having som du först gjorde med pople.age vet jag inte riktigt, jag tror inte det är normalt att göra så, men jag kan tycka att det antingen borde varit en no-op, eller att den skulle spottat ut sig ett error. Men om jag tolkar fel-diffen rätt så var enda skillnaden att din och facits lista var sorterade olika (och då det inte angavs i frågan hur man skulle sortera borde den ju gett rätt). Ofta sorteras det på de fält man anger i GROUP BY, men jag tror inte det är något man kan förutsätta, det beror väl bl.a på vilken SQL-motor man har, så man kanske kan läsa sig till det.

Laguna 4970
Postad: 20 maj 2019

Nja, som jag skrev så är resultatlistorna lika långa, men innehåller delvis olika saker. 

TB16 151
Postad: 7 jun 2019
jek7 skrev:

Man kan i princip säga att först körs WHERE, sedan GROUP BY och sist HAVING.

Nu har du ingen WHERE, så alla rader kommer med till grupperingen, men säg att du bara ville räkna ut tabellen på personer som hette något på A så kunde du haft WHERE name LIKE 'A%'. Här väljer man alltså vilka poster i tabellen som ska vara med till sammanslagningen/grupperingen.

GROUP BY slår ihop alla rader (som matchade where) som har samma värde i de angivna fälten, i ditt fall age. Då den slår ihop exempelvis raden "1,Nisse,7" med "2,Anna,7" så kan man inte längre använda fälten id och name, för det fanns (kanske) olika värden där, och en strikt SQL-motor ger ett fel ifall man gör t.ex "SELECT name,age FROM pople GROUP BY age" av den anledningen. Man kan således normalt bara selecta de fält som finns med i group-by, samt så kallade aggregerings-funktioner, som COUNT, MAX och liknande, som gör en funktion på alla raderna som ingår i den gruppen, vilket i ditt fall blir alla rader som har samma age. Du kan alltså lika gärna skriva COUNT(*) AS people_count. 

HAVING används sedan om man vill göra ytterligare urval på det sammaslagna resultatet, för saker som man inte kan kolla redan i WHERE. Exempelvis kanske du bara vill se antalet i åldrarna som har minst tio personer, då kan man lägga på HAVING people_count>=10. (I HAVING kan man alltså använda alias-namnet efter AS, vilket man inte kan i WHERE.)

Vad som händer när man tar med en tabell-kolumn i having som du först gjorde med pople.age vet jag inte riktigt, jag tror inte det är normalt att göra så, men jag kan tycka att det antingen borde varit en no-op, eller att den skulle spottat ut sig ett error. Men om jag tolkar fel-diffen rätt så var enda skillnaden att din och facits lista var sorterade olika (och då det inte angavs i frågan hur man skulle sortera borde den ju gett rätt). Ofta sorteras det på de fält man anger i GROUP BY, men jag tror inte det är något man kan förutsätta, det beror väl bl.a på vilken SQL-motor man har, så man kanske kan läsa sig till det.

Väldigt ingående och informativt svar :) Stort tack! Det stärkte min förståelse  

Svara Avbryt
Close