Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to order a list aggregate?

In the following query, I want the equivalent for

GROUP_CONCAT(ctAncestors.ancestor ORDER BY ctAncestors.depth DESC) AS breadcrumbs_id 

in Firebird.

So far I got

LIST(ctAncestors.ancestor, ',') AS breadcrumbs_id 

I cannot figure out how to add an order by in the list directive.

How can I do a order by in the list aggregate?

-- http://www.unlimitedtricks.com/sorting-a-subtree-in-a-closure-table-hierarchical-data-structure/

-- DECLARE @__in_rootnodeId AS bigint 
-- SET @__in_rootnodeId = 8 
-- SET @__in_rootnodeId = 1 


SELECT 
     COALESCE(ctDescendants.ancestor, 0) AS parent_id 
    ,ctAncestors.descendant AS child_id 
    ,tClosureItemsTable.COM_Id 
    ,tClosureItemsTable.COM_Text 

--,'ab' as breadcrumbs
 
--,LIST(ctAncestors.ancestor ORDER BY ctAncestors.depth DESC) AS breadcrumbs_id 
,LIST(ctAncestors.ancestor, ',') AS breadcrumbs_id 
    --,GROUP_CONCAT(ctAncestors.ancestor ORDER BY ctAncestors.depth DESC) AS breadcrumbs_id 
    -- ,GROUP_CONCAT(breadcrumb_data.COM_Text ORDER BY ctAncestors.depth DESC) AS breadcrumbs 
--,GROUP_CONCAT(breadcrumb_data.COM_Text ORDER BY ctAncestors.depth) AS breadcrumbs 
,LIST(breadcrumb_data.COM_Text) AS breadcrumbs 
--,GROUP_CONCAT(breadcrumb_data.COM_Text ORDER BY ctAncestors.depth DESC SEPARATOR '-') AS breadcrumbs2 




/*  
,
    SUBSTRING
    (
        (
            SELECT 
                -- breadcrumb.ancestor AS 'text()'  -- Remove substring for this 
                -- ', ' + CAST(breadcrumb.ancestor AS nvarchar(36)) AS 'text()'
                ', ' + CAST(breadcrumb_data.comment AS nvarchar(36)) AS 'text()'
            FROM T_CommentClosure AS breadcrumb 
            
            LEFT JOIN Comments AS breadcrumb_data
                ON breadcrumb_data.COM_Id = breadcrumb.ancestor

            WHERE (breadcrumb.descendant = ctAncestors.descendant) 

            ORDER BY breadcrumb.depth DESC
            FOR XML PATH('')
        )
        ,2
        ,8000
    ) AS breadcrumbs 
*/  

    ,
    (
        SELECT COUNT(*) FROM T_CommentClosure AS tp 
        WHERE tp.ancestor = tClosureItemsTable.COM_Id AND tp.depth = 1 
    ) AS ChildCount 

FROM T_CommentClosure AS ctAncestors  

-- Must be left join, for root node
LEFT JOIN T_CommentClosure AS ctDescendants 
    ON (ctDescendants.descendant = ctAncestors.descendant) 
    AND (ctDescendants.depth = 1) 

-- INNER JOIN just in case item has been somehow deleted when FK disabled 
INNER JOIN T_Comments AS tClosureItemsTable  
    ON (ctAncestors.descendant = tClosureItemsTable.COM_Id) 
    
INNER JOIN T_Comments AS breadcrumb_data
    ON breadcrumb_data.COM_Id = ctAncestors.ancestor 
    
WHERE (1=1) 
-- AND (ctAncestors.ancestor = @__in_rootnodeId) -- ROOT node id 
AND 
( 
    -- ( ctAncestors.ancestor = @__in_rootnodeId) -- ROOT node id 
    (1=2) 
    OR 
    (1=1)
--    (@__in_rootnodeId IS NULL) 
) 

-- AND tClosureItemsTable.active = 1 

GROUP BY 
     ctAncestors.descendant 
    ,ctDescendants.ancestor 
    ,tClosureItemsTable.COM_Id 
    ,tClosureItemsTable.COM_Text 

ORDER BY breadcrumbs ASC  -- DESC
like image 348
Stefan Steiger Avatar asked Jun 22 '13 17:06

Stefan Steiger


People also ask

How do you order an aggregate function?

An aggregate function cannot be used directly in: an ORDER BY clause. Attempting to do so generates an SQLCODE -73 error. However, you can use an aggregate function in an ORDER BY clause by specifying the corresponding column alias or selectItem sequence number.

Can you ORDER BY SUM SQL?

Discussion: Use ORDER BY if you want to order rows according to a value returned by an aggregate function like SUM() . The ORDER BY operator is followed by the aggregate function (in our example, SUM() ). DESC is placed after this function to specify a descending sort order.

How do you order in GROUP BY?

When combining the Group By and Order By clauses, it is important to bear in mind that, in terms of placement within a SELECT statement: The GROUP BY clause is placed after the WHERE clause. The GROUP BY clause is placed before the ORDER BY clause.

What is LIST aggregate function in SQL?

The LISTAGG function is used to aggregate a set of string values within a group into a single string by appending the string-expression values based on the order that's specified in the 'WITHIN GROUP' clause. As a single-set aggregate function, LISTAGG operates on all rows and returns a single output row.


1 Answers

As the documentation of LIST() states:

The ordering of the list values is undefined.

That said, if you use a subquery or common table expression (CTE) that first orders by the GROUP BY-columns and this column then it will work, however this does mean that you are depending on an implementation artefact which might change with point releases or new versions.

There is an improvement ticket (CORE-2332) in the Firebird tracker for this, but it hasn't been planned for a version. This ticket also contains an example of the workaround:

WITH EDU_EPT AS (
  SELECT EEPT2.TARGET_SWE
  FROM EDUCATION_EVENT_PR_TRGT EEPT2
  WHERE EEPT2.EDUCATION_EVENT_ID = :EDU_EVENT_ID
  ORDER BY EEPT2.ORDINAL, EEPT2.ID
)
SELECT LIST('• ' || EEPT.TARGET_SWE, ASCII_CHAR(13) || ASCII_CHAR(10)) || '.'
FROM EDU_EPT EEPT 
like image 128
Mark Rotteveel Avatar answered Oct 18 '22 04:10

Mark Rotteveel