SQL Server Create a concatenated column to an existing table

azpvetkf  于 2023-05-21  发布在  其他
关注(0)|答案(3)|浏览(129)

I added the column using the alter table function, but I am now trying to use the 'update' and 'set' syntax to successfully update the table and translate the data over in the desired format

I'm basically trying to translate this into a format I can use to update the table:

select record_no, string_agg(final_ip_description, ' | ') as Concatenated_IP 
from [dm_na_fin_da].[updated_ip_dataset]
group by record_no

Example of desired output (by record_no):

record_no   Concatenated_IP
--------------------------------------------------
382102878   Transportation | Energy | Construction

When I try to use the below, I get the following error:

alter table [dm_na_fin_da].[ip_tiebreaker_ref_table] 
    add Concatenated_IP varchar(100);

update [dm_na_fin_da].[ip_tiebreaker_ref_table] 
set Concatenated_IP = (select string_agg(final_ip_description, ' | ') 
                       from [dm_na_fin_da].[updated_ip_dataset] 
                       group by record_no)

Error

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

Is there a way for me to update this newly formed table column so it displays as shown above?

cu6pst1q

cu6pst1q1#

Assuming that you want to update the new column with the list of descriptions of all IPs of each record_no , then, starting from your existing query, you would need to correlate the subquery to the outer query (and drop the having clause):

update r
set concatenated_ip = (
    select string_agg(final_ip_description, ' | ') 
        within group (order by final_ip_description)
    from ip_tiebreaker_ref_table r1 
    where r1.record_no = r.record_no  -- correlation
)
from ip_tiebreaker_ref_table r

Note that this assigns the same value to all rows that have the same record_no ( within group is there to make the sort predictable) - which one might consider data duplication - and it is hard to maintain such information up to date when the data changes later on.

Another approach would be to use a view, which gives you an always up-to-date perspective at your data for 0 maintenance costs:

create view v_ip_tiebreaker_ref_table as
select r.*, r1.*
from ip_tiebreaker_ref_table r
cross apply (
    select string_agg(final_ip_description, ' | ') 
        within group (order by final_ip_description) as concatenated_ip
    from ip_tiebreaker_ref_table r1 
    where r1.record_no = r.record_no  -- correlation
) r1
67up9zun

67up9zun2#

The problem with your query is that your subquery is not correctly linked to the single records you're trying to update, as long as your subqueries returns multiple rows.

In order to fix this problem, you can try using the FROM... WHERE clauses featured in SQL Server UPDATE statements.

UPDATE [dm_na_fin_da].[ip_tiebreaker_ref_table] 
SET Concatenated_IP = cte.descr
FROM (SELECT record_no, STRING_AGG(final_ip_description, ' | ') AS descr
      FROM [dm_na_fin_da].[updated_ip_dataset] 
      GROUP BY record_no) cte
WHERE [dm_na_fin_da].[ip_tiebreaker_ref_table].record_no = cte.record_no
v440hwme

v440hwme3#

You can update using INNER JOIN as follows :

UPDATE [ip_tiebreaker_ref_table]
SET Concatenated_IP = s.Concatenated_IP
FROM [ip_tiebreaker_ref_table] it
INNER JOIN (
  select uid.record_no, string_agg(final_ip_description, ' | ') as Concatenated_IP
  from [updated_ip_dataset] uid
  group by uid.record_no
) as s on it.record_no = s.record_no

Demo here

相关问题