Microsoft SQL Server 데이터베이스 중 하나에 대한 쿼리에 문제가 있습니다. 다음 표와보기는 간략하게하기 위해 단순화되었지만 문제를 설명하는 역할을합니다.SQL Server 재귀 쿼리 문제
각 테이블의 점수는 직계 자녀의 평균으로 계산됩니다. 뷰는 고정 된 구조로는 충분하지만 현재 중첩 된 세트 형식 인 위치 계층 구조와 더 복잡해집니다. 사용자가 정의한 위치 계층에는 고정 된 수의 계층이 없습니다.
재귀 CTE를 사용하여이 문제를 해결했지만 재귀 부분에서 집계를 허용하지 않았습니다.
CREATE TABLE [dbo].[locations_main](
[id] [smallint] NOT NULL,
[name] [nchar](50) NOT NULL,
[lft] [smallint] NOT NULL,
[rgt] [smallint] NOT NULL,
[parent_id] [smallint] NULL,
CONSTRAINT [PK_locations_main] PRIMARY KEY CLUSTERED ([id] ASC)
)
GO
INSERT INTO [dbo].[locations_main] VALUES
(1, 'location 1', 1, 16, NULL),
(2, 'location 1-1', 2, 9, 1),
(3, 'location 1-1-1', 3, 4, 2),
(4, 'location 1-1-2', 5, 6, 2),
(5, 'location 1-1-3', 7, 8, 2),
(7, 'location 1-2', 10, 15, 1),
(8, 'location 1-2-1', 11, 12, 7),
(9, 'location 1-2-2', 13, 14, 7)
GO
CREATE TABLE [dbo].[outcomes](
[id] [smallint] NOT NULL,
[location_id] [smallint] NOT NULL,
[name] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_outcomes] PRIMARY KEY CLUSTERED ([id] ASC)
)
GO
INSERT INTO [dbo].[outcomes] VALUES
(1, 3, 'outcome 1'),
(2, 4, 'outcome 2'),
(3, 5, 'outcome 3'),
(4, 8, 'outcome 4'),
(5, 9, 'outcome 5')
GO
CREATE TABLE [dbo].[prompts](
[id] [smallint] NOT NULL,
[outcome_id] [smallint] NOT NULL,
[name] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_prompts] PRIMARY KEY CLUSTERED ([id] ASC)
)
GO
INSERT INTO [dbo].[prompts] VALUES
(1, 1, 'prompt 1'),
(2, 2, 'prompt 2'),
(3, 3, 'prompt 3'),
(4, 4, 'prompt 4'),
(5, 5, 'prompt 5')
GO
CREATE TABLE [dbo].[subprompts](
[id] [smallint] NOT NULL,
[prompt_id] [smallint] NOT NULL,
[name] [nvarchar](50) NOT NULL,
[score] [smallint] NOT NULL,
CONSTRAINT [PK_subprompts] PRIMARY KEY CLUSTERED ([id] ASC)
)
GO
INSERT INTO [dbo].[subprompts] VALUES
(1, 1, 'subprompt 1', 1),
(2, 1, 'subprompt 2', 1),
(3, 2, 'subprompt 3', 1),
(4, 2, 'subprompt 4', 3),
(5, 3, 'subprompt 5', 2),
(6, 3, 'subprompt 6', 4),
(7, 4, 'subprompt 7', 1),
(8, 4, 'subprompt 8', 5),
(9, 5, 'subprompt 9', 3),
(10, 5, 'subprompt 10', 3)
GO
CREATE VIEW [dbo].[vw_prompts]
AS
SELECT
dbo.prompts.id,
dbo.prompts.outcome_id,
dbo.prompts.name,
AVG(dbo.subprompts.score) AS score
FROM dbo.prompts
LEFT OUTER JOIN dbo.subprompts
ON dbo.prompts.id = dbo.subprompts.prompt_id
GROUP BY
dbo.prompts.id,
dbo.prompts.outcome_id,
dbo.prompts.name
GO
CREATE VIEW [dbo].[vw_outcomes]
AS
SELECT
dbo.outcomes.id,
dbo.outcomes.location_id,
dbo.outcomes.name,
AVG(dbo.vw_prompts.score) AS score
FROM dbo.outcomes
LEFT OUTER JOIN dbo.vw_prompts
ON dbo.outcomes.id = dbo.vw_prompts.id
GROUP BY
dbo.outcomes.id,
dbo.outcomes.location_id,
dbo.outcomes.name
GO
쿼리는 아래의 모든 위치를 검색하지만, 리프 노드에서하지 해당 위치의 직계 자식 평균값을 계산 -
SELECT loc_main_ag.name, AVG(CAST(vw_outcomes.score AS FLOAT))
FROM locations_main loc_main_ag
LEFT JOIN locations_main loc_main
ON loc_main_ag.lft <= loc_main.lft
AND loc_main_ag.rgt >= loc_main.rgt
INNER JOIN vw_outcomes
ON loc_main.id = vw_outcomes.location_id
GROUP BY loc_main_ag.name
반환
location 1 2.4
location 1-1 2
location 1-1-1 1
location 1-1-2 2
location 1-1-3 3
location 1-2 3
location 1-2-1 3
location 1-2-2 3
"위치를 1 "은 평균"위치 1-1-1 ","위치 1-1-2 ","위치 1-1-3 ","위치 1-2-1 "및"위치 1-2-2 " - "위치 1-1"및 "위치"의 평균 대신에 (1 + 2 + 3 + 3 + 3)/5 = 2.4 n은 1-2 "- 나는 CTE를 사용하여이 문제를 해결하기 위해 노력하지만, CTE의 재귀 부분에서 GROUP BY와 집계 함수를 사용하여 문제를 충돌 (2 + 3)/2 = 2.5
-
WITH location_scores
AS
(
-- Anchor member definition
-- Get score for all leaf node locations
SELECT locations_main.id, locations_main.name, locations_main.parent_id, AVG(CAST(vw_outcomes.score AS FLOAT)) AS score
FROM locations_main
INNER JOIN vw_outcomes
ON locations_main.id = vw_outcomes.location_id
WHERE locations_main.rgt - locations_main.lft = 1
GROUP BY locations_main.id, locations_main.name, locations_main.parent_id
UNION ALL
-- Recursive member definition
-- Rollup through locations parents to build averages
SELECT locations_main.id, locations_main.name, locations_main.parent_id, AVG(CAST(location_scores.score AS FLOAT)) AS score
FROM locations_main
INNER JOIN vw_outcomes
ON locations_main.id = vw_outcomes.location_id
INNER JOIN location_scores
ON locations_main.id = location_scores.parent_id
GROUP BY locations_main.id, locations_main.name, locations_main.parent_id
)
-- Statement that executes the CTE
SELECT *
FROM location_scores
업데이트 : 여기 테이블 값 기능에 대한 시도입니다. 여기에 포함 된 단순화 된 예제를 기반으로 올바른 결과를 반환하지만 이것이 어떻게 확장 될지 걱정됩니다. 야생에서 실행되는 계층 구조는 15^5 레코드의 어딘가에있을 수 있습니다.
CREATE FUNCTION scores() RETURNS
@result TABLE
(
id SMALLINT,
name NVARCHAR(50),
lft SMALLINT,
rgt SMALLINT,
parent_id SMALLINT,
score FLOAT,
[level] SMALLINT
) AS
BEGIN
DECLARE @level INT
SET @level = 1
INSERT INTO @result
SELECT
locations_main.id,
locations_main.name,
locations_main.lft,
locations_main.rgt,
locations_main.parent_id,
AVG(CAST(vw_outcomes.score AS FLOAT)) AS score,
@level AS [level]
FROM locations_main
INNER JOIN vw_outcomes
ON locations_main.id = vw_outcomes.location_id
WHERE locations_main.rgt - locations_main.lft = 1
GROUP BY
locations_main.id,
locations_main.name,
locations_main.lft,
locations_main.rgt,
locations_main.parent_id
WHILE (SELECT COUNT(*) FROM @result WHERE level = @level AND parent_id IS NOT NULL) > 0 BEGIN
INSERT INTO @result
SELECT
locations_main.id,
locations_main.name,
locations_main.lft,
locations_main.rgt,
locations_main.parent_id,
AVG(CAST(res.score AS FLOAT)) AS score,
(@level + 1) AS [level]
FROM locations_main
INNER JOIN @result res
ON locations_main.id = res.parent_id
AND res.level = @level
GROUP BY
locations_main.id,
locations_main.name,
locations_main.lft,
locations_main.rgt,
locations_main.parent_id
SET @level = @level + 1
END
RETURN
END
이 방법이 적절한 방법인지 아닌지에 관해서는 정말 고마워 할 것입니다.
귀하의 데이터가 어떻게 보이고 어떤 결과가 기대되는지는 분명하지 않기 때문에 귀하의 질문은 명확하지 않습니다. 당신이 달성하고자하는 것을 정확히 보여주는 간단한 테스트 케이스를 게시 할 수 있습니까? 테스트 케이스는 실제 테이블이나 데이터를 사용할 필요가 없으며 요구 사항을 설명하기 만하면됩니다. – Pondlife