0

i would like to create virtual columns that are dynamic where the values are being generated based on a join table.

i have the following table called types:

id, name
1, TypeA
2, TypeB

and i have a table called category

id, name, type
1, a, 1
2, b, 2

i would like to have a query that returns the following

category name, TypeA, TypeB
a, 1, 0
b, 0, 1

is this possible to do in mysql?

1
  • Do you know how many types(columns) you will be checking on beforehand? If so, do you just want to display a boolean 0 or 1 if that type exists for the category? Commented Jul 1, 2012 at 7:37

2 Answers 2

3

I'd outline several cases here.

  1. First and most straightforward is the following:

    SELECT c.name AS "CatName",
           IF(typea.id IS NULL, 0, 1) AS "TypeA",
           IF(typeb.id IS NULL, 0, 1) AS "TypeB"
      FROM category c
      LEFT JOIN types typea ON c.type = typea.id AND typea.name = 'TypeA'
      LEFT JOIN types typeb ON c.type = typeb.id AND typeb.name = 'TypeB';
    

    But this requires manually mentioning all types in the query, which is apparently not what you're seeking for.

  2. It is possible to build SQL query and use it, this method assumes you're running queries from some script, that can grab output from the first query and use it as a new query.

    SELECT concat('SELECT c.name AS "CatName",',
        group_concat(concat('IF(',lower(t.name),
          '.id IS NULL,0,1) AS "',t.name,'"')),
        ' FROM category c ',
        group_concat(concat('LEFT JOIN types ',
          lower(t.name),' ON c.type = ',lower(t.name),'.id AND ',
          lower(t.name),'.name = ''',t.name,'''') SEPARATOR ' '),
        ';')
      FROM types t;
    

    Writing a small shell (or other) script should be easy.

  3. In the standard SQL it is not possible to use contents of the tables to create DML statements. Different databases provide different facilities for this, like PIVOT statement, procedural languages, etc. I do not know how to achieve this with MySQL facilities, but the idea is to dynamically build a query outlined in point #2 and execute it.

I've covered first 2 cases on the SQL Fiddle.

Sign up to request clarification or add additional context in comments.

2 Comments

Your second solution is interesting as it is like my PHP example which dynamically builds the query based on how many types there are. I wonder if something like that could be incorporated into a stored procedure.
@ZaneBien, for sure it is possible. I don't know how to do it in MySQL, but with PostgreSQL is quite straightforward for me.
1

There is a feature called PIVOT which does what you want, but unfortunately, it is not available in MySQL.

What you could do however, is concatenate all types into a single string per category:

SELECT
    a.name,
    GROUP_CONCAT(b.name) AS types
FROM
    category a
LEFT JOIN
    types b ON a.type = b.id
GROUP BY
    a.id

Which would result in something like:

name    |    types
--------------------------------
a       |    TypeA
b       |    TypeB
c       |    TypeA,TypeB,TypeC,TypeD

Where category c has four different types, but a and b only have one type associated with them.

If you know beforehand what and how many types you're going to check on, and want to display a boolean value if that type exists for the category, you could do this:

SELECT,
    a.name,
    b.id IS NOT NULL AS TypeA,
    c.id IS NOT NULL AS TypeB,
    -- etc...
FROM
    category a
LEFT JOIN
    types b ON a.type = b.id AND b.id = 1
LEFT JOIN
    types c ON a.type = c.id AND c.id = 2
-- etc...

Edit: If you don't know the number of columns you're going to create beforehand, but still want boolean values for each type in their own separate columns, another option would be to dynamically build the query string in your application logic. Let's say you were using PHP for example:

$columns = $ljoins = array();
$i = 1;

foreach($pdo->query('SELECT id, name FROM types') as $row)
{
    $columns[] = "t$i.id IS NOT NULL AS " . $row['name'];
    $ljoins[] = "LEFT JOIN types t$i ON a.type = t$i.id AND t$i.id = " . $row['id'];
    $i++;
}

$sql = 'SELECT a.name, ' . implode(', ', $columns) . ' FROM category a ' . implode(' ', $ljoins);
$stmt = $pdo->query($sql);

// Do stuff with result-set

4 Comments

Thats not what i'm looking for. I would like to have the type show as the column. so instead of "types" i would like to show typea, typeb. i'm starting to believe that is not possible.
Yes, PIVOT is only available to Oracle, SQL Server DBMSs. What are you developing your application in? One thing you could actually do is dynamically build you query in your application logic. First, you would query for all types and their ids, then you would dynamically build a query string using that information by concatenating however many LEFT JOINs as there are types. This way, you aren't hard-coding the column selection in your query, but it is still a clunky solution that would be better if it were handled in SQL.
i believe the alternative solution to this is use group_concat. so for each category i would display a type column comma separated as follow: groupa, type1,type2
First solution edited so that it displayed the names of the types in the group_concat string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.