Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I'm going to add a somewhat longer and more detailed explanation of the steps to take to solve this problem. I apologize if it's too long.</p> <hr> <p>I'll start out with the base you've given and use it to define a couple of terms that I'll use for the rest of this post. This will be the <strong>base table</strong>:</p> <pre><code>select * from history; +--------+----------+-----------+ | hostid | itemname | itemvalue | +--------+----------+-----------+ | 1 | A | 10 | | 1 | B | 3 | | 2 | A | 9 | | 2 | C | 40 | +--------+----------+-----------+ </code></pre> <p>This will be our goal, the <strong>pretty pivot table</strong>:</p> <pre><code>select * from history_itemvalue_pivot; +--------+------+------+------+ | hostid | A | B | C | +--------+------+------+------+ | 1 | 10 | 3 | 0 | | 2 | 9 | 0 | 40 | +--------+------+------+------+ </code></pre> <p>Values in the <code>history.hostid</code> column will become <strong>y-values</strong> in the pivot table. Values in the <code>history.itemname</code> column will become <strong>x-values</strong> (for obvious reasons).</p> <hr> <p>When I have to solve the problem of creating a pivot table, I tackle it using a three-step process (with an optional fourth step):</p> <ol> <li>select the columns of interest, i.e. <strong>y-values</strong> and <strong>x-values</strong></li> <li>extend the base table with extra columns -- one for each <strong>x-value</strong></li> <li>group and aggregate the extended table -- one group for each <strong>y-value</strong></li> <li>(optional) prettify the aggregated table</li> </ol> <p>Let's apply these steps to your problem and see what we get:</p> <p><strong>Step 1: select columns of interest</strong>. In the desired result, <code>hostid</code> provides the <strong>y-values</strong> and <code>itemname</code> provides the <strong>x-values</strong>.</p> <p><strong>Step 2: extend the base table with extra columns</strong>. We typically need one column per x-value. Recall that our x-value column is <code>itemname</code>: </p> <pre><code>create view history_extended as ( select history.*, case when itemname = "A" then itemvalue end as A, case when itemname = "B" then itemvalue end as B, case when itemname = "C" then itemvalue end as C from history ); select * from history_extended; +--------+----------+-----------+------+------+------+ | hostid | itemname | itemvalue | A | B | C | +--------+----------+-----------+------+------+------+ | 1 | A | 10 | 10 | NULL | NULL | | 1 | B | 3 | NULL | 3 | NULL | | 2 | A | 9 | 9 | NULL | NULL | | 2 | C | 40 | NULL | NULL | 40 | +--------+----------+-----------+------+------+------+ </code></pre> <p>Note that we didn't change the number of rows -- we just added extra columns. Also note the pattern of <code>NULL</code>s -- a row with <code>itemname = "A"</code> has a non-null value for new column <code>A</code>, and null values for the other new columns.</p> <p><strong>Step 3: group and aggregate the extended table</strong>. We need to <code>group by hostid</code>, since it provides the y-values:</p> <pre><code>create view history_itemvalue_pivot as ( select hostid, sum(A) as A, sum(B) as B, sum(C) as C from history_extended group by hostid ); select * from history_itemvalue_pivot; +--------+------+------+------+ | hostid | A | B | C | +--------+------+------+------+ | 1 | 10 | 3 | NULL | | 2 | 9 | NULL | 40 | +--------+------+------+------+ </code></pre> <p><em>(Note that we now have one row per y-value.)</em> Okay, we're almost there! We just need to get rid of those ugly <code>NULL</code>s.</p> <p><strong>Step 4: prettify</strong>. We're just going to replace any null values with zeroes so the result set is nicer to look at:</p> <pre><code>create view history_itemvalue_pivot_pretty as ( select hostid, coalesce(A, 0) as A, coalesce(B, 0) as B, coalesce(C, 0) as C from history_itemvalue_pivot ); select * from history_itemvalue_pivot_pretty; +--------+------+------+------+ | hostid | A | B | C | +--------+------+------+------+ | 1 | 10 | 3 | 0 | | 2 | 9 | 0 | 40 | +--------+------+------+------+ </code></pre> <p>And we're done -- we've built a nice, pretty pivot table using MySQL.</p> <hr> <p>Considerations when applying this procedure:</p> <ul> <li>what value to use in the extra columns. I used <code>itemvalue</code> in this example</li> <li>what "neutral" value to use in the extra columns. I used <code>NULL</code>, but it could also be <code>0</code> or <code>""</code>, depending on your exact situation</li> <li>what aggregate function to use when grouping. I used <code>sum</code>, but <code>count</code> and <code>max</code> are also often used (<code>max</code> is often used when building one-row "objects" that had been spread across many rows)</li> <li>using multiple columns for y-values. This solution isn't limited to using a single column for the y-values -- just plug the extra columns into the <code>group by</code> clause (and don't forget to <code>select</code> them)</li> </ul> <p>Known limitations:</p> <ul> <li>this solution doesn't allow n columns in the pivot table -- each pivot column needs to be manually added when extending the base table. So for 5 or 10 x-values, this solution is nice. For 100, not so nice. There are some solutions with stored procedures generating a query, but they're ugly and difficult to get right. I currently don't know of a good way to solve this problem when the pivot table needs to have lots of columns.</li> </ul>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload