Как сделать сравнение логических строк в SQL Server 2008 - PullRequest
1 голос
/ 24 сентября 2019

Проще говоря, я хочу добавить содержимое некоторых столбцов вместе, но только если связанные столбцы содержат определенное значение.Чтобы сделать это в MS Access, я использую следующее:

STRUint:(Abs(1*([Code01]='0192'))*[Code01int])+(Abs(1*([Code02]='0192'))*[Code02int])...

Разбивая это, если Code01 = '0192', я получаю результат TRUE, который я умножаю на 1, чтобы получить -1, и использую Abs для преобразования в1. Затем это умножается на Code01int, поэтому целое число будет равно Code01int только тогда, когда Code01 равно «0192», в противном случае я получу ноль.Результат этого вычисления добавляется к следующему вычислению в последовательности и т. Д.

Последовательность повторяется 15 раз, суммируя целые числа от Code01int до Code15int, где содержимое Code01 - Code15 равно '0192'

Я лично могу думать, как сделать это в SQL, с помощью

UPDATE Table1 
SET STRUint = 0

UPDATE Table1 
SET STRUint = CASE 
                 WHEN Code01='0192' THEN STRUint + Code01int 
              END

UPDATE Table1 
SET STRUint = CASE 
                 WHEN Code02='0192' THEN STRUint + Code02int 
              END
etc

Это единственный способ достичь моей цели, выполнив много ОБНОВЛЕНИЙ?Я делаю это для 15 наборов столбцов и повторяю для разного содержимого строки 5 раз, так что 80 обновлений (включая начальный набор в ноль).

Я надеюсь, что есть способ сделать это без такого большого количества обновлений при условии, что лучше не делать так много.

Ответы [ 3 ]

2 голосов
/ 24 сентября 2019

Лучше всего было изменить дизайн вашего стола.Всякий раз, когда вы чувствуете необходимость имя-номер столбцов (таких как 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;
1 голос
/ 24 сентября 2019

Что не так с:

UPDATE Table1 SET STRUint = 0;

UPDATE 
    Table1 
SET 
    STRUint += 
    CASE WHEN Code01='0192' THEN Code01int ELSE 0 END
    + CASE WHEN Code02='0192' THEN Code02int ELSE 0 END
    + CASE WHEN Code03='0192' THEN Code03int ELSE 0 END
etc.
1 голос
/ 24 сентября 2019

есть ли у вас идентификатор в таблице?если да, вы можете сделать:

UPDATE A
SET STRUint = B.TOTAL
FROM TABLE1 A
     INNER JOIN
     (
      SELECT ID,SUM(VALUE) AS TOTAL
      FROM
      (
        SELECT ID,Code01int AS VALUE
        FROM TABLE
        WHERE Code01= '0192' 
        UNION ALL
        SELECT ID,Code02int
        FROM TABLE
        WHERE Code02= '0192' 
        UNION ALL
        SELECT ID,Code03int
        FROM TABLE
        WHERE Code03= '0192' 
        ....
        ....
      )A
      GROUP BY ID
    )B
    ON A.ID = B.ID
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...