【问题标题】:Easier way to reverse the order of a canonical name更简单的方法来反转规范名称的顺序
【发布时间】:2022-05-06 10:02:53
【问题描述】:

我想知道是否有更简单的方法可以在 SQL 中反转 Active Directory 规范名称。我找到了一种方法来做到这一点,但它只适用于一定数量的 OU,我希望它适用于任意数量的 OU。

例如:我想使用规范名称为“domain.org/company/users/department/john smith”的一行并反转字符串顺序,使其显示“John Smith/department/users/company /domain.org"

为此,我使用了从其他帖子中找到的几种不同的 XML 方法。下面的代码将字符串转换为 XML 并计算值中的节点数。然后它使用 case 语句将字符串以相反的顺序连接在一起。

正如您在 case 语句中看到的那样,我必须将所有可能数量的节点都放入 case 语句中,以便当前可以正常工作。如果可能的话,我想计算节点计数并通过节点倒计时向后循环,但我不确定如何使用 SQL 来实现这一点,或者是否有更好的方法来完成我正在尝试做的事情。

  SELECT *
        ,CASE 
           WHEN NodeCount = 4 
             THEN CONCAT('"',MyXML.value('/root[1]/i[4]','varchar(100)'),'/',MyXML.value('/root[1]/i[3]','varchar(100)'),'/',MyXML.value('/root[1]/i[2]','varchar(100)'),'/',MyXML.value('/root[1]/i[1]','varchar(100)'),'"')
           WHEN NodeCount = 5 
             THEN CONCAT('"',MyXML.value('/root[1]/i[5]','varchar(100)'),'/',MyXML.value('/root[1]/i[4]','varchar(100)'),'/',MyXML.value('/root[1]/i[3]','varchar(100)'),'/',MyXML.value('/root[1]/i[2]','varchar(100)'),'/',MyXML.value('/root[1]/i[1]','varchar(100)'),'"')
           WHEN NodeCount = 6 
             THEN CONCAT('"',MyXML.value('/root[1]/i[6]','varchar(100)'),MyXML.value('/root[1]/i[5]','varchar(100)'),'/',MyXML.value('/root[1]/i[4]','varchar(100)'),'/',MyXML.value('/root[1]/i[3]','varchar(100)'),'/',MyXML.value('/root[1]/i[2]','varchar(100)'),'/',MyXML.value('/root[1]/i[1]','varchar(100)'),'"')
        END AS ReversedPath
  FROM (
    SELECT CanonicalName
           ,(CONVERT(XML, '<root><i>' + REPLACE(CanonicalName , '/', '</i><i>') + '</i></root>').query('.')) MyXML
           ,(CONVERT(XML, '<root><i>' + REPLACE(CanonicalName , '/', '</i><i>') + '</i></root>').value('count(/root/i)', 'INT')) NodeCount 
    FROM  dbo.[GetActiveDirectoryUsers] 
    WHERE AccountIsEnabled = 'True') T

如果有人对解决此问题的其他方法有一些想法,我们将不胜感激。

供参考:我使用这些脚本用我的 AD 用户信息填充 SQL 表。 https://www.sqlservercentral.com/articles/powershell-to-get-active-directory-users-and-groups-into-sql

编辑:按照 Kevin 的建议,使用下面的代码创建了一个缩放器值函数。

ALTER FUNCTION [dbo].[fnReverseString] (@string varchar(500),@splitChar varchar(1)) 


RETURNS varchar(500)
AS
BEGIN
DECLARE @rev varchar(500);

with cte as 
(
   select 1 pos_from, charindex(@splitChar, @string) + 1 pos_to
      union all
   select pos_to, charindex(@splitChar, @string + @splitChar, pos_to) + 1
      from cte
   where pos_to <= len(@string)
)

select @rev = coalesce( @rev + @splitChar, '') + substring(@string, pos_from, pos_to - pos_from - 1) 
from cte
order by pos_to desc

return @rev
END

现在我可以从我的查询中调用它并为供应商创建请求的输出。再次感谢!

WITH CTE1 AS (
SELECT dbo.fnReverseString(CanonicalName,'/') ReversedPath
FROM dbo.[GetActiveDirectoryUsers] 
WHERE AccountIsEnabled = 'True'
)

SELECT '[' + STUFF((SELECT ',' + CONCAT('"',ReversedPath,'"')  AS [text()] FROM CTE1 FOR XML PATH ('')), 1, 1, '') + ']' FinalResult

输出

["John Smith/department/users/company/domain.org","Jane Smith/department/users/company/domain.org"]

【问题讨论】:

  • 您可以使用循环或 cte 来完成,我认为这两种方式都是更简单/更好的方式。

标签: sql-server


【解决方案1】:

以下是使用 CTE 的方法(修改自这篇帖子 Reverse Order of Words

declare @domain varchar(500), @rev varchar(500)

set @domain = 'domain.org/company/users/department/john smith'


;with cte as 
(
   select 1 pos_from, charindex('/', @domain) + 1 pos_to
      union all
   select pos_to, charindex('/', @domain + '/', pos_to) + 1
      from cte
   where pos_to <= len(@domain)
)
select @rev = coalesce( @rev + '/', '') +substring(@domain, pos_from, pos_to - pos_from - 1) 
from cte
order by pos_to desc

select @rev

【讨论】:

  • 谢谢凯文,这更干净了。感谢您的帮助!
猜你喜欢
  • 2015-11-29
  • 2019-12-24
  • 1970-01-01
  • 1970-01-01
  • 2012-12-18
  • 1970-01-01
  • 2012-07-21
  • 2012-12-26
  • 2021-10-14
相关资源
最近更新 更多