关于sql server:SQL-如果组中的所有成员都相同,则更新字段

SQL - Update a field if all in group are the same

我有一个SQL Server 2014临时表#SourceTable如下所示,其中AllTheSamePerDOI是一个位字段,默认为0:

1
2
3
4
5
6
7
8
ID  | DOI | Affiliations | SameAffiliationsPerDOI
----+-----+--------------+-----------------------
1   | 1   | Text A       | 0
2   | 1   | Text A       | 0
3   | 7   | Text CCC     | 0
4   | 7   | Text CR      | 0
5   | 7   | Text CCC     | 0
6   | 9   | Text CCC     | 0

仅当同一DOI中的所有记录在该分组中的所有关系中具有完全相同的文本时,我才想将SameAffiliationsPerDOI字段设置为1。因此最终结果看起来像这样,其中DOI 1和DOI 9都具有1集,因为每个DOI中的所有东西对于其所有记录在关联中都具有相同的值。如何编写SQL语句来做到这一点?

1
2
3
4
5
6
7
8
ID  | DOI | Affiliations | SameAffiliationsPerDOI
----+-----+--------------+-----------------------
1   | 1   | Text A       | 1
2   | 1   | Text A       | 1
3   | 7   | Text CCC     | 0
4   | 7   | Text CR      | 0
5   | 7   | Text CCC     | 0
6   | 9   | Text CCC     | 1

我喜欢使用可更新的CTE和窗口函数来解决这些问题:

1
2
3
4
5
6
7
8
9
WITH toupdate AS (
      SELECT st.*,
             MIN(Affiliations) OVER (partition BY doi) AS mina,
             MAX(Affiliations) OVER (partition BY doi) AS maxa
      FROM #SourceTable st
     )
UPDATE toupdate
    SET SameAffiliationsPerDOI = 1
    WHERE mina = maxa;

您也可以使用not exists

编写此代码

1
2
3
4
5
6
UPDATE #SourceTable st
    SET SameAffiliationsPerDOI = 1
    WHERE NOT EXISTS (SELECT 1
                      FROM #SourceTable st2
                      WHERE st2.doi = st.doi AND st2.Affiliations <> st.Affiliations
                     );

哪个更快可能取决于数据中值的分布和可用索引。


因此,据我了解,这是一次更新吗?对于类似的未来案例,不是连续更新吗?

如果是这样,请尝试以下SQL代码:

1
2
3
UPDATE #SourceTable
SET SameAffiliationsPerDOI = 1
WHERE ID IN (1, 2, 6);

希望有帮助。

如果要使其自动化,则可能必须调查触发器。


1
2
3
4
UPDATE S
SET SameAffiliationsPerDOI = 1
FROM #SourceTable S
WHERE NOT EXISTS (SELECT 1 FROM #SourceTable S2 WHERE S2.DOI = S.DOI AND S2.Affiliations <> S.Affiliations)


以下是使用density_rank()窗口函数的解决方案:

1
2
3
4
5
6
7
WITH ranked AS (
    SELECT DOI, dense_rank() OVER (partition BY DOI ORDER BY Affiliations) r
    FROM #SourceTable),
    same AS (SELECT DOI FROM ranked GROUP BY DOI HAVING MAX(r)=1)

UPDATE #SourceTable SET SameAffiliationsPerDIO=1
WHERE DOI IN (SELECT DOI FROM same)