Advanced

Group, Image

We can group parts of relations. Since the group operation returns a relation, we can then apply further processing on it, such as adding totals. The image operator lets us embed matching rows from another relation or relation expression. These can be used for summaries.

Group

We can group some attributes together as nested relations (or RVAs - relation-valued-attributes). For example, if we make a group in the parts table from all the attributes except COLOR:

group(P, {PNO, PNAME, WEIGHT, CITY}, gpart)
COLORgpart
Blue
PNOPNAMEWEIGHTCITY
P3Screw17Rome
P5Cam12Paris
Green
PNOPNAMEWEIGHTCITY
P2Bolt17Paris
Red
PNOPNAMEWEIGHTCITY
P1Nut12London
P4Screw14London
P6Cog19London

This can perhaps be expressed more simply by making a group from all the columns except COLOR:

r := group(P, ~{COLOR}, gpart)
r
COLORgpart
Blue
PNOPNAMEWEIGHTCITY
P3Screw17Rome
P5Cam12Paris
Green
PNOPNAMEWEIGHTCITY
P2Bolt17Paris
Red
PNOPNAMEWEIGHTCITY
P1Nut12London
P4Screw14London
P6Cog19London

This version has the advantage that it still gives us a tuple per COLOR even if the attributes of P change later (providing COLOR remains). It is also closer to the SQL GROUP BY construct.

Ungroup

We can unnest it using ungroup.

ungroup(r, gpart)
COLORPNOPNAMEWEIGHTCITY
BlueP3Screw17Rome
BlueP5Cam12Paris
GreenP2Bolt17Paris
RedP1Nut12London
RedP4Screw14London
RedP6Cog19London

Image

We can also create RVAs using the image operator !!.

This includes tuples from the imaged relation that match each tuple in the outer relation.

To find non-London suppliers and their shipments:

S[CITY != "London"]{*, ship:=!!SP}
shipSNOSNAMESTATUSCITY
PNOQTY
P1300
P2400
S2Jones10Paris
PNOQTY
P2200
S3Blake30Paris
S5Adams30Athens

Notice how suppliers with no shipments still appear. We don't need an outer join.

Aggregate Operators

We can use aggregate operators to add totals. For example, to total the shipments above, by supplier, we can use the sum operator on the image relation.

S[CITY != "London"]{*, tot_qty:=sum(!!SP, QTY)}
tot_qtySNOSNAMESTATUSCITY
0S5Adams30Athens
200S3Blake30Paris
700S2Jones10Paris

Notice how we get a 0 for suppliers with no shipments.

There are other aggregate operators available:

S[CITY != "London" and count(!!SP) > 0]{*, 
    min_qty:=min(!!SP, QTY), 
    max_qty:=max(!!SP, QTY)
}
min_qtymax_qtySNOSNAMESTATUSCITY
200200S3Blake30Paris
300400S2Jones10Paris

Aggregate operators needing an attribute, when used on single attribute relations, can omit the attribute name:

count(S{CITY})
3