场景:主用户表以及跟踪用户名称更改的单独审计表。每次添加用户或编辑其部分名称时,我们都会向审计表写一行。
尝试编写一个提取最直接的前名称的查询
select nsh.AuthEmail, nsh.UserID, nsh.name_lastnamefirst, t.FormerName, t.RankOrder
from (
Select
an.AuditNameID, nsh.AuthEmail, nsh.UserID, nsh.name_lastnamefirst,
FormerName = CASE WHEN RTRIM(an.LastName) <> RTRIM(nsh.LastName) OR RTRIM(an.FirstName) <> RTRIM(nsh.FirstName) OR RTRIM(an.Suffix) <> RTRIM(nsh.Suffix) OR RTRIM(an.MaidenName)<>RTRIM(nsh.MaidenName) THEN LTRIM(an.LastName + ' ' + an.Suffix + ', ' + an.FirstName + ' ' + ISNULL(an.MiddleName,''))
ELSE null
END,
RANK() over (partition by an.UserID order by an.AuditNameID DESC) RankOrder
From [dbo].[AuditName] an
INNER JOIN dbo.StudentPrograms p ON an.UserID = p.UserID
INNER JOIN dbo.NameScalarHelper nsh ON p.UserID = nsh.UserID
WHERE p.SiteProgramID = 139 AND p.IsActive =1
) t
RIGHT OUTER JOIN dbo.NameScalarHelper nsh ON nsh.UserID = t.UserID
where FormerName is not null
问题是我无法弄清楚如何从RANK为RANK -1的审计表中返回数据,因为最高等级是当前数据。如果有任何想法,请告诉我。
答案 0 :(得分:1)
根据您的要求,您基本上需要返回与审核表中的当前名称不匹配的最新名称。
我认为您可以使用OUTER APPLY
来实现这一目标:
SELECT *
FROM [dbo].[StudentPrograms] AS SP
INNER JOIN [dbo].[NameScalarHelper] AS NSH
ON NSH.UserID = SP.UserID
OUTER APPLY (
SELECT TOP (1) *
FROM [dbo].[AuditName] AS AN
WHERE AN.UserID = SP.UserID
AND (
RTRIM(AN.LastName) <> RTRIM(NSH.LastName)
OR RTRIM(AN.FirstName) <> RTRIM(NSH.FirstName)
OR RTRIM(AN.Suffix) <> RTRIM(NSH.Suffix)
OR RTRIM(AN.MaidenName) <> RTRIM(NSH.MaidenName)
)
ORDER BY AuditNameID DESC
) AS AN
WHERE SP.SiteProgramID = 139
AND SP.IsActive = 1;
这将从您的审核表中找到与最新名称不匹配的最新名称。
顺便说一下,我强烈建议您清理数据库并删除任何尾随/前导空格,这样您就不需要使用LTRIM()
或RTRIM()
了您的where子句,以便SQL Server能够使用索引。有关详情,请参阅this文章。
SELECT *
FROM [dbo].[StudentPrograms] AS SP
INNER JOIN [dbo].[NameScalarHelper] AS NSH
ON NSH.UserID = SP.UserID
OUTER APPLY (
SELECT TOP (1) *
FROM [dbo].[AuditName] AS AN
WHERE AN.UserID = SP.UserID
AND (
AN.LastName <> NSH.LastName
OR AN.FirstName <> NSH.FirstName
OR AN.Suffix <> NSH.Suffix
OR AN.MaidenNam) <> NSH.MaidenName
)
ORDER BY AuditNameID DESC
) AS AN
WHERE SP.SiteProgramID = 139
AND SP.IsActive = 1;
我试图了解您存储数据的方式并复制了一个小例子:
DECLARE @User TABLE
(
UserID INT
, FirstName VARCHAR(50)
, LastName VARCHAR(50)
);
DECLARE @Audit TABLE
(
AuditID INT IDENTITY(1, 1)
, UserID INT
, FirstName VARCHAR(50)
, LastName VARCHAR(50)
);
INSERT INTO @User (UserID, FirstName, LastName)
VALUES (1, 'Ben', 'White');
INSERT INTO @Audit (UserID, FirstName, LastName)
VALUES (1, 'Ben', 'White');
SELECT *
FROM @User AS U
OUTER APPLY (
SELECT TOP (1) *
FROM @Audit AS A
WHERE A.UserID = U.UserID
AND (
A.FirstName <> U.FirstName
OR A.LastName <> U.LastName
)
ORDER BY A.AuditID DESC
) AS A;
UPDATE U
SET U.LastName = 'Whiter'
FROM @User AS U
WHERE U.UserID = 1;
INSERT INTO @Audit (UserID, FirstName, LastName)
VALUES (1, 'Ben', 'Whiter');
SELECT *
FROM @User AS U
OUTER APPLY (
SELECT TOP (1) *
FROM @Audit AS A
WHERE A.UserID = U.UserID
AND (
A.FirstName <> U.FirstName
OR A.LastName <> U.LastName
)
ORDER BY A.AuditID DESC
) AS A;
UPDATE U
SET U.LastName = 'Whitest'
FROM @User AS U
WHERE U.UserID = 1;
INSERT INTO @Audit (UserID, FirstName, LastName)
VALUES (1, 'Ben', 'Whitest');
SELECT *
FROM @User AS U
OUTER APPLY (
SELECT TOP (1) *
FROM @Audit AS A
WHERE A.UserID = U.UserID
AND (
A.FirstName <> U.FirstName
OR A.LastName <> U.LastName
)
ORDER BY A.AuditID DESC
) AS A;
INSERT INTO @User (UserID, FirstName, LastName)
VALUES (2, 'Tom', 'Brooks');
INSERT INTO @Audit (UserID, FirstName, LastName)
VALUES (2, 'Tom', 'Brooks');
SELECT *
FROM @User AS U
OUTER APPLY (
SELECT TOP (1) *
FROM @Audit AS A
WHERE A.UserID = U.UserID
AND (
A.FirstName <> U.FirstName
OR A.LastName <> U.LastName
)
ORDER BY A.AuditID DESC
) AS A;
我假设您在创建用户时 - 还要将记录添加到Audit表以保持一致性。每次进行更新时 - 您还会将其记录到Audit表中。最后,我刚刚添加了另一个用户并运行了查询。
这是每个查询的输出:
用户已创建:
UserID FirstName LastName AuditID UserID FirstName LastName
------ --------- -------- ------- ------ --------- --------
1 Ben White null null null null
及其&#39;姓氏第一次被更改:
UserID FirstName LastName AuditID UserID FirstName LastName
------ --------- -------- ------- ------ --------- --------
1 Ben Whiter 1 1 Ben White
及其&#39;姓氏第二次被更改:
UserID FirstName LastName AuditID UserID FirstName LastName
------ --------- -------- ------- ------ --------- --------
1 Ben Whitest 2 1 Ben Whiter
添加了新用户:
UserID FirstName LastName AuditID UserID FirstName LastName
------ --------- -------- ------- ------ --------- --------
1 Ben Whitest 2 1 Ben Whiter
2 Tom Brooks null null null null
其他一切只是格式化,你不应该在SQL Server中这样做 - 这应该在应用层完成。
答案 1 :(得分:0)
通过查看您的查询,我猜测您正在收回所有人的姓氏,因为您没有基于您已创建的RankOrder的过滤器。我认为你的当前名字应该是RankOrder中的1,所以你最近的名字将被排名为2.你可以将它添加到派生表的where where子句中:
select nsh.AuthEmail, nsh.UserID, nsh.name_lastnamefirst, t.FormerName, t.RankOrder
from (
Select
an.AuditNameID, nsh.AuthEmail, nsh.UserID, nsh.name_lastnamefirst,
FormerName = CASE WHEN RTRIM(an.LastName) <> RTRIM(nsh.LastName) OR RTRIM(an.FirstName) <> RTRIM(nsh.FirstName) OR RTRIM(an.Suffix) <> RTRIM(nsh.Suffix) OR RTRIM(an.MaidenName)<>RTRIM(nsh.MaidenName) THEN LTRIM(an.LastName + ' ' + an.Suffix + ', ' + an.FirstName + ' ' + ISNULL(an.MiddleName,''))
ELSE null
END,
RANK() over (partition by an.UserID order by an.AuditNameID DESC) RankOrder
From [dbo].[AuditName] an
INNER JOIN dbo.StudentPrograms p ON an.UserID = p.UserID
INNER JOIN dbo.NameScalarHelper nsh ON p.UserID = nsh.UserID
WHERE p.SiteProgramID = 139 AND p.IsActive =1 and RankOrder = 2
) t
RIGHT OUTER JOIN dbo.NameScalarHelper nsh ON nsh.UserID = t.UserID
where FormerName is not null
如果我遗失了某些内容,请告诉我。