2

let's imagine I have the following two tables

CREATE TABLE `articles` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `artId` int(11) NOT NULL,
 `price` float NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `artId` (`artId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

CREATE TABLE `priceHistory` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `artId` int(11) NOT NULL,
 `price` float NOT NULL,
 `checkdate` datetime NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

And the following data

INSERT INTO `test`.`articles` (`id`, `artId`, `price`) VALUES (NULL, '1', '5'), (NULL, '2', '2'), (NULL, '3', '3'), (NULL, '4', '9.50'), (NULL, '5', '1.3');


INSERT INTO `test`.`priceHistory` (`id`, `artId`, `price`, `checkdate`) VALUES (NULL, '1', '5', '2014-11-10 04:19:56'), (NULL, '1', '8.50', '2014-11-09 04:19:56'), (NULL, '1', '2.5', '2014-11-08 04:19:56'), (NULL, '2', '2', '2014-11-10 04:19:56'), (NULL, '2', '2.5', '2014-11-09 04:19:56'), (NULL, '3', '3', '2014-11-10 04:19:56'), (NULL, '4', '9.50', '2014-11-10 04:19:56'), (NULL, '4', '10', '2014-11-09 04:19:56'), (NULL, '4', '8', '2014-11-08 04:19:56'), (NULL, '4', '7', '2014-11-07 04:19:56'), (NULL, '5', '1.3', '2014-11-10 04:19:56'), (NULL, '5', '2', '2014-11-09 04:19:56');

What I now want to do is the following. I want to select all articles from the table articles and also have every price change / price history entry in the same row. As an example, the final result should look like this:

id  articleId   currentPrice    2014-11-07        2014-11-08    2014-11-09      2014-11-10
1   1           5               NULL              2.5               8.5             5
2   2           2               NULL              NULL              2.5             2
3   3           3               NULL              NULL              NULL            3
4   4           9.5             7                 8                 10              9.5
5   5           1.3             NULL              NULL              2               1.3

Basically, I want to select the dates from another table and put them in as column names and fill in the data accordingly. Is this somehow possible with SELECT? I found multiple ressources on this topic, but they were either for a fixed number of rows and I need it to have it dynamic, because the datetime could reach until next year (extreme example) or they were for just one table. These are the ressources I found

  1. Problems to select the correct row from a second table
  2. Using MySQL GROUP_CONCAT or PIVOT on multiple joined tables
  3. MySQL - How to display row value as column name using concat and group_concat
  4. Select dynamic Columns in mysql
  5. mysql select dynamic row values as column names, another column as value
  6. Mysql query to dynamically convert rows to columns
  7. MySQL - Rows to Columns
  8. http://buysql.com/mysql/12-how-to-pivot-tables.html
Community
  • 1
  • 1
Musterknabe
  • 5,763
  • 14
  • 61
  • 117
  • Anything you tried already? I would assume it can be done by querying for the dates first, then add them to the fields you want to retrieve. – RST Nov 12 '14 at 09:47
  • Hi, unfortunately I didn't really try anything. I used the code examples from the links I provided at the bottom of the post, but they are too complicated for me to understand or make them work for multiple tables. As I stated above, the examples all were only for one single table (which worked for me, also!) or for a limited amount of rows and not a dynamic amount. – Musterknabe Nov 12 '14 at 09:49
  • 1
    This forum is about `I tried it this way but it doesn't work where do I go wrong` it is not `I have no clue what I am doing can you supply me with correct code`. You can't expect people to go through all the code in all the links you provided, while you didn't put any effort in it yourself. But maybe you will get lucky. In the meantime, try something, share your code. For starters I would not save the time, just the date. – RST Nov 12 '14 at 09:59
  • I can post the things I tried, but that won't matter, because what I tried was for databases with one tables or a fixed ammount of rows/columns and not for dynamic/multiple. I don't know why you have such a negativity in you. Also I provided many links as sources, where I looked at and tried out. What do you want more? I also provided the database with data. You act like I just asked and provided nothing. – Musterknabe Nov 12 '14 at 10:46
  • 1
    Would you mind sharing the idea behind producing such a result with multiple columns, and not operating with rows instead? – Kouber Saparev Nov 12 '14 at 11:31
  • To create a table view with dynamic number of columns is not in power of MySQL, unless you use hardcore ugly stuff like concat-ing a query string in procedure end executing it. Please, consider another approach. – David162795 Nov 12 '14 at 11:51
  • If one criticizes it does not necessarily means he is being negative. You even didn't tell why you want to do so. At least u must have shared some lines of code (even if they are not working at all but must be relevant). Anyhow here you need a stored procedure with dynamic sql to produce such a result. If you have not idea about that, it will be hard to absorb/understand the answer even. Your requirement is complex so do not expect a cake answer.. It could be easier for you to show this result in some other programming language like (php,c#,java) than sql using multiple queries in sequence. – Sami Nov 12 '14 at 13:01

1 Answers1

3

Well, you should have put some more effort trying to adapt one of the solutions you've found for your case, or if you do not understand something there - try harder, ask for the specific things that you do not understand - how to join two tables, how to concatenate strings, how to use variables in MySQL, etc., learn how the things work.

That said, let's take solution #6 for instance - Mysql query to dynamically convert rows to columns, and adapt it for your case.

SET @sql = NULL;

SELECT
  GROUP_CONCAT(
    DISTINCT CONCAT(
      'MAX(IF(CAST(checkdate AS date) = ''', CAST(checkdate AS date), ''', h.price, NULL)) AS ', '`', CAST(checkdate AS date), '`'
    )
    ORDER BY checkdate
  )
INTO
  @sql
FROM
  priceHistory;

SET @sql = CONCAT('
  SELECT
    a.id AS articleId,
    a.price AS currentPrice,
    ', @sql, '
  FROM
    articles a LEFT JOIN priceHistory h
  ON
    a.id = h.artId
  GROUP
    BY a.id
');

PREPARE stmt FROM @sql;

EXECUTE stmt;

Et voilà!

+-----------+--------------+------------+------------+------------+--------------------+
| articleId | currentPrice | 2014-11-07 | 2014-11-08 | 2014-11-09 | 2014-11-10         |
+-----------+--------------+------------+------------+------------+--------------------+
|         1 |            5 |       NULL |        2.5 |        8.5 |                  5 |
|         2 |            2 |       NULL |       NULL |        2.5 |                  2 |
|         3 |            3 |       NULL |       NULL |       NULL |                  3 |
|         4 |          9.5 |          7 |          8 |         10 |                9.5 |
|         5 |          1.3 |       NULL |       NULL |          2 | 1.2999999523162842 |
+-----------+--------------+------------+------------+------------+--------------------+

There are three things to fix in your data structure.

  1. Remove artId from articles - it is completely redundant.
  2. Alter the type of checkdate to date.
  3. Never use float for storing money (take a look at the value 1.2999999523162842), use NUMERIC instead!
Community
  • 1
  • 1
Kouber Saparev
  • 7,637
  • 2
  • 29
  • 26
  • Hi. For the db structure: 1. My article IDs were just examples, in the real world they are different from the primary key and also needed for data extraction 2. done 3. done, thank you very much! – Musterknabe Nov 12 '14 at 13:28