2013-07-24 1 views
3

Мне нужно выполнить самообучение, которое может привести к нескольким строкам, но мне нужно ограничить объединение одной строкой на запись. Если несколько строк соответствуют критериям соединения, следует использовать только строку значений с максимальным значением PK. Вот упрощенная схема, гипотетическая:Как ограничить себя Присоединиться к началу 1 в SQL Server

CREATE TABLE #Records(
    Id int NOT NULL, 
    GroupId int NOT NULL, 
    Node varchar(10) NOT NULL, 
    Value varchar(10) NULL, 
    Meta1 varchar(10) NULL, 
    Meta2 varchar(10) NULL, 
    Meta3 varchar(10) NULL 
) 

Вот некоторые примеры вставка:

INSERT INTO #Records VALUES(1,123,'Parent', '888', 'meta1', 'meta2', 'meta3') 
INSERT INTO #Records VALUES(2,123,'Guardian', '789', 'meta1', 'meta2', 'meta3') 
INSERT INTO #Records VALUES(3,123,'Parent', '999', 'meta1', 'meta2', 'meta3') 
INSERT INTO #Records VALUES(4,123,'Guardian', '654', 'meta1', 'meta2', 'meta3') 
INSERT INTO #Records VALUES(5,123,'Sibling', '222', 'meta1', 'meta2', 'meta3') 
INSERT INTO #Records VALUES(6,456,'Parent', '777', 'meta1', 'meta2', 'meta3') 
INSERT INTO #Records VALUES(7,456,'Guardian', '333', 'meta1', 'meta2', 'meta3') 

В общих чертах, я хотел бы, чтобы количество строк вернувшейся равно количеству или записи в таблице. Мне нужна колонка родителя в столбце Guardian. Родитель должен соответствовать самой последней строке, основанной на Id, которая имеет узел «Родительский» для соответствующего GroupId. Мне нужно то же самое для Guardian, но Узел должен быть «Хранителем». Результаты будут выглядеть так:

Id GroupId Node  Value Meta1 Meta2 Meta3 Parent Guardian 
--- ---------- --------- --------- ------- ------- ------- ------- ---------- 
1  123  Parent  888  meta1 meta2 meta3 999  654  
2  123  Guardian 654  meta1 meta2 meta3 999  654 
3  123  Parent  999  meta1 meta2 meta3 999  654 
4  123  Guardian 789  meta1 meta2 meta3 999  654 
5  123  Sibling 222  meta1 meta2 meta3 999  654 
6  456  Parent  777  meta1 meta2 meta3 777  333 
7  456  Guardian 333  meta1 meta2 meta3 777  333 

Примечание. У меня есть эта частично работающая сейчас, но она не ограничивает последнее значение. Он отлично работает, когда все родительские и операндовые узлы имеют одинаковое значение. Я пытался ограничить MAX, но потерпел неудачу. Глядя на этот запрос, вы можете отклонить свое мнение, поэтому, пожалуйста, не стесняйтесь полностью его отбрасывать.

SELECT #Records.*, Parent,Guardian 
FROM #Records 
LEFT JOIN (
    SELECT MAX(Id) As ParentRow, GroupId, Value AS Parent 
    FROM #Records 
    WHERE Node = 'Parent' 
    GROUP BY GroupId, Value 
) AS Parents 
ON #Records.GroupId = Parents.GroupId 
LEFT JOIN (
    SELECT MAX(Id) As ParentRow, GroupId, Value AS Guardian 
    FROM #Records 
    WHERE Node = 'Guardian' 
    GROUP BY GroupId, Value 
) AS Guardians 
ON #Records.GroupId = Guardians.GroupId 

Заранее благодарен!

ответ

2

Вы были близки, но вы возвращали слишком много результатов из ваших подзапросов, потому что вы группировали по нескольким полям, так как вы хотите, чтобы значение для Max (id) для каждого идентификатора группы, вы можете использовать функцию ROW_NUMBER() для достижения этой цели:

SELECT DISTINCT #Records.*, Parent,Guardian 
FROM #Records 
LEFT JOIN (SELECT GroupID,Value'Parent',ROW_NUMBER() OVER(PARTITION BY GroupID ORDER BY ID DESC)'RowRank' 
      FROM #Records 
      WHERE Node = 'Parent' 
      ) AS Parents 
    ON #Records.GroupId = Parents.GroupId 
     AND Parents.RowRank = 1 
LEFT JOIN (SELECT GroupID,Value'Guardian',ROW_NUMBER() OVER(PARTITION BY GroupID ORDER BY ID DESC)'RowRank' 
      FROM #Records 
      WHERE Node = 'Guardian' 
     ) AS Guardians 
    ON #Records.GroupId = Guardians.GroupId 
     AND Guardians.RowRank = 1 
+0

Я не хочу MAX (Value), я хочу значение в MAX (Id). Я вижу, что моя вставка и результаты находятся в порядке возрастания по значению, поэтому, вероятно, это не помогло. Я буду редактировать. – kakridge

+0

А, я вижу, будет обновляться. –

+0

Обновлено соответственно. –

1

Следующее получает последний предыдущий родитель/опекун в группе для каждой строки в исходной таблице. Он использует коррелированные подзапросы в предложении select сделать работу:

select r.*, 
     (select top 1 Value 
     from #Records r2 
     where r2.GroupId = r.GroupId and Node = 'Parent' 
     order by id desc 
     ) parent, 
     (select top 1 Value 
     from #Records r2 
     where r2.GroupId = r.GroupId and Node = 'Guardian' 
     order by id desc 
     ) guardian 
from #Records r; 

Использование вложенных выбирает гарантирует, что все строки в исходной таблице включены ровно один раз.

В некоторых базах данных вы можете сделать это с помощью оконных/аналитических функций. Например, синтаксис Oracle:

select r.*, 
     Last(case when Node = 'Parent' then Value end) over (partition by GroupId order by id) as Parent, 
     Last(case when Node = 'Parent' then Value end) over (partition by GroupId order by id) as Guardian 
from #Records;