SQL计算字段中的不同值

时间:2013-09-18 00:38:28

标签: sql sql-server xml sql-server-2008

我有这个奇怪的场景(至少对我而言)我有一个表(实际上是一个结果集,但我想让它更简单),如下所示:

ID  |  Actions
------------------
1   |  10,12,15
2   |  11,12,13
3   |  15  
4   |  14,15,16,17

我想计算所有表中的不同动作。在这种情况下,我希望结果为8(只计算10,11,....,17;并忽略重复的值)。

如果重要,我使用的是MS SQL 2008。

如果它变得更容易,那么之前的操作就像XML一样

<root>
  <actions>10,12,15</actions>
</root>

我怀疑它会让它变得更容易,但是有些人可能会回来使用我不知道的xml函数,只是让一切变得更容易。

请告诉我是否还有其他问题。

4 个答案:

答案 0 :(得分:1)

使用与http://codecorner.galanter.net/2012/04/25/t-sql-string-deaggregate-split-ungroup-in-sql-server/类似的方法:

首先你需要一个能够分割字符串的函数,SO上有很多例子,这里有一个例子:

CREATE FUNCTION dbo.Split (@sep char(1), @s varchar(512))
RETURNS table
AS
RETURN (
    WITH Pieces(pn, start, stop) AS (
      SELECT 1, 1, CHARINDEX(@sep, @s)
      UNION ALL
      SELECT pn + 1, stop + 1, CHARINDEX(@sep, @s, stop + 1)
      FROM Pieces
      WHERE stop > 0
    )
    SELECT pn,
      SUBSTRING(@s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
    FROM Pieces
)

使用此功能,您可以运行简单的查询:

SELECT COUNT(DISTINCT S) FROM MyTable CROSS APPLY dbo.Split(',', Actions)

以下是演示:http://sqlfiddle.com/#!3/5e706/3/0

答案 1 :(得分:1)

SQL Fiddle

MS SQL Server 2008架构设置

CREATE TABLE Table1
    ([ID] int, [Actions] varchar(11))
;

INSERT INTO Table1
    ([ID], [Actions])
VALUES
    (1, '10,12,15'),
    (2, '11,12,13'),
    (3, '15'),
    (4, '14,15,16,17')
;

查询1

DECLARE @S varchar(255)
DECLARE @X xml

SET @S = (SELECT Actions + ',' FROM Table1 FOR XML PATH(''))
SELECT @X = CONVERT(xml,'<root><s>' + REPLACE(@S,',','</s><s>') + '</s></root>')

SELECT count(distinct [Value])
FROM (
SELECT [Value] = T.c.value('.','varchar(20)')
FROM @X.nodes('/root/s') T(c)) AS Result
WHERE [Value] > 0

<强> Results

| COLUMN_0 |
|----------|
|        8 |

编辑:

我认为这正是您所寻找的:

SQL Fiddle

MS SQL Server 2008架构设置

查询1

DECLARE @X xml

SELECT @X = CONVERT(xml,replace('
<root>
  <actions>10,12,15</actions>
  <actions>11,12,13</actions>
  <actions>15</actions>
  <actions>14,15,16,17</actions>
</root>
',',','</actions><actions>'))

SELECT count(distinct [Value])
FROM (
SELECT [Value] = T.c.value('.','varchar(20)')
FROM @X.nodes('/root/actions') T(c)) AS Result

<强> Results

| COLUMN_0 |
|----------|
|        8 |

答案 2 :(得分:0)

有点混乱,但这里是先创建函数然后调用较低的代码。

/* Helper Function */

CREATE FUNCTION dbo.Split (@sep char(1), @s varchar(8000))
RETURNS table
AS
RETURN (
    WITH splitter_cte AS (
      SELECT CHARINDEX(@sep, @s) as pos, 0 as lastPos
      UNION ALL
      SELECT CHARINDEX(@sep, @s, pos + 1), pos
      FROM splitter_cte
      WHERE pos > 0
     )
    SELECT SUBSTRING(@s, lastPos + 1,
                     case when pos = 0 then 80000
                     else pos - lastPos -1 end) as chunk
    FROM splitter_cte
  )
GO
---------------- End of Function 


/* Function Call */ 
Declare @Actions varchar(1000)
SELECT @Actions = STUFF((SELECT ',' + actions
          FROM tblActions
          ORDER BY actions
          FOR XML PATH('')), 1, 1, '')

SELECT  Distinct *
  FROM dbo.Split(',', @Actions)
OPTION(MAXRECURSION 0);

答案 3 :(得分:0)

如果您有一个Actions表,每个可能的操作ID都有一行,您可以使用连接执行此操作:

select count(distinct a.ActionId)
from t join
     Actions a
     on ','+t.Actions+',' like '%,'+cast(a.ActionId as varchar(255))+',%';

如果你知道动作在某个范围内,你也可以创建一个数字表(使用CTE)。