根据列值生成ID

时间:2012-03-27 13:37:03

标签: sql tsql

我有以下数据集,它代表项目和活动之间的映射:

ProjectID  ActivityID
A         A
B         B
B         C
D         D
E         D
M         N

我想基于以下规则计算ID:

a project that maps 1-1 with an activity:
A - A
M - N

one project that maps to multiple activities:
B - B
B - C

one activity that maps to multiple projects:
D - D
E - D

这会产生:

ProjectID  Activity CalculatedID
A         A        1
B         B        2
B         C        2
D         D        3
E         D        3
M         N        4

我希望那里有足够的信息,任何想法都会受到赞赏。我特别感兴趣的是看一套基于集合的方法。

- 更新:关于答案的说明 - 我将@Erwin采用的方法描述为映射的分类,与@mellamokb(建立在@ CodeByMoonlight的解决方案上)提供的解决方案相比,该解决方案分配了一个seqential ID。你的两个解决方案都帮助了我,谢谢你们!

3 个答案:

答案 0 :(得分:2)

这有点令人费解,但它有效:

SELECT ProjectID, ActivityID,
DENSE_RANK() OVER(ORDER BY ProjectID) +
DENSE_RANK() OVER(ORDER BY ActivityID) -
ROW_NUMBER() OVER(ORDER BY ProjectID, ActivityID) AS CalculatedID
FROM MyTable

当重复ProjectID或ActivityID发生时,DENSE_RANK的两种用途会产生对ROW_NUMBER创建偏移的效果。

答案 1 :(得分:2)

这是一个基于@CodeByMoonlight的答案构建的解决方案,它处理活动ID和projectID可以交错的情况,即,活动ID的ID高于其他一些条目,但projectID的ID低于其他条目输入:

SELECT
    D.ProjectID,
    D.ActivityID,
    -- generate id based on the three different scenarios
    -- 1) projects with 1-many activities, use project id
    -- 2) activities with 1-many projects, use activity id
    -- 3) 1-1, use project id
    DENSE_RANK() over (order by
        case
            when P.ProjectID is not null then P.ProjectID
            when A.ActivityID is not null then A.ActivityID
            else D.ProjectID
        end
    ) as Identifier
from
    MyTable D
left join
(
    -- projects with 1-many activities
    SELECT ProjectID
    FROM MyTable
    group by ProjectID
    having Count(ActivityID) > 1
) P on P.ProjectID = D.ProjectID
left join
(
    -- activities with 1-many projects
    SELECT ActivityID
    FROM MyTable
    group by ActivityID
    having Count(ProjectID) > 1
) A on A.ActivityID = D.ActivityID

示例输入:

B   C
A   A
B   B
B   G
D   D
B   F
E   D
M   N

示例输出:

A   A   1
B   B   2
B   G   2
B   F   2
B   C   2
E   D   3
D   D   3
M   N   4

答案 2 :(得分:1)

;WITH p AS (
    SELECT ProjectID FROM tbl GROUP BY ProjectID HAVING count(*) > 1
    ),a AS (
    SELECT ActivityID FROM tbl GROUP BY ActivityID HAVING count(*) > 1
    )
SELECT t.*
      ,CASE
         WHEN p.ProjectID  IS NOT NULL
          AND a.ActivityID IS NOT NULL THEN 4 -- n:m (missing in question!)
         WHEN p.ProjectID  IS NOT NULL THEN 2 -- 1:n
         WHEN a.ActivityID IS NOT NULL THEN 3 -- n:1
         ELSE                               1 -- 1:1
       END AS CalculatedID
FROM   tbl AS t
LEFT   JOIN p ON p.ProjectID = t.ProjectID
LEFT   JOIN a ON a.ActivityID = t.ActivityID

说明:

  • 1)在CTE p中找到所有具有多个活动的项目。
  • 2)在CTE a中查找包含多个项目的所有活动。
  • 3)LEFT将结果加入基表并在CASE语句中区分4个案例。

我添加了问题中缺少的案例4(n:m) 请参阅working demo on data.SE