0

I am trying to update some fields, without mentioning the field name in the query, with values from other tables.

EXISTING_TABLE:

           +--------------------+
           |   Dynamic Columns  |
+---+------+------+------+------+
|ID |Item  |ABC   |GHQ   |XYZ   |
+---+------+------+------+------+
|1  |Item1 |100   |200   |Null  |
|2  |Item2 |Null  |Null  |600   |
+---+------+------+------+------+

With the query I am trying to formulate, the result of the table should be:

RESULT_TABLE:

           +-----------------+
           | Dynamic Columns |
+---+------+-----+-----+-----+
|ID |Item  |ABC  |GHQ  |XYZ  |
+---+------+-----+-----+-----+
|1  |Item1 |100  |200  |300  |
|2  |Item2 |400  |500  |600  |
+---+------+-----+-----+-----+

Those nulls should be replaced by the value of the source table below. In this table your will find how the fields above are dynamically produced.

SOURCE_TABLE:

+------+----------+------------+---------+
|ID    |Vendor    |Item        |Price    |
+------+----------+------------+---------+
|1     |ABC       |Item1       |100      |
|2     |ABC       |Item2       |400      |
|3     |GHQ       |Item1       |200      |
|4     |GHQ       |Item2       |500      |
|5     |XYZ       |Item1       |300      |
|6     |XYZ       |Item2       |600      |
+------+----------+------------+---------+

The tricky part here of this query is the columns are random or dynamic. It can only be determined at runtime. So, I should be using some syntax here to identify first the columns and update with values.

I am trying in this code but I could not find the expression for the for column_with_null_value and current_row_item:

CREATE DEFINER=`admin`@`%` PROCEDURE `null_update`()
BEGIN
    DECLARE n INT DEFAULT 0;
    DECLARE i INT DEFAULT 0;
    SELECT COUNT(*) FROM canvass_prices INTO n;
    SET i = 0;
    WHILE i < n DO
        UPDATE existing_table SET column_with_null_value = (SELECT price
           FROM source_table WHERE vendor = column_with_null_value
           AND item = current_row_item) 
           WHERE item = current_row_item;
        SET i = i + 1;
    END WHILE;
END;

UPDATE 1 Edited the entire question for clearer illustration of my case including the source table and my stored procedure attempt.

UPDATE 2 You may wonder why the data was not captured initially by the existing_table from source_table, it is because there were procedures needed to run to capture minimum prices in each item queried that leaves some columns remained null in the next item query.

UPDATE 3 Here's my actual script on how I arrived with the tables above.

This is the initial query for the first item:

DROP VIEW IF EXISTS min_prices;
CREATE VIEW min_prices AS
SELECT item_var.list_id, vendor.vendor_name, price
FROM price
JOIN item_var ON price.item_var_id = item_var.list_id
JOIN vendor ON price.vendor_id = vendor.list_id
JOIN item ON item_var.item_id = item.list_id
WHERE item_var.list_id = 1
ORDER BY price ASC
LIMIT 3;

SET @vendor1_name = (SELECT vendor_name FROM min_prices LIMIT 0, 1);
SET @vendor2_name = (SELECT vendor_name FROM min_prices LIMIT 1, 1);
SET @vendor3_name = (SELECT vendor_name FROM min_prices LIMIT 2, 1);

