如何找到前任的前任

问题描述 投票:0回答:1

我正在尝试使用 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;
sql recursive-query sql-server-2022
1个回答
0
投票

我不太确定这是最有效的方法,但它确实做到了。

我使用

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;
© www.soinside.com 2019 - 2024. All rights reserved.