Reputation: 1073
I think I've seen answers for similar questions for MySQL, but I'm struggling to find an answer applicable to SQL Server 2005.
So I have a table like this:
| ID | RelationalID | Year
----------------------------
| 1 | A | 2014
| 2 | A | 2014
| 3 | B | 2014
| 4 | A | 2015
| 5 | B | 2015
And I'd like a result like this when I join the same table where RelationID matches but the year is different:
| 2014_ID | 2015_ID | RelationalID |
------------------------------------
| 1 | 4 | A |
| 2 | NULL | A |
| 3 | 5 | B |
But a standard JOIN ends up getting duplicate matches:
| 2014_ID | 2015_ID | RelationalID |
------------------------------------
| 1 | 4 | A |
| 2 | 4 | A |
| 3 | 5 | B |
Is there a way to join two tables where the matches from the right table are joined only once in SQL Server 2005?
I tried this query with no success:
SELECT * FROM myTable
LEFT JOIN (SELECT * FROM myTable) AS t ON t.RelationalID = myTable.RelationalID
WHERE myTable.Year = 2014 and t.Year = 2015
Upvotes: 0
Views: 2065
Reputation: 1932
DECLARE @MyTable TABLE
(
ID INT,
RelationalID VARCHAR(10),
[Year] INT
)
INSERT INTO @MyTable
VALUES
( 1 ,'A', 2014),
( 2 ,'A', 2014),
( 3 ,'B', 2014),
( 4 ,'A', 2015),
( 5 ,'B', 2015)
;WITH TEST AS
(
SELECT
a.Id AS Id2014,
NULL AS Id2015,
a.RelationalId,
RANK() OVER (PARTITION BY RelationalId ORDER BY ID) Ranked
FROM @MyTable a
WHERE a.Year = 2014
UNION
SELECT
NULL AS Id2014,
b.Id AS Id2015,
b.RelationalId,
RANK() OVER (PARTITION BY RelationalId ORDER BY ID) Ranked
FROM @MyTable b
WHERE b.Year = 2015
)
SELECT
t1.Id2014,
t2.Id2015,
t1.RelationalID
FROM TEST t1
LEFT JOIN TEST t2
ON t1.Ranked = t2.Ranked
AND t1.RelationalID = t2.RelationalID
AND t2.Id2015 IS NOT NULL
WHERE t1.Id2014 IS NOT NULL
ORDER BY t1.Id2014
I used a union and then ranked each side by relational id and left joined them. Here is the output:
Id2014 Id2015 RelationalID
1 4 A
2 NULL A
3 5 B
Upvotes: 1
Reputation: 60482
You can get the result based on ROW_NUMBERs, but you need a rule how to assign them, I assumed it's based on the Id.
;WITH cte AS
(SELECT Id,
RelationalId,
year,
row_number()
over (partition by RelationalId, year
order by Id) as rn
FROM [YourTable]
)
select t1.id as Id_2014,t2.id as Id_2015, t1.RelationalId
from cte as t1 left join cte as t2
on t1.RelationalId = t2.RelationalId
and t1.rn = t2.rn
and t2.year = 2015
where t1.Year = 2014
This is based on TMNT2014's fiddle
Upvotes: 2
Reputation: 2130
Below Sql would give you the result you are looking for but as I said before complexity would depend on the original set of data you have in your table. Here is the SQL Fiddle - http://sqlfiddle.com/#!3/d6300/24 - Good Luck!
;WITH CTE_Union AS
(SELECT
a.Id AS Id2014,
NULL AS Id2015,
a.RelationalId
FROM [YourTable] a
WHERE a.Year = 2014
UNION
SELECT
NULL AS Id2014,
b.Id AS Id2015,
b.RelationalId
FROM [YourTable] b
WHERE b.Year = 2015)
SELECT Distinct CASE WHEN Id2014 IS NULL THEN (SELECT MIN(Id2014) FROM CTE_Union C WHERE C.RelationalId =M.RelationalId) ELSE Id2014 END AS ID2014 ,
CASE WHEN Id2015 IS NULL AND Id2014 = (SELECT MIN(Id2014) FROM CTE_Union C2 WHERE C2.RelationalId =M.RelationalId) THEN (SELECT MIN(Id2015) FROM CTE_Union C WHERE C.RelationalId =M.RelationalId) ELSE Id2015 END
,RelationalID
FROM CTE_Union M
Upvotes: 1
Reputation: 86892
There are probably a few ways to solve this but below shows an example of utilizing "Derived Tables" in a query.
SELECT
q1.Id AS [2014_Id],
q2.Id AS [2015_Id],
q1.RelationalId
FROM (SELECT
MAX(a.Id) AS Id,
a.RelationalId
FROM [table] a
WHERE a.Year = 2014
GROUP BY
a.RelationalId) q1
INNER JOIN (SELECT
MAX(b.Id) AS Id,
b.RelationalId
FROM [table] b
WHERE b.Year = 2015
GROUP BY
b.RelationalId) q2
ON q2.RelationalId = q1.RelationalId
Upvotes: 0