2011-10-09 5 views
1

나는 지금 흥미로운 딜레마를 가지고있다.비슷한 ID에 대해 SQL 행을 병합 하시겠습니까?

GameList: 
+-------+----------+-----------+------------+--------------------------------+ 
| id | steam_id | origin_id | impulse_id |   game_title   | 
+-------+----------+-----------+------------+--------------------------------+ 
| 1 | 17450 | NULL | NULL |  Dragon Age: Origins  | 
| 2 | NULL | 138994900 | NULL | Dragon Age(TM): Origins  | 
| 3 | NULL | NULL | dragonage |  Dragon Age Origins  | 
| 4 | 47850 | 201841300 | fifamgr11 |  FIFA Manager 11   | 
| ... | ... | ... |  ... |    ...    | 
+-------+----------+-----------+------------+--------------------------------+ 

GameAlias: 
+----------+-----------+ 
| old_id | new_id | 
+----------+-----------+ 
| 2  |  1  | 
| 3  |  1  | 
| ... | ... | 
+----------+-----------+ 

상점이 더 문제가있을 수 없다, 또는 같은 게임을 여러 행이있을 수 있습니다 게임의 동일한 제목을 사용하는지 여부에 따라 : 나는 다음과 같은 데이터베이스 스키마가 있습니다. Alias ​​테이블은 id 2와 id 3이 id 1의 별칭 일 뿐이라는 문제를 해결하기 위해 존재합니다.

GameList 테이블과 GameAlias ​​테이블을 모두 사용하고 다음을 반환하는 SQL 쿼리가 필요합니다.

ConglomerateGameList: 
+-------+----------+-----------+------------+--------------------------------+ 
| id | steam_id | origin_id | impulse_id |   game_title   | 
+-------+----------+-----------+------------+--------------------------------+ 
| 1 | 17450 | 138994900 | dragonage |  Dragon Age: Origins  | 
| 4 | 47850 | 201841300 | fifamgr11 |  FIFA Manager 11   | 
| ... | ... | ... |  ... |    ...    | 
+-------+----------+-----------+------------+--------------------------------+ 

"새로운 ID"의 게임 제목이 필요합니다. "이전 ID"에 대한 게임 제목은 단순히 무시하거나 무시해야합니다.

이 문제를 해결하기 위해 GameList 테이블을 수정할 수는 없습니다. 데이터베이스에서 게임을 찾지 못해 상점에서 업데이트 된 게임 목록을 가져올 때마다 밤마다 원하는 출력으로 보이도록 테이블을 다시 작성하면 다음과 같은 행이 생성됩니다.

+-------+----------+-----------+------------+--------------------------------+ 
| id | steam_id | origin_id | impulse_id |   game_title   | 
+-------+----------+-----------+------------+--------------------------------+ 
| 1 | 17450 | 138994900 | dragonage |  Dragon Age: Origins  | 
| 4 | 47850 | 201841300 | fifamgr11 |  FIFA Manager 11   | 
| ... | ... | ... |  ... |    ...    | 
| 8139 | NULL | 138994900 | NULL |  Dragon Age(TM): Origins | 
| 8140 | NULL | NULL | dragonage |  Dragon Age Origins  | 
+-------+----------+-----------+------------+--------------------------------+ 

Steam이 게임의 주요 업데이트를 릴리스 할 때 Steam이 변경하는 것으로 알려져 있기 때문에 게임의 ID가 변경되지 않는다는 가정하에도 작업 할 수 없습니다. 이 같은 재귀 별칭을 인식 할 수

보너스 포인트 경우 다음

GameAlias: 
+----------+-----------+ 
| old_id | new_id | 
+----------+-----------+ 
| 2  |  1  | 
| 3  |  2  | 
| ... | ... | 
+----------+-----------+ 

ID (3) 재귀 적 별명이 다음 내가 할 수없는 경우 자체가 ID 1의 별칭입니다 ID 2의 별칭이기 때문에 응용 프로그램 논리를 개발하여 막을 수 있습니다.

답변

2

이 방법이 유용합니까? 테이블 이름을 정정하십시오. (순환)없이

select ga1.new_id, max(gl1.steam_id), max(gl1.origin_id), max(gl1.impulse_id), 
max(if(gl1.id = ga1.new_id,gl1.game_title,NULL)) as game_title 
from gl1, ga1 
where (gl1.id = ga1.new_id OR gl1.id = ga1.old_id) 
group by ga1.new_id 

union 

select gl2.id, gl2.steam_id, gl2.origin_id, gl2.impulse_id, gl2.game_title 
from gl2, ga2 
where (gl2.id not in (
    select ga3.new_id from ga3 
    union 
    select ga4.old_id from ga4)) 
+0

매력처럼 작동했습니다. 사실, 별칭 테이블에서 ID를 반환하기 위해'COALESCE()'를 사용하거나 별칭이없는 경우 원래 ID를 사용하여 쿼리를 조금 더 단순화하는 방법을 찾았습니다. 'group by'와'max (gl1.steam_id), max (...')는 분명 많이 도움이되었습니다. – stevendesu

0

1.First 용액 :

