SubTable is a helper component for grouping.
<h:form>
    <div class="card">
        <p:dataTable var="team" value="#{subTableView.teams}">
            <f:facet name="header">
                NBA Teams
            </f:facet>
            <p:columnGroup type="header">
                <p:row>
                    <p:column rowspan="2" headerText="Team"/>
                    <p:column colspan="2" headerText="Stats"/>
                </p:row>
                <p:row>
                    <p:column headerText="Wins"/>
                    <p:column headerText="Losses"/>
                </p:row>
            </p:columnGroup>
            <p:subTable var="stats" value="#{team.stats}">
                <f:facet name="header">
                    <h:outputText value="#{team.name}"/>
                </f:facet>
                <p:column>
                    <h:outputText value="#{stats.season}"/>
                </p:column>
                <p:column>
                    <h:outputText value="#{stats.win}"/>
                </p:column>
                <p:column>
                    <h:outputText value="#{stats.loss}"/>
                </p:column>
                <p:columnGroup type="footer">
                    <p:row>
                        <p:column footerText="Totals: " class="text-right font-bold"/>
                        <p:column footerText="#{team.allWins}" class="font-bold"/>
                        <p:column footerText="#{team.allLosses}" class="font-bold"/>
                    </p:row>
                </p:columnGroup>
            </p:subTable>
        </p:dataTable>
    </div>
</h:form>
package org.primefaces.showcase.view.data.datatable;
import org.primefaces.showcase.domain.Stats;
import org.primefaces.showcase.domain.Team;
import java.util.ArrayList;
import java.util.List;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
@Named
@RequestScoped
public class SubTableView {
    private List<Team> teams;
    @PostConstruct
    public void init() {
        teams = new ArrayList<Team>();
        Team lakers = new Team("Los Angeles Lakers");
        lakers.getStats().add(new Stats("2005-2006", 50, 32));
        lakers.getStats().add(new Stats("2006-2007", 44, 38));
        lakers.getStats().add(new Stats("2007-2008", 40, 42));
        lakers.getStats().add(new Stats("2008-2009", 45, 37));
        lakers.getStats().add(new Stats("2009-2010", 48, 34));
        lakers.getStats().add(new Stats("2010-2011", 42, 42));
        teams.add(lakers);
        Team celtics = new Team("Boston Celtics");
        celtics.getStats().add(new Stats("2005-2006", 46, 36));
        celtics.getStats().add(new Stats("2006-2007", 50, 32));
        celtics.getStats().add(new Stats("2007-2008", 41, 41));
        celtics.getStats().add(new Stats("2008-2009", 45, 37));
        celtics.getStats().add(new Stats("2009-2010", 38, 44));
        celtics.getStats().add(new Stats("2010-2011", 35, 47));
        teams.add(celtics);
    }
    public List<Team> getTeams() {
        return teams;
    }
}
package org.primefaces.showcase.domain;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Team implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private List<Stats> stats;
    public Team() {
        stats = new ArrayList<Stats>();
    }
    public Team(String name) {
        this.name = name;
        stats = new ArrayList<Stats>();
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<Stats> getStats() {
        return stats;
    }
    public void setStats(List<Stats> stats) {
        this.stats = stats;
    }
    public int getAllWins() {
        int sum = 0;
        for (Stats s : stats) {
            sum += s.getWin();
        }
        return sum;
    }
    public int getAllLosses() {
        int sum = 0;
        for (Stats s : stats) {
            sum += s.getLoss();
        }
        return sum;
    }
}
package org.primefaces.showcase.domain;
import java.io.Serializable;
public class Stats implements Serializable {
    private static final long serialVersionUID = 1L;
    private String season;
    private int win;
    private int loss;
    public Stats() {
        // default constructor
    }
    public Stats(String season, int win, int loss) {
        this.season = season;
        this.win = win;
        this.loss = loss;
    }
    public int getWin() {
        return win;
    }
    public void setWin(int win) {
        this.win = win;
    }
    public int getLoss() {
        return loss;
    }
    public void setLoss(int loss) {
        this.loss = loss;
    }
    public String getSeason() {
        return season;
    }
    public void setSeason(String season) {
        this.season = season;
    }
}