0

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

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

4 回答 4

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

于 2013-09-18T01:52:18.137 回答
1

SQL小提琴

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

结果

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

编辑 :

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

SQL小提琴

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

结果

| COLUMN_0 |
|----------|
|        8 |
于 2013-09-18T02:04:46.950 回答
0

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

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

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

于 2013-09-18T02:44:37.603 回答
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);
于 2013-09-18T02:23:29.757 回答