Simply you can use pivot and group based on columns.
case class StudentRecord(Student: String, `Class`: String, Subject: String, Grade: String) val rows = Seq(StudentRecord ("Sam", "6th Grade", "Maths", "A"), StudentRecord ("Sam", "6th Grade", "Science", "A"), StudentRecord ("Sam", "7th Grade", "Maths", "A-"), StudentRecord ("Sam", "7th Grade", "Science", "A"), StudentRecord ("Rob", "6th Grade", "Maths", "A"), StudentRecord ("Rob", "6th Grade", "Science", "A-"), StudentRecord ("Rob", "7th Grade", "Maths", "A-"), StudentRecord ("Rob", "7th Grade", "Science", "B"), StudentRecord ("Rob", "7th Grade", "AP", "A") ).toDF() rows.groupBy("Student", "Class").pivot("Subject").agg(first("Grade")).orderBy(desc("Student"), asc("Class")).show() /** * +-------+---------+----+-----+-------+ * |Student| Class| AP|Maths|Science| * +-------+---------+----+-----+-------+ * | Sam|6th Grade|null| A| A| * | Sam|7th Grade|null| A-| A| * | Rob|6th Grade|null| A| A-| * | Rob|7th Grade| A| A-| B| * +-------+---------+----+-----+-------+ */