André Moreira
André Moreira

Reputation: 1699

subqueries and user variables

I'm having a problem that I can't get a grasp on and it's driving me nuts.

I'm doing a query with a subquery where I use variables to reformat some of the values

SELECT 
    IF(qry.pFamily=@lastFamily,'',@lastFamily:=qry.pFamily) AS family,
    IF(qry.pSubFamily=@lastSubFamily,'',@lastSubFamily:=qry.pSubFamily) AS subFamily,
    qry.pUid AS qUID,
    qry.pPlu AS qPLU,
    qry.pDescription AS qDesc,
    replace(round(qry.pSalesPrice/100,2),'.',',') as pPrice
FROM (
   SELECT
   @lastFamily ='',
   @lastSubFamily ='',
   IF(sf.RecordDeleted=0,
        SUBSTR(concat(f.description,"\n"),1,20),
        SUBSTR(concat("Sem familia\n"),1,20)) AS pFamily,
   IF(sf.RecordDeleted=0,
        SUBSTR(concat("    ",sf.description,"\n"),1,30),
        SUBSTR(concat(""),1,30))
        AS pSubFamily,
    p.ItemID AS pUid,
    IF(p.ProductLookUp IS NULL,'0',p.ProductLookUp) AS pPlu,
    SUBSTR(p.ShortDescription1,1,20) AS pDescription, 
    SUBSTR(prop.SalesPrice1,1,10) AS pSalesPrice
    FROM plus p
    INNER JOIN properties prop on p.PropertyUID = prop.uid 
    INNER JOIN families f on p.FamilyID = f.UID
    INNER JOIN subFamilies sf on p.SubFamilyID = sF.UID 
    WHERE p.RecordDeleted=0 
    ORDER BY pFamily, pSubFamily,pDescription
) AS qry;

The idea behind the use of the variables lastFamily and lastSubFamily is to replace repeated text to get a clean, ready to use result set.

In the first run I get

'Bebida', '    Agua', '22', ?, '1/4 Castelo', ?
'Bebida', '    Agua', '23', ?, 'Agua 0.33cl', ?
'Bebida', '    Agua', '24', ?, 'Agua 0.50cl', ?
'Bebida', '    Agua', '25', ?, 'Agua 1.5l', ?
'Bebida', '    Agua', '26', ?, 'Agua c/Sabor', ?
'Bebida', '    Agua', '27', ?, 'Agua Gás', ?
'Bebida', '    Alcoolica', '1', ?, 'Alianca Velha', ?
                    (etc...)

but the second time I run the query I get the desired results

'Bebida', '    Agua', '22', ?, '1/4 Castelo', ?
'', '    ', '23', ?, 'Agua 0.33cl', ?
'', '    ', '24', ?, 'Agua 0.50cl', ?
'', '    ', '25', ?, 'Agua 1.5l', ?
'', '    ', '26', ?, 'Agua c/Sabor', ?
'', '    ', '27', ?, 'Agua Gás', ?
'', '    Alcoolica', '1', ?, 'Alianca Velha', ?
                    (etc...)

My question here is how (where) do I initialize lastFamily and lastSubFamily so that they are set in the first run.

Every time I start a new mysql session this happens and then it never happens. So I guess the variables are being stored somewhere. I tried cleaning the cache and flushing the tables, but the result is the same.

Any ideas?

Cheers

Upvotes: 0

Views: 170

Answers (1)

N West
N West

Reputation: 6819

It sounds like you are trying to generate a cross tab report using SQL to hide the "repeated" values...you only want the "grouped" columns to appear once, then blank for the remaining rows.

Family     SubFamily   qUID    qPLU    qDesc         qPrice
-----------------------------------------------------------
Bebida     Auga        22      ?       1/4 Castelo   ?
                       23      ...
                       24      ...
                       25      ...
                       26      ...
                       27      ...
           Alcoolica   1       ...
Family2    SubFamily1  15
                       16
           SubFamily2  15
                       16

Note that the MySQL reference says that:

As a general rule, you should never assign a value to a user variable and read the value within the same statement. You might get the results you expect, but this is not guaranteed. The order of evaluation for expressions involving user variables is undefined and may change based on the elements contained within a given statement; in addition, this order is not guaranteed to be the same between releases of the MySQL Server.

This task is much more suited to the client application / reporting tool which is displaying and formatting the data set retrieved from the database.

You'll be hard pressed to do this easily in SQL, since in a relational table, each row is independent of the other rows (even when the set is ordered). There may be methods using analytic functions in some DBMS's to achieve this, but really I would highly recommend that you do this in the procedural language that is displaying the result set - a simple procedural loop with some variables to keep track of the prior family/subfamily should do the trick.

Upvotes: 1

Related Questions