我有两个标量值函数,它们以用户ID和角色ID作为参数。第一个GetCountries
返回以逗号分隔的国家/地区列表。第二个GetBusinesses
返回以逗号分隔的业务列表。我将每个结果传递给一个名为StringSplit
的表值函数,该函数返回一个单列表,其中每个值对应一行。然后,我交叉加入各个国家和企业,以获取所有组合。
问题是我不仅拥有一个角色ID,而且拥有一组角色ID。我可以使用光标,一次又一次地重复此过程,以获取国家和企业的完整列表,但是光标很慢,我想知道是否还有更高效的方法。
如果只有一个角色ID,这就是它的工作方式。
SELECT [Data] AS Countries INTO #TempCountries FROM StringSplit(GetCountries(@UserID, @RoleID), ',')
SELECT [Data] AS Businesses INTO #TempBus FROM StringSplit(GetBusinesses(@UserID, @RoleID), ',')
SELECT Countries, Businesses INTO #CountryBusCombo FROM #TempCountries CROSS JOIN #TempBus
DROP TABLE #TempCountries
DROP TABLE #TempBus
但实际上,我有以下角色ID的列表:
SELECT RoleID FROM UserRoles WHERE UserID = @UserID
因此,我必须重复执行上述操作,直到在#CountryBusCombo中具有每个不同角色ID的所有国家和企业组合为止。
有没有游标的方法吗?
-编辑 是的,代码库很糟糕。我正在使用已经存在的内容来尝试保持一致性,但是如果现有基础结构非常糟糕并且不会引入回归错误,我可以自己动手做。
这里是GetCountries
SELECT @CountryCodes = ISNULL((SELECT Country FROM HierarchyMap WHERE UserID = @UserID AND RoleID = @RoleID),'')
这里是GetBusinesses
SELECT @Businesses = ISNULL((SELECT Business FROM HierarchyMap WHERE UserID = @UserID AND RoleID = @RoleID ),'')
还有StringSplit
ALTER FUNCTION StringSplit
(
@RowData NVARCHAR(MAX) ,
@SplitOn NVARCHAR(5)
)
RETURNS @ReturnValue TABLE ( Data NVARCHAR(MAX) )
AS
BEGIN
DECLARE @Counter INT
SET @Counter = 1
WHILE ( CHARINDEX(@SplitOn, @RowData) > 0 )
BEGIN
INSERT INTO @ReturnValue
( data
)
SELECT Data = LTRIM(RTRIM(SUBSTRING(@RowData, 1,
CHARINDEX(@SplitOn,
@RowData) - 1)))
SET @RowData = SUBSTRING(@RowData,
CHARINDEX(@SplitOn, @RowData) + 1,
LEN(@RowData))
SET @Counter = @Counter + 1
END
INSERT INTO @ReturnValue
( data )
SELECT Data = LTRIM(RTRIM(@RowData))
RETURN
END
-编辑2 因此,起点是HierarchyMap表,其中有如下所示的记录:
UserID|RoleID|Countries|Businesses
Bob|role1|AU,GB|Bus1,Bus2,Bus3
Bob|role2|BE|Bus4
预期结果:
Country|Business
AU|Bus1
AU|Bus2
AU|Bus3
GB|Bus1
GB|Bus2
GB|Bus3
BE|Bus4
答案 0 :(得分:2)
我在这里完全不知所措,但是您的表格似乎已经以分隔格式存储了国家和地区;因此当您已经存储定界数据时,在功能GetCountries
和GetBusiness
中看不到重点。因此,我正在猜测表和列的名称,但是您应该能够通过以下方式做到这一点:
SELECT C.Item AS Country,
B.Item AS Business
FROM dbo.Users U --What ever table has your users in
JOIN dbo.UsersInRoles UR ON U.UserID = UR.UserID --What ever table has your many to many relationship for roles
JOIN dbo.Roles R ON UR.RoleID = R.RoleID --What ever table has all your roles
JOIN dbo.HierarchyMap HM ON U.UserID = HM.UserID
AND R.RoleID = HM.RoleID
CROSS APPLY dbo.DelimitedSplit8K_LEAD(HM.Countries,',') C
CROSS APPLY dbo.DelimitedSplit8K_LEAD(HM.Businesses,',') B;
我不使用拆分器的原因是因为它是多行表值函数,并且使用WHILE
。恐怕它会非常糟糕。 Jeff,Eirikur和SSC社区的其他成员在上述功能上所做的工作将在一周的任何一天完成。
尽管理想情况下,您需要修复该设计,这确实很糟糕。我很乐意为您提供帮助,但是我确实需要一些适当的消耗性数据来实现这一目标。
编辑:注释中的OP表示存在诸如'AU,CA,,BE'
之类的值,但是,这些值已从其样本数据中排除。如果您确实有这样的行,请添加一个WHERE
:
WHERE C.item <> ''
AND B.item <> '';
答案 1 :(得分:1)
您只想要cross apply
吗?
SELECT c.value as country, b.value as business
FROM UserRoles ur cross apply
StringSplit(GetCountries(@UserID, ur.RoleID), ',') c CROSS APPLY
StringSplit(GetBusinesses(@UserID, ur.RoleID), ',') b;
WHERE ur.UserID = @UserID