DROP TABLE IF EXISTS canvass_prices;
SET @canvass_var = CONCAT("CREATE TABLE canvass_prices AS
SELECT item.name, item_var.container, item_var.size, 
    (SELECT price FROM min_prices LIMIT 0, 1) AS '", @vendor1_name, "' ,   
    (SELECT price FROM min_prices LIMIT 1, 1) AS '", @vendor2_name, "' , 
    (SELECT price FROM min_prices LIMIT 2, 1) AS '", @vendor3_name, "' 
FROM item_var
JOIN item ON item_var.item_id = item.list_id
WHERE item_var.list_id = (SELECT DISTINCT list_id FROM min_prices)");
PREPARE canvass_statement FROM @canvass_var;
EXECUTE canvass_statement;
DEALLOCATE PREPARE canvass_statement;
SELECT * FROM canvass_prices;

And this is the second query for the succeeding items:

DROP VIEW IF EXISTS min_prices;
CREATE VIEW min_prices AS
SELECT item.name, item_var.container, item_var.size, vendor.vendor_name, price
FROM price
JOIN item_var ON price.item_var_id = item_var.list_id
JOIN vendor ON price.vendor_id = vendor.list_id
JOIN item ON item_var.item_id = item.list_id
WHERE item_var.list_id = 9
ORDER BY price ASC
LIMIT 3;

SET @vendor1_name = (SELECT vendor_name FROM min_prices LIMIT 0, 1);
SET @vendor2_name = (SELECT vendor_name FROM min_prices LIMIT 1, 1);
SET @vendor3_name = (SELECT vendor_name FROM min_prices LIMIT 2, 1);

call project_x.vendor1_name();
call project_x.vendor2_name();
call project_x.vendor3_name();

SET @canvass_var = CONCAT("INSERT INTO canvass_prices (name, container, size, 
                                    `", @vendor1_name, "`,
                                    `", @vendor2_name, "`,
                                    `", @vendor3_name, "`)
                           VALUES ((SELECT DISTINCT name FROM min_prices),
                                   (SELECT DISTINCT container FROM min_prices),
                                   (SELECT DISTINCT size FROM min_prices),                                   
                                   (SELECT price FROM min_prices LIMIT 0, 1),
                                   (SELECT price FROM min_prices LIMIT 1, 1),
                                   (SELECT price FROM min_prices LIMIT 2, 1))");
PREPARE canvass_statement FROM @canvass_var;
EXECUTE canvass_statement;
DEALLOCATE PREPARE canvass_statement;
SELECT DISTINCT * FROM canvass_prices;
Strawberry
  • 33,750
  • 13
  • 40
  • 57
RickyBelmont
  • 619
  • 4
  • 11
  • Show full case example - DDL and some sample data for all tables (both shown and mentioned as external source) included into the process as CREATE TABLE + INSERT INTO scripts, and desired output/result for this data. *The tricky part here of this query is the columns are random or dynamic. It can only be determined at runtime.* Create SP which uses prepared statements. – Akina Jul 03 '20 at 04:44
  • 'Random' or 'dynamic' columns are often symptomatic of poor schema design. Just sayin' – Strawberry Jul 03 '20 at 06:50
  • @Akina Thank you for your comment. I have updated the entire question, please check if its clearer this time. Let me know if you have more questions. – RickyBelmont Jul 03 '20 at 07:28
  • @Strawberry I have updated the question for clearer demonstration of my case. I don't have full control of the tables, so I did some row-columns-interpolation which is working already except for some null values I have to fill-in after interpolation. – RickyBelmont Jul 03 '20 at 07:33
  • *I have updated the entire question* I have asked for scripts which allows re-create your data and work with it - table-formatted example data does not allow this. – Akina Jul 03 '20 at 08:06
  • PS. Does `SOURCE_TABLE` table has UNIQUE `(Vendor, Item)` index? PPS. If some column for some vendor contains the values in both `EXISTING_TABLE` and `SOURCE_TABLE`, and these values differs - does the value must be altered in `EXISTING_TABLE`? – Akina Jul 03 '20 at 08:07
  • @Akina please check my update 3. I have shared here the script your were asking. – RickyBelmont Jul 03 '20 at 08:24
  • *I have shared here the script your were asking.* I have asked `CREATE TABLE` and `INSERT INTO` scripts for both `EXISTING_TABLE` and `SOURCE_TABLE`. It seems... – Akina Jul 03 '20 at 08:27
  • 1
    To update a dynamic table, you need dynamic sql, just as in the original code that generated your table. Instead of `INSERT INTO ... @vendor1_name...` you use it with your query and replace `column_with_null_value` with `@vendor1_name`. If your problem is to get the original vendor name variables (e.g. the names of your columns, if those are just a subset of all existing vendors), you can use e.g. [MySQL query to get column names?](https://stackoverflow.com/q/4165195). See e.g. [MySQL pivot row into dynamic number of columns](https://stackoverflow.com/q/12004603) for dynamic number of vendors. – Solarflare Jul 03 '20 at 08:29
  • @Solarflare Thank you. I will try to work-out on this. I could already get the columns which is the good news. – RickyBelmont Jul 03 '20 at 08:33

0 Answers0