Reputation: 3970
I have the following sample table structures for a parent
/ child
relationship.
parent
table
id ShortText
--------------
10
20
child
table
id char value order
-----------------------------
10 COLOR RED 1
10 HEIGHT 1FT 2
10 LENGTH 10FT 5
20 COLOR BLUE 1
20 WEIGHT 100LBS 3
20 WIDTH 2FT 4
I have a requirement that specifies that certain fields from the child table rows need to be concatenated together and placed in the parent table ShortText
field. The ShortText
field can be a maximum of 10 characters.
I would expect (or I should say I WANT) to get this.
id ShortText
---------------
10 RED,1FT,
20 BLUE,2FT,
I would like to complete this in a single SQL query if possible. Any suggestions as to how I can do this and avoid iterating through each child record set? Any help is appreciated!
Here's what I have tried so far.
The following update statement...
UPDATE
parent
SET
ShortText = COALESCE(ShortText, N'') +
CASE WHEN DATALENGTH(COALESCE(ShortText, N'') + child.val + ',')/2 < 10
THEN COALESCE(ShortText, N'') + child.val + ',' ELSE N'' END
FROM
parent INNER JOIN child
ON
parent.id = child.id
But I only get the following results.
id ShortText
------------------
10 RED,
20 BLUE,
I also tried the following and was unsuccessful because the case statement that is checking the length is not executed on each child table row, only on the before ShortText.
UPDATE
p
SET
p.ShortText = p.ShortText +
STUFF((
SELECT
CASE WHEN
DATALENGTH(p.ShortText)/2 + DATALENGTH(c.val + N',')/2 < 10
THEN
c.val + N','
ELSE
N''
END
FROM
child as c
WHERE
c.id = p.id
FOR XML PATH(''), type).value('.','NVARCHAR(max)'), 1, 0, N'')
FROM
parent as p
Here is a SQLfiddle for reference. I also posted and got an answer for a similar question here, but this is a different requirement and I can not scale it for the length requirement. As always, any help is much appreciated.
Upvotes: 2
Views: 3339
Reputation: 16904
Check p.ShortText on NULL and then update derived table
UPDATE x
SET x.ShortText = NewShortText
FROM (SELECT p.ShortText, STUFF((SELECT CASE WHEN
DATALENGTH(ISNULL(p.ShortText, ''))/2 + DATALENGTH(ISNULL(c.value, '') + N',')/2 < 10
THEN c.value + N','
ELSE N'' END
FROM child as c
WHERE c.id = p.id
FOR XML PATH(''), type).value('.','NVARCHAR(max)'), 1, 0, N'') AS NewShortText
FROM parent as p) x
UPDATE 14.11.2012
;WITH cte (id, uid, val)
AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY p.[uid] ORDER BY c.val DESC),
p.uid, c.val
FROM parent p INNER JOIN child c ON p.uid = c.uid
), cte2 (id, uid, val)
AS
(
SELECT id, uid, val
FROM cte
WHERE id = 1
UNION ALL
SELECT c.id, c.uid, CAST(ISNULL(ct.val, '') + ', ' + ISNULL(c.val, '') AS nvarchar(100)) AS val
FROM cte c JOIN cte2 ct ON c.id = ct.id + 1 AND c.uid = ct.uid
)
UPDATE x
SET x.ShortText = x.MaxNewShortText
FROM
(
SELECT p.uid, p.ShortText, CASE WHEN DATALENGTH(val)/2 < 10
THEN val END AS NewShortText,
MAX(CASE WHEN DATALENGTH(val)/2 < 10
THEN val END)
OVER(PARTITION BY p.[uid]) AS MaxNewShortText
FROM parent p JOIN cte2 ct ON p.uid = ct.uid
) x
Demo on SQLFiddle
Upvotes: 2