1

I have 2 tables I would like to update one column in table 1 with values from table 2 where id=id. However table 2 has many rows matching table 1 and all rows of table 2 would need to be updated to 1 row in table 1

Table_A

id |  all_names      |
---+-----------------+
1  |AB CD FG HI      |
2  |                 |  

** Table_B **

id | name  |
---+-------+
1  |       |
2  | Jon   | 
2  | Mike   |

After the update Table 1 should look like

    id |  all_names      |
    ---+-----------------+
    1  |AB CD FG HI      |
    2  |Jon Mike         |  

I tried

update a 
set a.all_names = TRIM(a.all_names) + b.name + ' '
from table_a a, table_b b
where a.id = b.id

All I end up getting is an empty all_names in table_a

Any idea?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Yon
  • 31
  • 7
  • [Bad habits to kick : using old-style JOINs](https://sqlblog.org/2009/10/08/bad-habits-to-kick-using-old-style-joins) - that old-style *comma-separated list of tables* style was replaced with the *proper* ANSI `JOIN` syntax in the ANSI-**92** SQL Standard (**25 years** ago) and its use is discouraged – marc_s Aug 10 '17 at 04:45

3 Answers3

0

I can't really see any other way of doing this other than through a loop.

DECLARE @id int
DECLARE @name varchar(50)

SELECT * INTO #temp FROM TABLE_B

WHILE EXISTS (SELECT 1 FROM #temp)
BEGIN
SELECT @id = (SELECT TOP 1 id from #temp)
SELECT @name = (SELECT TOP 1 [name] from #temp where id = @id)

UPDATE A
SET all_names = LTRIM(RTRIM(all_names + CHAR(32) + @name))
FROM Table_A A
WHERE A.id = @id

DELETE FROM #temp WHERE id = @id and [name] = @name

END

DROP TABLE #temp

The query puts the contents of table B into a temporary table, and removes the row once it has used it. So essentially all names keeps the same value through the loop for its own ID, except a space + the next name gets added each time. I've added a trim to the update as well to prevent leading / trailing spaces.

Conorou
  • 31
  • 4
0

I don't know if this helps, but this is an Oracle version strictly using SQL. You didn't mention it in your requirements, but the second merge prevents duplicate entries in the row:

Create tables and insert sample rows

DROP TABLE table_a;
DROP TABLE table_b;

CREATE TABLE table_a
(
    id INTEGER
  , all_names VARCHAR2 (128)
);

CREATE TABLE table_b
(
    id INTEGER
  , name VARCHAR2 (10)
);

INSERT INTO table_a (id, all_names)
     VALUES (1, 'AB CD FG HI');

INSERT INTO table_a (id, all_names)
     VALUES (2, NULL);

INSERT INTO table_b (id, name)
     VALUES (1, NULL);

INSERT INTO table_b (id, name)
     VALUES (2, 'Jon');

INSERT INTO table_b (id, name)
     VALUES (2, 'Mike');

COMMIT;

Merge allowing duplicates

MERGE INTO table_a ta
     USING (SELECT DISTINCT id, LISTAGG (name, ' ') WITHIN GROUP (ORDER BY name) OVER (PARTITION BY id) names
              FROM table_b) tb
        ON (ta.id = tb.id)
WHEN MATCHED
THEN
    UPDATE SET all_names   = all_names || tb.names
WHEN NOT MATCHED
THEN
    INSERT     (
               ta.id, ta.all_names
               )
        VALUES (
                   tb.id, tb.names
               );

SELECT *
  FROM table_a;

ROLLBACK;

Merge eliminating duplicates

MERGE INTO table_a ta
     USING (SELECT DISTINCT id, LISTAGG (name, ' ') WITHIN GROUP (ORDER BY name) OVER (PARTITION BY id) names
              FROM (WITH
                        aset
                        AS
                            (SELECT id, TRIM (all_names) || ' ' AS all_names
                               FROM table_a),
                        bset (id, name, REMAINDER)
                        AS
                            (SELECT id
                                  , SUBSTR (all_names, 1, INSTR (all_names, ' ') - 1) name
                                  , SUBSTR (all_names, INSTR (all_names, ' ') + 1) REMAINDER
                               FROM aset
                             UNION ALL
                             SELECT id
                                  , SUBSTR (REMAINDER, 1, INSTR (REMAINDER, ' ') - 1) name
                                  , SUBSTR (REMAINDER, INSTR (REMAINDER, ' ') + 1) REMAINDER
                               FROM bset
                              WHERE name IS NOT NULL)
                    SELECT id, name
                      FROM bset
                     WHERE name IS NOT NULL
                    UNION
                    SELECT id, name
                      FROM table_b
                     WHERE name IS NOT NULL)) tb
        ON (ta.id = tb.id)
WHEN MATCHED
THEN
    UPDATE SET all_names   = tb.names 
WHEN NOT MATCHED
THEN
    INSERT (ta.id, ta.all_names)
    VALUES (tb.id, tb.names);

SELECT *
  FROM table_a;

--ROLLBACK;
Brian Leach
  • 2,025
  • 1
  • 11
  • 14
0

What I ended up doing

Declare @Crs cursor as select * from Table_B;   //Temp Table 
open @crs;
while fetch @crs do
update Table_A set all_names=ifnull(Table_B,'')+trim(@crs.name)+' ' where 
id=@Crs.id;
end while;
close @crs;

This uses the least of lines and is elegant

Yon
  • 31
  • 7