```sql
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED       FOLLOWING
VS 
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED       PRECEDING


select product_name, price, group_name, round(avg0), round(avg1)
from (
SELECT
	product_name,
	price,
	group_name,
	avg(price) OVER (PARTITION BY group_name ORDER BY price) avg0,
	avg(price) OVER (PARTITION BY group_name ORDER BY
			price RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) avg1
FROM products INNER JOIN  product_groups USING (group_id)) t
order by group_name, product_name, price;




SELECT
    product_name,
    price,
    group_name,
    round(avg0),
    round(avg1)
FROM
(
    SELECT
        product_name,
        price,
        group_name,
        avg(price) OVER (PARTITION BY group_name ORDER BY price ASC) AS avg0,
        avg(price) OVER (PARTITION BY group_name ORDER BY price ASC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED PRECEDING) AS avg1
    FROM products
    INNER JOIN product_groups USING (group_id)
) AS t
ORDER BY
    group_name ASC,
    product_name ASC,
    price ASC

```
{
    return "WindowDefinition";
}
void ASTWindowDefinition::formatImpl(const FormatSettings & settings,
    FormatState & state, FormatStateStacked format_frame) const
{
    if (partition_by)
    {
        settings.ostr << "PARTITION BY ";
        partition_by->formatImpl(settings, state, format_frame);
    }
    if (partition_by && order_by)
    {
        settings.ostr << " ";
    }
    if (order_by)
    {
        settings.ostr << "ORDER BY ";
        order_by->formatImpl(settings, state, format_frame);
    }
    if ((partition_by || order_by) && !frame.is_default)
    {
        settings.ostr << " ";
    }
    if (!frame.is_default)
    {
        settings.ostr << WindowFrame::toString(frame.type) << " BETWEEN ";
        if (frame.begin_type == WindowFrame::BoundaryType::Current)
        {