我正在尝试使用 SQL 查询来查找某个市镇的前身市镇,或者如果有的话,其他前身市镇。
这是我的输入表(MUNICIPALMERGE):
city_id | 有效年份 | 有效期至 | predecessor_municipality_id |
---|---|---|---|
1000 | 1990 | 1995 | 空 |
1001 | 1996 | 2000 | 1000 |
1002 | 2001 | 2005 | 1001 |
1003 | 1990 | 2005 | 空 |
我的目标是一张表格,显示相应年份哪个城市有效。对于上面的例子,正确的表格如下:
年 | city_id | valid_municipality_id |
---|---|---|
1990 | 1000 | 1000 |
1991 | 1000 | 1000 |
1992 | 1000 | 1000 |
1993 | 1000 | 1000 |
1994 | 1000 | 1000 |
1995 | 1000 | 1000 |
1996 | 1000 | 1001 |
1997 | 1000 | 1001 |
1998 | 1000 | 1001 |
1999 | 1000 | 1001 |
2000 | 1000 | 1001 |
2001 | 1000 | 1002 |
2002 | 1000 | 1002 |
2003 | 1000 | 1002 |
2004年 | 1000 | 1002 |
2005 | 1000 | 1002 |
1990 | 1001 | 1000 |
1991 | 1001 | 1000 |
1992 | 1001 | 1000 |
1993 | 1001 | 1000 |
1994 | 1001 | 1000 |
1995 | 1001 | 1000 |
1996 | 1001 | 1001 |
1997 | 1001 | 1001 |
1998 | 1001 | 1001 |
1999 | 1001 | 1001 |
2000 | 1001 | 1001 |
2001 | 1001 | 1002 |
2002 | 1001 | 1002 |
2003 | 1001 | 1002 |
2004年 | 1001 | 1002 |
2005 | 1001 | 1002 |
1990 | 1002 | 1000 |
1991 | 1002 | 1000 |
1992 | 1002 | 1000 |
1993 | 1002 | 1000 |
1994 | 1002 | 1000 |
1995 | 1002 | 1000 |
1996 | 1002 | 1001 |
1997 | 1002 | 1001 |
1998 | 1002 | 1001 |
1999 | 1002 | 1001 |
2000 | 1002 | 1001 |
2001 | 1002 | 1002 |
2002 | 1002 | 1002 |
2003 | 1002 | 1002 |
2004年 | 1002 | 1002 |
2005 | 1002 | 1002 |
1990 | 1003 | 1003 |
1991 | 1003 | 1003 |
1992 | 1003 | 1003 |
1993 | 1003 | 1003 |
1994 | 1003 | 1003 |
1995 | 1003 | 1003 |
1996 | 1003 | 1003 |
1997 | 1003 | 1003 |
1998 | 1003 | 1003 |
1999 | 1003 | 1003 |
2000 | 1003 | 1003 |
2001 | 1003 | 1003 |
2002 | 1003 | 1003 |
2003 | 1003 | 1003 |
2004年 | 1003 | 1003 |
2005 | 1003 | 1003 |
这意味着应为每个城市找到相应的前任或后继城市(如果有)。
这是否可能?如果可能,如何实现?
非常感谢您的帮助。
我尝试了下面的查询,但在 Valid_minicipality_id 列中得到了一些空值。
WITH
YEARS AS
(
SELECT
1990 AS YEAR
UNION ALL
SELECT
YEAR+1
FROM
YEARS
WHERE
YEAR+1<=2005--YEAR(GETDATE())
)
--SELECT * FROM YEARS;
, YEARS_MUNICIPALITY AS
(
SELECT
Y.YEAR
, MM.MUNICIPALITY_ID
, ISNULL(MM.PREDECESSOR_MUNICIPALITY_ID, MM.MUNICIPALITY_ID) AS PREDECESSOR_MUNICIPALITY_ID
FROM
YEARS Y
INNER JOIN
MUNICIPALMERGE MM
ON
Y.YEAR BETWEEN MM.VALID_YEAR_FROM AND MM.VALID_YEAR_TO
)
--SELECT * FROM YEARS_MUNICIPALITY;
, ALL_YEARS_MUNICIPALITY AS
(
SELECT
Y.YEAR
, MM.MUNICIPALITY_ID
, MM.PREDECESSOR_MUNICIPALITY_ID
FROM
YEARS Y
CROSS JOIN
MUNICIPALMERGE MM
)
--SELECT * FROM ALL_YEARS_MUNICIPALITY;
SELECT
AYM.YEAR
, AYM.MUNICIPALITY_ID
, YM.MUNICIPALITY_ID AS VALID_MUNICIPALITY_ID
FROM
ALL_YEARS_MUNICIPALITY AYM
LEFT JOIN
YEARS_MUNICIPALITY YM
ON
AYM.YEAR=YM.YEAR
AND AYM.MUNICIPALITY_ID=YM.PREDECESSOR_MUNICIPALITY_ID
ORDER BY
AYM.MUNICIPALITY_ID
, AYM.YEAR;
我不太确定这是最有效的方法,但它确实做到了。
我使用
GENERATE_SERIES
来获取所有日历年,而不是 rCTE。如果您使用的不是 SQL Server 2022+,请使用计数。对于少量数据,rCTE 对于生成行来说“很好”,但它会变得慢快,因此我避免在所有情况下使用它们来生成此类数据,并使用基于集合的方法。
然后我使用 rCTE 来遍历数据的层次结构。然后,我使用进一步的 CTE 将值放在两侧(因此您有 1000,1001 和 1001,1000)并获得
DISTINCT
结果。
最后,我根据“有效”市镇的值,将其
JOIN
添加到您的原始数据中。结果如下:
CREATE TABLE dbo.YourTable (municipality_id int,
valid_year_from int,
valid_year_to int,
predecessor_municipality_id int);
GO
INSERT INTO dbo.YourTable (municipality_id,
valid_year_from,
valid_year_to,
predecessor_municipality_id)
VALUES (1000, 1990, 1995, NULL),
(1001, 1996, 2000, 1000),
(1002, 2001, 2005, 1001),
(1003, 1990, 2005, NULL);
GO
WITH MinMaxYears AS(
SELECT MIN(valid_year_from) AS MinYear,
MAX(valid_year_to) AS MaxYear
FROM dbo.YourTable),
Years AS(
SELECT GS.value AS CalendarYear
FROM MinMaxYears MMY
CROSS APPLY GENERATE_SERIES(MMY.MinYear, MMY.MaxYear, 1) GS),
Municipalities AS(
SELECT YT.municipality_id,
YT.municipality_id AS Current_municipality_id,
YT.predecessor_municipality_id
FROM dbo.YourTable YT
UNION ALL
SELECT M.municipality_id,
YT.municipality_id AS Current_municipality_id,
YT.predecessor_municipality_id
FROM dbo.YourTable YT
JOIN Municipalities M ON YT.municipality_id = M.predecessor_municipality_id),
ValidMunicipalities AS(
SELECT DISTINCT V.municipality_id,
V.valid_municipality_id
FROM Municipalities M
CROSS APPLY (VALUES(M.municipality_id, M.Current_municipality_id),
(M.Current_municipality_id, M.municipality_id))V(municipality_id,valid_municipality_id))
SELECT Y.CalendarYear,
VM.municipality_id,
VM.valid_municipality_id
FROM ValidMunicipalities VM
CROSS JOIN Years Y
JOIN dbo.YourTable YT ON Y.CalendarYear BETWEEN YT.valid_year_from AND YT.valid_year_to
AND VM.valid_municipality_id = YT.municipality_id
ORDER BY VM.municipality_id,
VM.valid_municipality_id,
Y.CalendarYear;
GO
DROP TABLE dbo.YourTable;