Как сгруппировать родительские/дочерние записи по флагу и свернуть в одну запись для комбинации, в которой флаг является истинным, если один или несколько развернутых были истинными?

#sql-server #tsql #sql-server-2019

Вопрос:

Извините за длинное название, мне было трудно описать то, что я пытаюсь сделать. Это просто понять, как вы увидите ниже, но трудно обобщить в название.

У меня есть запрос, который возвращает следующие данные:

 | ParentID | ChildID | Flag |
| 100      | 1       | 0    |
| 100      | 1       | 1    |
| 100      | 2       | 0    |
| 100      | 2       | 0    |
| 200      | 1       | 1    |
| 200      | 1       | 1    |
 

В столбце флаг будет только 1 или 0.
Мне нужно отфильтровать результаты так, чтобы для каждой комбинации родитель/потомок была только одна строка.
Флаг должен быть равен 1, если в полном наборе результатов выше была одна или несколько записей, где для комбинации родитель/потомок было 1, в противном случае он должен быть равен нулю.

Таким образом, результат, если применить его к вышесказанному, будет:

 | ParentID | ChildID | Flag |
| 100      | 1       | 1    |
| 100      | 2       | 0    |
| 200      | 1       | 1    |
 

У меня это работает только с колонками childID и Flag:

 DECLARE @InMemoryResultsFirstPass AS TABLE (ChildID Integer, Flag Integer)
DECLARE @InMemoryResultsRecs AS TABLE (ChildID Integer, Flag Integer)

INSERT INTO @InMemoryResultsFirstPass
      SELECT 1 ChildID, 0 Flag
UNION SELECT 1 ChildID, 1 Flag
UNION SELECT 2 ChildID, 0 Flag
UNION SELECT 2 ChildID, 0 Flag
UNION SELECT 1 ChildID, 1 Flag
UNION SELECT 1 ChildID, 1 Flag

select * from @InMemoryResultsFirstPass

INSERT INTO @InMemoryResultsRecs
SELECT DISTINCT 
    result.* 
FROM @InMemoryResultsFirstPass imr
    CROSS APPLY (
        SELECT TOP 1
            *
        FROM @InMemoryResultsFirstPass imrfp
        WHERE imrfp.ChildID = imr.ChildID
        ORDER BY imrfp.Flag DESC
    ) result

select * from @InMemoryResultsRecs
 

Но я не смог понять, как это сделать, как только я добавлю это в столбец ParentID. Я попробовал несколько разных подходов, пытаясь выполнить вложенный запрос в ПЕРЕКРЕСТНОМ ПРИМЕНЕНИИ с ГРУППОЙ по родительскому идентификатору, но независимо от того, что я пытаюсь, я теряю родительский идентификатор = 200 записей:

 DECLARE @InMemoryResultsFirstPass AS TABLE (ParentID Integer, ChildID Integer, Flag Integer)
DECLARE @InMemoryResultsRecs AS TABLE (ParentID Integer, ChildID Integer, Flag Integer)

INSERT INTO @InMemoryResultsFirstPass
      SELECT 100 ParentID, 1 ChildID, 0 Flag
UNION SELECT 100 ParentID, 1 ChildID, 1 Flag
UNION SELECT 100 ParentID, 2 ChildID, 0 Flag
UNION SELECT 100 ParentID, 2 ChildID, 0 Flag
UNION SELECT 200 ParentID, 1 ChildID, 1 Flag
UNION SELECT 200 ParentID, 1 ChildID, 1 Flag

select * from @InMemoryResultsFirstPass

INSERT INTO @InMemoryResultsRecs
SELECT DISTINCT 
    result.* 
FROM @InMemoryResultsFirstPass imr
    CROSS APPLY (
        SELECT TOP 1
            *
        FROM @InMemoryResultsFirstPass imrfp
        WHERE imrfp.ChildID = imr.ChildID
        ORDER BY imrfp.Flag DESC
    ) result

select * from @InMemoryResultsRecs
 

Любая помощь будет весьма признательна.

Спасибо, что уделили мне время.

Комментарии:

1. это просто SELECT ParentID, ChildID, MAX(Flag) FROM table GROUP BY ParentID, ChildID так ?

2. @Белка спасибо за ответ. В колледже мне показали ту же технику, прежде чем я увидел это. 😉

Ответ №1:

На самом деле, я только что разобрался в этом:

 SELECT ParentID, ChildID, MAX(Flag) AS Flag
FROM @InMemoryResultsFirstPass
GROUP BY ParentID, ChildID
ORDER BY ParentID, ChildID
 

Надеюсь, это поможет кому-то еще: -)

Комментарии:

1. Хорошая работа! Есть куча разных способов сделать это, этот может быть самым простым.