假设我在SQL Server数据库中有一些数据。
Location PayID Year
------------------------
Loc1 100 2010
Loc1 100 2011
Loc1 101 2012
Loc2 200 2010
Loc2 201 2011
Loc2 202 2012
我正在尝试在SQL Server中编写一个查询,该查询将为我提供一个包含两列的表,我可以搜索这些列以查找特定位置的先前PayID
。所以输出就是。
PayID PrevID
-----------------
101 100
202 201
201 200
当前一年的ID与当前年份不同时,它只需要一个条目,如果用户返回超过一年时我没有正确的匹配,我将递归查询它所以它将拉取每个以前的ID基于刚刚拉出的那个,直到找到与第一个表匹配的PayID和年份。
对此的任何帮助将不胜感激。如果我能找到它,我会专心搜索并发布解决方案。
答案 0 :(得分:3)
这可以通过递归CTE轻松完成:
with cte as (
select Location, PayID, PayID as PrevID, Year from payhistory
union all
select p.Location, p.PayID, cte.PayID as PrevID, p.Year
from payhistory p
join cte on cte.Location = p.Location and cte.Year + 1 = p.Year
)
select distinct Location, PayID, PrevID
from cte
where PayID <> PrevID;
以下是我得到的结果:
| LOCATION | PAYID | PREVID |
|----------|-------|--------|
| Loc1 | 101 | 100 |
| Loc2 | 201 | 200 |
| Loc2 | 202 | 201 |
答案 1 :(得分:1)
我没有看到指定的版本,所以我在2012年使用LAG。如果您想要更少的信息,可以过滤结果。您可以用LAG(PayID,1,PayID)替换LAG(PayID,1,NULL)来改变第一个payid的行为。
DECLARE @tbl TABLE (Location VARCHAR(4), PayID INT, Year INT)
INSERT INTO @tbl VALUES
('Loc1',100,2010)
,('Loc1',100,2011)
,('Loc1',101,2012)
,('Loc2',200,2010)
,('Loc2',201,2011)
,('Loc2',202,2012)
SELECT Location
,PayID
,LAG(PayID,1,NULL) OVER (PARTITION BY Location ORDER BY Year ASC) PrevID
FROM @tbl
答案 2 :(得分:0)
关键假设 - 此查询仅在每个位置的PayIds是连续数字时才有效。
select distinct l1.payId as PayId,
l2.payId as PrevId
from locs as l1
inner join locs as l2
on l1.location = l2.location
and l1.payid = (l2.payid + 1)
答案 3 :(得分:0)
以下解决方案是非递归的,它可能会提供更好的性能:
DECLARE @Payment TABLE (
ID INT IDENTITY(1,1) PRIMARY KEY,
Location VARCHAR(50) NOT NULL,
PayID INT NOT NULL,
[Year] SMALLINT NOT NULL
);
INSERT @Payment
SELECT 'Loc1', 100, 2010
UNION ALL SELECT 'Loc1', 100, 2011
UNION ALL SELECT 'Loc1', 101, 2012
UNION ALL SELECT 'Loc2', 200, 2010
UNION ALL SELECT 'Loc2', 201, 2011
UNION ALL SELECT 'Loc2', 202, 2012
SELECT z.Location, z.GroupID,
MAX(CASE WHEN z.RowType = 1 THEN z.[Year] END) AS CurrentYear,
MAX(CASE WHEN z.RowType = 0 THEN z.[Year] END) AS PreviousYear,
MAX(CASE WHEN z.RowType = 1 THEN z.[PayID] END) AS CurrentPayID,
MAX(CASE WHEN z.RowType = 0 THEN z.[PayID] END) AS PreviousPayID
FROM
(
SELECT y.PayID, y.[Location], y.[Year],
-- It "groups" rows two by two: current row and previous row will have the same GroupID
(ROW_NUMBER() OVER(PARTITION BY y.Location ORDER BY y.RowNum + n.Num ASC) + 1) / 2 AS GroupID,
-- RowType: 1=Current row, 0=Previous row
ROW_NUMBER() OVER(PARTITION BY y.Location ORDER BY y.RowNum + n.Num ASC) % 2 AS RowType
FROM
(
SELECT x.Location, x.[Year], x.PayID, ROW_NUMBER() OVER(PARTITION BY x.Location ORDER BY x.[Year] DESC) RowNum
FROM @Payment x
) y
-- For every location, it duplicates every row except the last one
INNER JOIN (VALUES (1), (2)) n(Num) ON y.RowNum = 1 AND n.Num = 1 OR y.RowNum > 1
) z
GROUP BY z.Location, z.GroupID
HAVING MAX(CASE WHEN z.RowType = 1 THEN z.[Year] END) = MAX(CASE WHEN z.RowType = 0 THEN z.[Year] END) + 1
AND MAX(CASE WHEN z.RowType = 1 THEN z.[PayID] END) <> MAX(CASE WHEN z.RowType = 0 THEN z.[PayID] END)
ORDER BY z.Location;
输出:
Location GroupID CurrentYear PreviousYear CurrentPayID PreviousPayID
--------- ------- ----------- ------------ ------------ -------------
Loc1 1 2012 2011 101 100
Loc2 1 2012 2011 202 201
Loc2 2 2011 2010 201 200