2015-02-06 111 views
1

我有一個這樣的表結構的共同祖先(其實有更多的層次):找到一個樹形結構表

------------------------------------------ 
|region1|region2|region3|region4|postcode| 
|-------|-------|-------|-------|--------| 
|a  |x  |i  |  |1  | 
|a  |y  |i  |  |2  | 
|a  |y  |j  |  |2  | 
|a  |z  |k  |  |3  | 
|b  |u  |m  |  |4  | 
|b  |  |n  |  |4  | 
|c  |  |  |  |5  | 
|c  |q  |  |  |6  | 
------------------------------------------ 

因此,例如,a => x => ia => y => i有不同的地方,但兩者在相同的區域1 a

我想知道每個郵政編碼可以覆蓋哪個區域。

例如,代碼2涵蓋區域a => y => ia => y => j,因此這些共同的祖先是a => y

這裏是關於例如運行查詢所需的輸出:

------------------------------------------ 
|postcode|region1|region2|region3|region4| 
|--------|-------|-------|-------|-------| 
|1  |a  |x  |i  |  | 
|2  |a  |y  |  |  | 
|3  |a  |z  |k  |  | 
|4  |b  |  |  |  | 
|5  |c  |  |  |  | 
|6  |c  |q  |  |  | 
------------------------------------------ 

我真的不知道如何攻擊這個問題。我想通過郵編分區,但這仍然留下找到每個分區內共同的祖先的問題...

+2

一個樹狀結構表是將每一行都有它的父行的引用的表。我不知道你在那裏做什麼,我不明白你用'a => x => i''表示的意思。另外,根據我的經驗,無論何時我遇到具有名稱列相似列的表僅有一個(數字或非數字)後綴的表時,某個人在某個地方不理解數據庫規範化。 – 2015-02-06 15:49:18

+0

這當然不是標準化的,我意識到這一點。我可能會這樣做,但如果有解決方案,我會感興趣。 'a => x => i'表示它是示例表中的第一行(region1 = a,region2 = x,region3 = i) – 2015-02-06 15:52:18

+1

查看https://msdn.microsoft.com/zh-cn/ gb/library/bb677173%28v = sql.110%29.aspx – Elliveny 2015-02-06 15:54:59

回答

2

這是一個非常混亂的解決方案,但它似乎給出了正確的答案。毫無疑問,需要相當多的工作來滿足您的實際需求,但也許這可能會幫助您指引某種方向!

-- Setup a test table 

DECLARE @tbl AS TABLE(R1 NVARCHAR(10), R2 NVARCHAR(10), R3 NVARCHAR(10), R4 NVARCHAR(10), PC NVARCHAR(10)); 

INSERT INTO @tbl(R1,R2,R3,R4,PC) VALUES ('a','x','i',NULL,'1'); 
INSERT INTO @tbl(R1,R2,R3,R4,PC) VALUES ('a','y','i',NULL,'2'); 
INSERT INTO @tbl(R1,R2,R3,R4,PC) VALUES ('a','y','j',NULL,'2'); 
INSERT INTO @tbl(R1,R2,R3,R4,PC) VALUES ('a','z','k',NULL,'3'); 
INSERT INTO @tbl(R1,R2,R3,R4,PC) VALUES ('b','u','m',NULL,'4'); 
INSERT INTO @tbl(R1,R2,R3,R4,PC) VALUES ('b',NULL,'n',NULL,'4'); 
INSERT INTO @tbl(R1,R2,R3,R4,PC) VALUES ('c',NULL,NULL,NULL,'5'); 
INSERT INTO @tbl(R1,R2,R3,R4,PC) VALUES ('c','q',NULL,NULL,'6'); 

-- Calculate the result: 

SELECT 
    PC, 
    CASE WHEN LVL1 = 1 THEN R1 ELSE NULL END AS R1, 
    CASE WHEN LVL2 = 1 THEN R2 ELSE NULL END AS R2, 
    CASE WHEN LVL3 = 1 THEN R3 ELSE NULL END AS R3, 
    CASE WHEN LVL4 = 1 THEN R4 ELSE NULL END AS R4 
FROM 
(
    SELECT 
     PC, 
     MAX(R1) AS R1, 
     MAX(R2) AS R2, 
     MAX(R3) AS R3, 
     MAX(R4) AS R4, 
     COUNT(DISTINCT ISNULL(R1,'.')) AS LVL1, 
     COUNT(DISTINCT ISNULL(R1,'.') + ISNULL(R2,'.')) AS LVL2, 
     COUNT(DISTINCT ISNULL(R1,'.') + ISNULL(R2,'.') + ISNULL(R3,'.')) AS LVL3, 
     COUNT(DISTINCT ISNULL(R1,'.') + ISNULL(R2,'.') + ISNULL(R3,'.') + ISNULL(R4,'.')) AS LVL4 
    FROM @tbl 
    GROUP BY PC 
) A 

最終結果與問題中的表格匹配。

+0

非常有用 - 我認爲我可以修改這些以用於我的真實數據......關於其他評論,我知道這很麻煩,我應該首先以不同的方式構造數據。所以,作爲一個重要的說明,我會接受這個答案。謝謝! – 2015-02-06 16:41:38

1

這個問題,而吸引了我,我想出了一個替代方案,這可能對您有用:

-- Setup test table 
DECLARE @InputTable TABLE (region1 varchar(2), region2 varchar(2), region3 varchar(2), region4 varchar(2), postcode varchar(2)) 

INSERT INTO @InputTable (region1, region2, region3, region4, postcode) 
      SELECT 'a','x','i',null,'1' 
UNION ALL SELECT 'a','y','i',NULL,'2' 
UNION ALL SELECT 'a','y','j',NULL,'2' 
UNION ALL SELECT 'a','z','k',NULL,'3' 
UNION ALL SELECT 'b','u','m',NULL,'4' 
UNION ALL SELECT 'b',NULL,'n',NULL,'4' 
UNION ALL SELECT 'c',NULL,NULL,NULL,'5' 
UNION ALL SELECT 'c','q',NULL,NULL,'6' 

-- Find the common ancestors 
;with totals as (
    select postcode, count(*) as postcodeCount from @InputTable group by postcode 
) 
, region4group as (
    select postcode, region1, region2, region3, region4 from @InputTable in1 
    group by postcode, region1, region2, region3, region4 having count(*)=(select postCodeCount from totals where totals.postcode=in1.postcode) 
) 
, region3group as (
    select * from region4group 
    union 
    select in1.postcode, in1.region1, in1.region2, in1.region3, null from @InputTable in1 
    left outer join region4group on region4group.postcode=in1.postcode 
    where region4group.postcode is null 
    group by in1.postcode, in1.region1, in1.region2, in1.region3 
    having count(*)=(select postCodeCount from totals where totals.postcode=in1.postcode) 
) 
, region2group as (
    select * from region3group 
    union 
    select in1.postcode, in1.region1, in1.region2, null, null from @InputTable in1 
    left outer join region3group on region3group.postcode=in1.postcode 
    where region3group.postcode is null 
    group by in1.postcode, in1.region1, in1.region2 
    having count(*)=(select postCodeCount from totals where totals.postcode=in1.postcode) 
) 
, commonancestors as (
    select * from region2group 
    union 
    select in1.postcode, in1.region1, null, null, null from @InputTable in1 
    left outer join region2group on region2group.postcode=in1.postcode 
    where region2group.postcode is null 
    group by in1.postcode, in1.region1 
    having count(*)=(select postCodeCount from totals where totals.postcode=in1.postcode) 
) 
select * from commonancestors