【发布时间】:2017-12-18 04:33:45
【问题描述】:
这个问题相当广泛,请多多包涵。我有一个具有以下结构的映射表:
此特定表用于生成层次结构的过程。表中列的顺序和位置表示层次结构的顺序(组织、类别、大陆、国家……等)。此层次结构中的每个实体都有一个相关的表,关联的Id 和Name。例如,有一个带有CountryId 和CountryName 的Country 表。请注意,由于 MappingTable 的值都可以为空,因此 没有外键约束。
我想生成一个执行以下操作的过程:
根据提供的条件,检索层次结构中下一个实体的值。比如给定OrganizationId和CategoryId,则需要取出满足上述条件的ContinentId的值。
另外,如果ContinentId 的值为NULL,则需要检索CountryId 的值。在这里,给定条件OrganizationId = 1 and CategoryId = 1,过程应该返回RegionId的列表。
除了检索RegionId之外,还应从Region表中检索对应的RegionName。
到目前为止,该过程看起来是这样的 - 这里只需要解释几件事。
ALTER PROCEDURE [dbo].[GetHierarchy]
(
@MappingTableName VARCHAR(30),
@Position VARCHAR(5),
-- Given in the form of Key-value pairs 'OrganizationId:1,CategoryId:1'
@InputData VARCHAR(MAX),
@Separator CHAR(1),
@KeyValueSeperator CHAR(1)
)
AS
BEGIN
DECLARE @Sql NVARCHAR(MAX)
DECLARE @Result NVARCHAR(MAX)
DECLARE @Sql1 NVARCHAR(MAX);
DECLARE @TableName NVARCHAR(30)
DECLARE @Exists bit
SELECT @TableName = COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @MappingTableName AND ORDINAL_POSITION = @position
SET @TableName = SUBSTRING(@TableName,0,LEN(@TableName) - 1)
-- Returns a dynamic query like "SELECT ContinentId from Continent WHERE OrganizationId = 1 and CategoryId = 1".
SELECT @Sql = [dbo].[KeyValuePairs](@TableName, @InputData, @Separator, @KeyValueSeperator)
SET @Sql1 = N'SET @Exists = CASE WHEN EXISTS(' + @Sql + N' AND ' + @TableName + N'Id IS NOT NULL) THEN 1 ELSE 0 END'
PRINT @Sql
EXEC sp_executesql @Sql1,
N'@Exists bit OUTPUT',
@Exists = @Exists OUTPUT
IF(@Exists = 1)
BEGIN
SET @Sql1 = 'SELECT ' + @TableName + 'Id, ' + @TableName + 'Name FROM '+ @TableName+' WHERE ' + @TableName +'Id IN (' + @Sql + ')';
PRINT @Sql1
EXECUTE sp_executesql @SQL1
END
ELSE
BEGIN
--PRINT 'NOT EXISTS'
DECLARE @nextPosition INT
SELECT @nextPosition = CAST(@position AS INT)
SET @nextPosition = @nextPosition + 1
SET @Position = CONVERT(VARCHAR(5), CAST(@position AS INT))
EXEC [dbo].[GetHierarchy] @MappingTableName, @Position, @InputData, @Separator, @KeyValueSeperator
END
END
这个过程的逻辑是,我在特定位置获取列的名称(根据这里的条件,它是Continent)并生成动态查询以根据输入条件的条件(我正在使用单独的函数为我执行此操作)。
检索到后,我运行查询以检查它是否返回任何行。如果查询返回行,则我从Continent 表中检索相应的ContinentName。如果没有返回行,我会以下一个位置作为输入再次递归调用该过程。
在业务方面,这似乎是一个两步过程。但是,作为一个过程,它非常复杂、广泛,而且——更不用说是递归的了。有没有更简单的方法来做到这一点?我对 CTE 不熟悉 - 可以使用 CTE 实现相同的逻辑吗?
【问题讨论】:
标签: sql-server stored-procedures dynamic-sql