你有一张可容纳42,400行的表。这对于SQL标准来说非常小。
该表保存设施的位置,并设计为父/子关系。
CREATE TABLE [dbo].[Location](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ParentLocationId] [int] NULL,
[Description] [varchar](100) NOT NULL,
[LocationTypeId] [int] NOT NULL,
[IsDeleted] [bit] NOT NULL,
CONSTRAINT [pk_Location] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
它有一个LocationType表的外键,它有5行。
ALTER TABLE [dbo].[Location] WITH CHECK ADD CONSTRAINT [fk_location_locationtype] FOREIGN KEY([LocationTypeId])
REFERENCES [ref].[LocationType] ([Id])
GO
它还有一个自我加入。
ALTER TABLE [dbo].[Location] WITH CHECK ADD CONSTRAINT [fk_LocationLocation] FOREIGN KEY([ParentLocationId])
REFERENCES [dbo].[Location] ([Id])
GO
父母可以有很多孩子。但是,我们有固定数量的位置级别。并且查询了位置信息。
所以,我已经实现了一个视图来获取位置数据。
它有点长,所以它位于底部,但是,想法是填充一排耳朵水平,然后加入它的孩子,做一个联合并返回结果集。
例如:
选择位置级别= 1(根)的位置 然后 选择位置级别为2的位置,并加入其父级。 然后 选择位置级别为3的位置并加入其父母及其父母。
现在这似乎是一个性能问题。有没有更好的方法来实现我正在寻找的结果,即每个位置一行...
第一行是根节点...... 第二个是根,是它的第一个孩子 第三个是它的第二个孩子的根源。
在特定位置进行选择的示例:
SELECT
l1.Id as LocationId,
l1.LocationTypeId,
lt.DisplayName,
l1.ParentLocationId,
l1.Description AS thisLocationName,
l1.IsDeleted,
l1.Description AS Level1,
NULL AS Level2,
NULL AS Level3,
NULL AS Level4,
NULL AS Level5,
NULL AS Level6,
NULL AS Level7,
NULL AS Level8,
NULL AS Level9,
NULL AS Level10
FROM [dbo].Location l1
INNER JOIN ref.LocationType lt
ON lt.Id = l1.LocationTypeId
AND lt.level = 1
UNION
SELECT
l2.Id AS LocationId,
l2.LocationTypeId,
lt.DisplayName,
l2.ParentLocationId,
l2.Description AS thisLocationName,
l1.IsDeleted | l2.IsDeleted,
l1.Description AS Level1,
l2.Description AS Level2,
NULL AS Level3,
NULL AS Level4,
NULL AS Level5,
NULL AS Level6,
NULL AS Level7,
NULL AS Level8,
NULL AS Level9,
NULL AS Level10
FROM [dbo].Location l1
INNER JOIN [dbo].Location l2
ON l2.ParentLocationId = l1.Id
INNER JOIN ref.LocationType lt
ON lt.Id = l2.LocationTypeId
AND lt.level = 2
UNION
SELECT
l3.Id AS LocationId,
l3.LocationTypeId,
lt.DisplayName,
l3.ParentLocationId,
l3.Description AS thisLocationName,
l1.IsDeleted | l2.IsDeleted | l2.IsDeleted,
l1.Description AS Level1,
l2.Description AS Level2,
l3.Description AS Level3,
NULL AS Level4,
NULL AS Level5,
NULL AS Level6,
NULL AS Level7,
NULL AS Level8,
NULL AS Level9,
NULL AS Level10
FROM [dbo].Location l1
INNER JOIN [dbo].Location l2
ON l2.ParentLocationId = l1.Id
INNER JOIN [dbo].Location l3
ON l3.ParentLocationId = l2.Id
INNER JOIN ref.LocationType lt
ON lt.Id = l3.LocationTypeId
AND lt.level = 3
UNION
.... (This occurs for 10 levels)
这里有表格的演示数据。
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(1, NULL, 'A Building', 1)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(2, 1, '1st Floor', 2)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(3, 1, '2nd Floor', 2)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(4, 1, '3rd Floor', 2)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(5, 1, '4th Floor', 2)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(6, 1, 'Boardroom', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(7, 1, 'Main Office', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(8, 1, 'Directors Office', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(9, 1, 'Kitchen', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(10, 2, 'Office', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(11, 2, 'Meeting Room', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(12, 2, 'Kitchen', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(13, 2, 'Gents WC', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(14, 2, 'Ladies WC', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(15, 3, 'Office 1', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(16, 3, 'Office 2', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(17, 3, 'Office 3', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(18, 3, 'Office 4', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(19, 3, 'Meeting Room', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(20, 3, 'Staff Room', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(21, 4, 'Small Office', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(22, 4, 'Medium', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(23, 4, 'Large Office', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(24, 4, 'Meeting Room', 3)
我尝试过以下推荐的CTE版本:
CREATE VIEW [dbo].[vwLocations3]
WITH SchemaBinding
AS
with h as (
select l.Id, l.ParentLocationId, l.Description, l.LocationTypeId, l.IsDeleted
, convert(varchar(100), null) level2
, convert(varchar(100), null) level3
, convert(varchar(100), null) level4
, convert(varchar(100), null) level5
, convert(varchar(100), null) level6
, convert(varchar(100), null) level7
, convert(varchar(100), null) level8
, convert(varchar(100), null) level9
from dbo.Location l
where ParentLocationId IS NULL
UNION ALL
select l.Id, l.ParentLocationId, l.Description, l.LocationTypeId, l.IsDeleted
, case when l.LocationTypeId = 2 then l.Description when l.LocationTypeId > 2 then h.Description end level2
, case when l.LocationTypeId = 3 then l.Description when l.LocationTypeId > 3 then h.Description end level3
, case when l.LocationTypeId = 4 then l.Description when l.LocationTypeId > 4 then h.Description end level4
, case when l.LocationTypeId = 5 then l.Description when l.LocationTypeId > 5 then h.Description end level5
, case when l.LocationTypeId = 6 then l.Description when l.LocationTypeId > 6 then h.Description end level6
, case when l.LocationTypeId = 7 then l.Description when l.LocationTypeId > 7 then h.Description end level7
, case when l.LocationTypeId = 8 then l.Description when l.LocationTypeId > 8 then h.Description end level8
, case when l.LocationTypeId = 9 then l.Description when l.LocationTypeId > 9 then h.Description end level9
from h
inner join dbo.Location l on l.ParentLocationId = h.id
)
SELECT
h.Id AS LocationId,
h.LocationTypeId,
lt.DisplayName,
h.ParentLocationId,
h.Description AS thisLocationName,
--h.Level1,
h.Level2,
h.Level3,
h.Level4,
h.Level5,
h.Level6,
h.Level7,
h.Level8,
h.Level9
--cte.Level10
FROM h
INNER JOIN ref.LocationType lt
ON lt.Id = h.LocationTypeId
但是这将在1,500毫秒内返回一个选择。
答案 0 :(得分:0)
尝试递归CTE(公用表表达式),例如
WHERE
with h as (
select l.Id, l.ParentLocationId, l.Description, l.LocationTypeId, l.IsDeleted
, convert(varchar(100), null) l2desc
, convert(varchar(100), null) l3desc
from Location l
where ParentLocationId IS NULL
UNION ALL
select l.Id, l.ParentLocationId, l.Description, l.LocationTypeId, l.IsDeleted
, case when l.LocationTypeId = 2 then l.Description when l.LocationTypeId > 2 then h.Description end l2desc
, case when l.LocationTypeId = 3 then l.Description when l.LocationTypeId > 3 then h.Description end l3desc
from h
inner join Location l on l.ParentLocationId = h.id
)
select
*
from h
order by LocationTypeId, ParentLocationId
;