CREATE TABLE GameList 
(
    id   INT NOT NULL PRIMARY KEY 
    ,steam_id INT NULL 
    ,origin_id INT NULL 
    ,impulse_id NVARCHAR(50) NULL    
    ,game_title NVARCHAR(50) NOT NULL 
); 
INSERT GameList(id, steam_id, origin_id, impulse_id, game_title) 
SELECT 1, 17450, NULL,  NULL,  'Dragon Age: Origins' 
UNION ALL 
SELECT 2, NULL, 138994900, NULL,  'Dragon Age(TM): Origins' 
UNION ALL 
SELECT 3, NULL, NULL,  'dragonage','Dragon Age Origins' 
UNION ALL 
SELECT 4, 47850, 201841300, 'fifamgr11','FIFA Manager 11'; 

CREATE TABLE GameAlias 
(
    old_id INT NOT NULL PRIMARY KEY 
    ,new_id INT NOT NULL 
); 

INSERT GameAlias (old_id, new_id) VALUES (2,1); 
INSERT GameAlias (old_id, new_id) VALUES (3,1); 

-- Solution 1 
SELECT COALESCE(ga.new_id, gl.id) new_id 
     ,MAX(gl.steam_id) new_steam_id 
     ,MAX(gl.origin_id) new_origin_id 
     ,MAX(gl.impulse_id) new_impulse_id 
     ,MAX(CASE WHEN ga.old_id IS NULL THEN gl.game_title ELSE NULL END) new_game_title 
FROM GameList gl 
LEFT OUTER JOIN GameAlias ga ON gl.id = ga.old_id 
GROUP BY COALESCE(ga.new_id, gl.id); 
-- End of Solution 1  
DROP TABLE GameList; 
DROP TABLE GameAlias; 

결과

1 17450 138994900 dragonage Dragon Age: Origins 
4 47850 201841300 fifamgr11 FIFA Manager 11 

2.Second 용액 (재귀 레벨 = 세 단계)

CREATE TABLE GameList 
(
    id   INT NOT NULL PRIMARY KEY 
    ,steam_id INT NULL 
    ,origin_id INT NULL 
    ,impulse_id NVARCHAR(50) NULL    
    ,game_title NVARCHAR(50) NOT NULL 
); 
INSERT GameList(id, steam_id, origin_id, impulse_id, game_title) 
SELECT 1, 17450, NULL,  NULL,  'Dragon Age: Origins' 
UNION ALL 
SELECT 2, NULL, 138994900, NULL,  'Dragon Age(TM): Origins' 
UNION ALL 
SELECT 3, NULL, NULL,  'dragonage','Dragon Age Origins' 
UNION ALL 
SELECT 4, 47850, 201841300, 'fifamgr11','FIFA Manager 11' 
UNION ALL 
SELECT 5, 11111, NULL,  NULL,  'Starcraft 1' 
UNION ALL 
SELECT 6, NULL, 1111111111, NULL,  'Starcraft 1.1' 
UNION ALL 
SELECT 7, NULL, NULL,  NULL,  'Starcraft 1.2' 
UNION ALL 
SELECT 8, NULL, NULL,  'sc1',  'Starcraft 1.3'; 

CREATE TABLE GameAlias 
(
    old_id INT NOT NULL PRIMARY KEY 
    ,new_id INT NOT NULL 
); 

INSERT GameAlias (old_id, new_id) VALUES (2,1); 
INSERT GameAlias (old_id, new_id) VALUES (3,1); 
INSERT GameAlias (old_id, new_id) VALUES (6,5); 
INSERT GameAlias (old_id, new_id) VALUES (7,6); 
INSERT GameAlias (old_id, new_id) VALUES (8,7); 

-- Solution 2 
CREATE TEMPORARY TABLE Mappings 
(
    old_id INT NOT NULL PRIMARY KEY 
    ,new_id INT NOT NULL 
); 
INSERT Mappings (old_id, new_id) 
-- first level mapping 
SELECT ga.old_id, ga.new_id 
FROM GameAlias ga 
WHERE ga.new_id NOT IN (SELECT t.old_id FROM GameAlias t) 
-- second level mapping 
UNION ALL 
SELECT ga.old_id, ga2.new_id 
FROM GameAlias ga 
INNER JOIN GameAlias ga2 ON ga.new_id = ga2.old_id 
WHERE ga2.new_id NOT IN (SELECT t.old_id FROM GameAlias t) 
-- third level mapping 
UNION ALL 
SELECT ga.old_id, ga3.new_id 
FROM GameAlias ga 
INNER JOIN GameAlias ga2 ON ga.new_id = ga2.old_id 
INNER JOIN GameAlias ga3 ON ga2.new_id = ga3.old_id; 

SELECT COALESCE(ga.new_id, gl.id) new_id 
     ,MAX(gl.steam_id) new_steam_id 
     ,MAX(gl.origin_id) new_origin_id 
     ,MAX(gl.impulse_id) new_impulse_id 
     ,MAX(CASE WHEN ga.old_id IS NULL THEN gl.game_title ELSE NULL END) new_game_title 
FROM GameList gl 
LEFT OUTER JOIN Mappings ga ON gl.id = ga.old_id 
GROUP BY COALESCE(ga.new_id, gl.id); 

DROP TEMPORARY TABLE Mappings; 
-- End of Solution 2 

DROP TABLE GameList; 
DROP TABLE GameAlias; 

결과 :

1 17450 138994900 dragonage Dragon Age: Origins 
4 47850 201841300 fifamgr11 FIFA Manager 11 
5 11111 1111111111 sc1   Starcraft 1 

죄송 합니다만 MySQL에는 재귀 쿼리/CTE가 없습니다.

관련 문제