Лучше всего было изменить дизайн вашего стола.Всякий раз, когда вы чувствуете необходимость имя-номер столбцов (таких как Code01
, Code02
), вы должны использовать связанную таблицу.
Мой код будет использовать APPLY
сVALUES()
чтобы создать необходимую структуру на лету (вроде univivoting ), а затем GROUP BY
и SUM()
, чтобы получить то, что (я думаю) вы просите.
DECLARE @MockTable TABLE(ID INT IDENTITY
,Comment VARCHAR(100)
,Code01 VARCHAR(100),Code01int INT
,Code02 VARCHAR(100),Code02int INT
,Code03 VARCHAR(100),Code03int INT);
INSERT INTO @MockTable VALUES('One is a' ,'a',1,'b',1,'c',1)
,('All are a','a',1,'a',1,'a',1)
,('Two are a','b',1,'a',1,'a',1);
- я использую 'a' вместо вашего номера, но вы получите ghist
DECLARE @SearchCode VARCHAR(100)='a';
- Запрос
SELECT t.ID
,t.Comment
,SUM(A.Val) AS SumOfValuesForTheCode
FROM @MockTable t
CROSS APPLY (VALUES(1,Code01,Code01int)
,(2,Code02,Code02int)
,(3,Code03,Code03int))A(Indx,Code,Val)
WHERE A.Code=@SearchCode
GROUP BY t.ID,t.Comment
Результат
1 One is a 1
2 All are a 3
3 Two are a 2
ОБНОВЛЕНИЕ: Полностью универсальный подход:
Это не будет быстрым, но это - в некотором роде - красиво: -)
SELECT t.ID
,t.Comment
,RowAsXml.query('for $code in /row/*[string-length(local-name())=6
and substring(local-name(),1,4)="Code"
and text()=sql:variable("@SearchCode")]
return /row/*[local-name()=concat(local-name($code),"int")]')
.value('sum(*/text())','int')
FROM @MockTable t
CROSS APPLY(SELECT t.* FOR XML PATH('row'),TYPE) A(RowAsXml)
Идея вкратце:
APPLY
создаст XML, представляющий всю строку.Против этого XML мы можем использовать FLWOR XQuery.Данный xquery будет проходить через узлы и находить те, где длина имени равна 6, и которые начинаются с «Code» и где text()
(= содержимое) равно значению, которое вы ищете.
Зная узлы подходящего кода, мы можем вернуть узлы подходящего значения, соединив имя столбца со словом "int".
С этим мы можем построить сумму, вуаля!
Промежуточный XML выглядит следующим образом (по одному на строку)
<row>
<Comment>One is a</Comment>
<Code01>a</Code01>
<Code01int>1</Code01int>
<Code02>b</Code02>
<Code02int>1</Code02int>
<Code03>c</Code03>
<Code03int>1</Code03int>
</row>
ОБНОВЛЕНИЕ: Как обновить столбец таблицы
Вы можете использовать объединенный запрос, как здесь
DECLARE @MockTable TABLE(ID INT IDENTITY
,Comment VARCHAR(100)
,Code01 VARCHAR(100),Code01int INT
,Code02 VARCHAR(100),Code02int INT
,Code03 VARCHAR(100),Code03int INT
,STRUint INT);
INSERT INTO @MockTable(Comment,Code01,Code01int,Code02,Code02int,Code03,Code03int)
VALUES('One is a' ,'a',1,'b',1,'c',1)
,('All are a','a',1,'a',1,'a',1)
,('Two are a','b',1,'a',1,'a',1);
DECLARE @SearchCode VARCHAR(100)='a';
UPDATE t1 SET STRUint=t2.SumOfValuesForTheCode
FROM
@MockTable t1
INNER JOIN
(
SELECT t.ID
,t.Comment
,SUM(A.Val) AS SumOfValuesForTheCode
FROM @MockTable t
CROSS APPLY (VALUES(1,Code01,Code01int)
,(2,Code02,Code02int)
,(3,Code03,Code03int))A(Indx,Code,Val)
WHERE A.Code=@SearchCode
GROUP BY t.ID,t.Comment
) t2 ON t1.ID=t2.ID;
- Проверьте результат
SELECT * FROM @MockTable
В другом подходе используется обновляемый CTE
WITH FindValue AS
(
SELECT t.ID
,SUM(A.Val) AS SumOfValuesForTheCode
FROM @MockTable t
CROSS APPLY (VALUES(1,Code01,Code01int)
,(2,Code02,Code02int)
,(3,Code03,Code03int))A(Indx,Code,Val)
WHERE A.Code=@SearchCode
GROUP BY t.ID,t.Comment
)
,TargetTable AS
(
SELECT t1.STRUint
,t2.SumOfValuesForTheCode
FROM @MockTable t1
INNER JOIN FindValue t2 ON t1.ID=t2.ID
)
UPDATE TargetTable SET STRUint=SumOfValuesForTheCode;