sql server update many columns with a select from a join of a table variable and a db table
-
13-07-2021 - |
Question
I have the classical person -> person attributes scheme. So, like this: person(PK) <- person_attribute(FK)
What I need is a query to get one row where a person is joined with her attributes. For example, to transform:
Person:
{ ID = 123456, Name = 'John Smith', Age = 25 }
Attributes:
1) { PersonID = 123456, AttributeTypeID = 'Height', AttributeValue = '6'6'''}
2) { PersonID = 123456, AttributeTypeID = 'Weight', AttributeValue = '220lbs'}
3) { PersonID = 123456, AttributeTypeID = 'EyeColor', AttributeValue = 'Blue'}
To:
PersonWithAttributes
{
ID = 123456, Name = 'John Smith', Age = 25, Height = '6'6''', Weight = '220lbs', EyeColor = 'Blue'
}
To make things worse my persons are in a table variable.
So, I have (in a sp with a parameter of person_id):
--result table
declare @people_info table
(
person_id int,
name nvarchar(max),
age int,
height nvarchar(10) null,
weight nvarchar(10) null,
eye_color nvarchar(16) null
)
insert into @people_info
select person_id, name, age, null, null, null
from dbo.HR.people where person_id = @person_id
update pi
set
pi.height = (select pa.attribute_value where pa.attribute_type_id = 'Height'),
pi.height = (select pa.attribute_value where pa.attribute_type_id = 'Weight'),
pi.eye_color = (select pa.attribute_value where pa.attribute_type_id = 'EyeColor')
from
@people_info pi
inner join dbo.HR.person_attributes pa on pi.person_id = pa.person_id
select * from @people_info
Which of course does not work for some reason. If I query the two joined tables and select "pa.attribute_value where pa.attribute_type_id = 'someval'" I get the correct value. But the update does not work.
Of course, I can write this as three updates, but I am thinking that it will be faster to do one join and then to filter in the update clause.
Also, please keep in mind that my attributes are spread over three tables, not just the attributes table. So, this is why I have the table variable.
Any help is very welcome. Maybe I am going about this the wrong way. Performance matters. What is the most performant way to accomplish this?
Thank you very much.
Solution
Try this code for update with pivot:
update
pi
set
pi.height = pa.Height
pi.weight = pa.Weight
pi.eye_color = pa.EyeColor
from
@people_info pi
inner join
(
SELECT
person_id
,[Height] Height
,[Weight] Weight
,[EyeColor] EyeColor
FROM
(
SELECT
attribute_type_id
, attribute_value
, person_id
FROM
dbo.HR.person_attributes pa
) pa
PIVOT
(
MAX(attribute_value) FOR attribute_type_id IN ([Height],[Weight],[EyeColor])
)pvt
) pa
on
pi.person_id = pa.person_id
OTHER TIPS
Maybe you want something like:
update pi
set
pi.height = paH.attribute_value,
pi.weight = paW.attribute_value,
pi.eye_color = paE.attribute_value
from
@people_info pi
inner join dbo.HR.person_attributes paH on pi.person_id = paH.person_id
and paH.attribute_type_id = 'Height'
inner join dbo.HR.person_attributes paW on pi.person_id = paW.person_id
and paW.attribute_type_id = 'Weight'
inner join dbo.HR.person_attributes paE on pi.person_id = paE.person_id
and paE.attribute_type_id = 'EyeColor'