简体   繁体   中英

Using GROUP_CONCAT column alias in CASE statement with LIKE

The idea here is that the GROUP_CONCAT compiles a list of option codes out of the stock table joined to the option_stock and options tables, grouped by the stock id. An example row is this:

Name                Options             Transmission
'Holden Commodore' '111, 145, 166, 188' 'Auto' 

This view works as it is, but I can't help but feel there's a more elegant solution?

CREATE VIEW stock_view AS
    (select s.description AS Name,
    group_concat(o.option_code order by o.option_code ASC separator ', ') 
    AS Options, 
    (case
        WHEN group_concat(o.option_code) LIKE '%111%' then 'Auto'
        WHEN group_concat(o.option_code) LIKE '%112%' then 'Manual'
        else 'Other'
    end) as Transmission
    from stock s
    join option_stock ost ON s.id = ost.stock_id
    join options o ON o.id = ost.option_id
    group by s.id)

I'm trying to avoid using this ugly looking GROUP_CONCAT inside CASE predicament, but I get an error saying the field Options does not exist if I use it inside the case statement like this:

WHEN `Options` LIKE '%111%' then 'Auto'

I know why the error is thrown - it's because you can't use the alias of another column in this manner. But is there a way around it?

These bits do not seem reliable enough to me:

WHEN group_concat(o.option_code) LIKE '%111%' ...
WHEN group_concat(o.option_code) LIKE '%112%' ...

LIKE '%111%' will match eg '111222, 145, 166, 188' just as well as '111, 145, 166, 188' . Unless, of course, there are only 3-character codes and you aren't expecting that to change soon.

Still, I would probably use a different technique anyway, most likely a conditional COUNT or SUM. For instance:

(CASE
    WHEN SUM(o.option_code = '111') > 0 THEN 'Auto'
    WHEN SUM(o.option_code = '112') > 0 THEN 'Manual'
    ELSE 'Other'
END) AS Transmission

Note also that in your particular case the following, although rather specific, solution should work as well:

IFNULL(
    MIN(CASE o.option_code WHEN '111' THEN 'Auto' WHEN '112' THEN 'Manual' END),
   'Other'
) AS Transmission

Ie if '111' or, for some reason, both '111' and '112' are found among the codes in the same group of rows, the MIN() will return 'Auto' , if '112' bot not '111' , it will evaluate to 'Manual' . Otherwise it will be NULL, in which case the IFNULL() function will evaluate to 'Other' .

Hard to test without the actual tables (can't actually execute the statement) but what about something like this:

CREATE VIEW stock_view AS
(SELECT
    gc.Name,
    gc.Options,
    (case
        WHEN gc.Options LIKE '%111%' then 'Auto'
        WHEN gc.Options LIKE '%112%' then 'Manual'
        else 'Other'
    end) as Transmission
FROM
    (select 
        s.description AS Name,
        group_concat(o.option_code order by o.option_code ASC separator ', ') AS Options
    from 
        stock s
        join option_stock ost ON s.id = ost.stock_id
        join options o ON o.id = ost.option_id
    group by 
        s.id) gc);

Make a separate join to determine the transmission type:

CREATE VIEW stock_view AS
select
    s.description AS Name,
    group_concat(o.option_code order by o.option_code separator ', ') AS Options,
    if(t.option_code = '111', 'Auto', 'Manual') as Transmission
from stock s
join option_stock ost ON s.id = ost.stock_id
join options o ON o.id = ost.option_id
left join options t on t.id = ost.option_id 
     and option_code in ('111', '112')
group by s.id

Only one row will join from the transmission join (a car can't be both auto and manual) and this approach avoids all those sub queries.

Making the join a left join means that a missing transmission option will show as a manual. You can tune that by adding a test for null to have a default value.

You have to create two separate VIEWS because MySQL doesn't support sub-query in VIEW .

Try this:

CREATE VIEW stock_view AS
  SELECT s.description AS sname, 
         GROUP_CONCAT(o.option_code ORDER BY o.option_code SEPARATOR ', ')  AS soptions 
  FROM stock s
  INNER JOIN option_stock ost ON s.id = ost.stock_id
  INNER JOIN OPTIONS o ON o.id = ost.option_id
  GROUP BY s.id;

CREATE VIEW stock_view1 AS 
  SELECT sname, soptions, 
         (CASE WHEN FIND_IN_SET('111', soptions) THEN 'Auto'
               WHEN FIND_IN_SET('112', soptions) THEN 'Manual'
               ELSE 'Other'
         END) AS Transmission
  FROM stock_view;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM