如何在 SQL Server 2008 中进行布尔字符串比较

How do I do a boolean string comparison in SQL Server 2008

简单来说,我想将一些列的内容加在一起,但前提是关联的列包含特定值。要在 MS Access 中执行此操作,我使用以下内容:

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

分解这个,如果 Code01='0192' 我得到结果 TRUE,我乘以 1 得到 -1 并使用 Abs 转换为 1。然后乘以 Code01int,所以我有一个仅当 Code01 为“0192”时整数才等于 Code01int,否则我将为零。该计算的结果将添加到序列中的下一个计算中,依此类推。

序列重复 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 次(包括初始设置为零)。

我希望有一种方法可以在没有这么多更新的情况下做到这一点,假设最好不要做那么多。

你在 table 有身份证吗? 如果是,你可以这样做:

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

有什么问题:

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.

最好是更改 table 的设计。每当您觉得需要 name-number 列(例如 Code01Code02)时,您应该使用相关的边 table.

我的代码将使用 APPLYVALUES() 动态创建所需的结构(有点 unpivoting)然后 GROUP BYSUM() 得到你想要的(我认为)。

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 我们可以使用 XQuery 的 FLWOR。给定的 xquery 将 运行 通过节点并找到名称长度为 6 且以 "Code" 开头且 text()(= 内容)等于您的值的节点正在寻找。

知道拟合代码节点,我们可以通过将列名与单词 "int".

连接来 return 拟合值节点

有了这个我们可以建立一个总和,瞧!

中间的 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>

更新:如何更新 table 的列

您可以像这里一样使用联合查询

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;