Получение максимального значения или объединение данных для повторяющихся значений

Это связано с моим предыдущим Qn

Table A: 
ID  Rank Name 
1   100  Name1 
1    45  Name2 
2    60  Name3 
2    42  Name4 
2    88 Name5 
3    50 name6
3    50 name7

Table B: 
ID FileName 
1  fn1 
2  fn2 
3  fn3

Я хочу

1 fn1 name1 
2 fn2 name5 
3 fn3  name6,name7

Вот мой код, который не имеет дело с повторяющимися рангами выше, поэтому я получаю две строки для значения 3.

select B.*,A.Name
LEFT JOIN ( SELECT A.Id, MAX(A.Rank)as Rank 
    FROM A 
    GROUP BY A.Id
    ) AS NewA 
            JOIN A 
                on A.Rank = NewA.Rank
                    AND A.ID = NewA.Id
    on NewA.ID = B.ID 

Как мне изменить это, чтобы дать мне A.name, разделенное запятой, когда ранги одинаковы для идентификатора?

Спасибо


person user393148    schedule 28.02.2012    source источник
comment
Объединение групп серверов Sql — это частый вопрос SO: stackoverflow. com/questions/941103/concat-groups-in-sql-server   -  person J Cooper    schedule 28.02.2012
comment
@JCooper: у меня нет проблем с объединением строк для значений. Я понял, как это сделать. Мое слабое место - когда мне нужно объединить данные с другой таблицей.   -  person user393148    schedule 28.02.2012
comment
Подождите, разве это не должно быть: 1|fn1|имя1,имя2 --- 2|fn2|имя3,имя4,имя5 --- 3|fn3|имя6,имя7 ? Я просто хочу убедиться, что создаю подходящее решение   -  person Justin Pihony    schedule 28.02.2012
comment
Нет. Комбинировать Только тогда, когда у меня максимальный конфликт. в противном случае я выбираю псевдоним для максимального ранга. Как и для идентификаторов 1 и 2. У идентификатора 3 есть дубликат ранга, затем объедините два имени.   -  person user393148    schedule 28.02.2012


Ответы (3)


Вам нужно будет использовать CTE, чтобы сгладить это.

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

create table #tableA (ID int, [rank] int, name varchar(max))
insert into #tableA values(1,100,'Name1')
insert into #tableA values(1,45,'Name2')
insert into #tableA values(2,60,'Name3')
insert into #tableA values(2,42,'Name4')
insert into #tableA values(2,88,'Name5')
insert into #tableA values(3,50,'Name6')
insert into #tableA values(3,50,'Name7')

create table #tableB (ID int, [FileName] varchar(max))
insert into #tableB values(1,'fn1')
insert into #tableB values(2,'fn2')
insert into #tableB values(3,'fn3')

SELECT B.*,A.Name, ROW_NUMBER() OVER (PARTITION BY A.ID ORDER BY A.[rank]) AS RowNum
INTO #RankedTable
FROM #tableB as B
    LEFT JOIN ( 
        SELECT A.Id, MAX(A.Rank)as Rank 
        FROM #tableA AS A 
        GROUP BY A.Id
        ) AS NewA 
    JOIN #tableA AS A
        on A.Rank = NewA.Rank
            AND A.ID = NewA.Id
    on NewA.ID = B.ID 

;WITH ConcatenationCTE (ID, [FileName], Name, RowNum)
AS
(
  SELECT ID, [FileName], Name, RowNum 
  FROM #RankedTable
  WHERE RowNum = 1
  UNION ALL
  SELECT #RankedTable.ID, #RankedTable.[FileName],
          ConcatenationCTE.Name + ',' + #RankedTable.Name AS Name, 
          #RankedTable.RowNum 
  FROM #RankedTable
      JOIN ConcatenationCTE 
          ON ConcatenationCTE.ID = #RankedTable.ID 
              AND ConcatenationCTE.RowNum +1 = #RankedTable.RowNum
)
SELECT ConcatenationCTE.ID, [FileName], Name 
FROM ConcatenationCTE 
        JOIN 
     (SELECT ID, MAX(RowNum) AS RowNum 
      FROM ConcatenationCTE GROUP BY ID) AS FinalValues 
        ON FinalValues.ID = ConcatenationCTE.ID 
            AND FinalValues.RowNum = ConcatenationCTE.RowNum 
person Justin Pihony    schedule 28.02.2012
comment
Хорошо, я проверил свой только что обновленный запрос на фиктивном наборе данных, и он сработал. Дайте мне знать, если что-то из этого не работает или не имеет смысла. Как всегда, покажите свою признательность, проголосовав за и приняв ответ :) - person Justin Pihony; 28.02.2012
comment
Я буду. Безусловно. Позвольте мне попробовать. Спасибо. - person user393148; 28.02.2012
comment
На самом деле запрос, который я использую в вопросе выше, является частью одного большого запроса на выборку из нескольких таблиц. Я не уверен, смогу ли я вписать это. Но позвольте мне попробовать. - person user393148; 28.02.2012
comment
Вы можете просто сбросить свои данные во временную таблицу для изменения. - person Justin Pihony; 28.02.2012
comment
Есть ли способ объединить вышеуказанную логику с моим исходным кодом. Я попробовал часть этого в своем коде, но я почти уверен, что сделал это неправильно. потому что я не вижу строк для другого запроса. Другие подзапросы в моем большом запросе просто выбираются. Я не уверена. Было бы очень полезно, если бы я мог сохранить исходный код, который у меня есть. Спасибо. - person user393148; 28.02.2012
comment
Обновил, на самом деле это не заняло много времени. Если ваш реальный запрос настолько сложен, что вы не можете подключить его, вам может потребоваться предоставить что-то более близкое к фактическому запросу. Потому что, если вы возьмете мой обновленный код выше и подключите его непосредственно к SQL, он будет работать именно так, как вы просили. - person Justin Pihony; 28.02.2012
comment
Я попробовал это, заменив мою схему таблицы. Это было не сложно. Но я получаю следующую ошибку. Типы не совпадают между привязкой и рекурсивной частью в столбце Имя рекурсивного запроса ConcatenationCTE. Как мне сделать этот тип приведения? - person user393148; 28.02.2012
comment
SELECT ID, [FileName], CAST(Name AS VARCHAR(MAX)), RowNum.... для якорной части CTE. (Первый запрос с ...WHERE RowNum = 1). - person Justin Pihony; 28.02.2012
comment
Спасибо, Джастин. Я попробовал это с некоторыми изменениями, и это сработало и с моими данными. Цените многое. - person user393148; 29.02.2012

select B.ID,
       B.[FileName],
       stuff((select ',' + A1.name
              from TableA as A1
              where B.ID = A1.ID and
                    A1.[Rank] = (select max(A2.[Rank])
                                 from TableA as A2                   
                                 where A1.ID = A2.ID)
              for xml path(''), type).value('.', 'varchar(max)'), 1, 1, '') as Names
from TableB as B

Попробуйте SE-Data

person Mikael Eriksson    schedule 28.02.2012
comment
+1 . Спасибо Микаэль. Я тоже попробовал это решение. Это сработало для меня. Я уже интегрировал приведенное ниже решение в свой проект, поэтому я буду использовать его. Жаль, что я не могу выбрать два ответа. :) - person user393148; 29.02.2012
comment
@user393148 user393148 Ваш выбор пал на таблицу #temp? Вероятно, это будет гораздо менее эффективно. Вы должны дать время для принятия решений, прежде чем реализовывать или принимать ответы, потому что первый ответ не всегда будет лучшим. Не пытаясь отнять что-либо от принятого ответа; иногда, пока требование выполняется, производительность или сложность гораздо менее важны. Но иногда они есть (или будут позже, и придется пересобирать). Другое дело, что раннее принятие ответа снижает вероятность того, что кто-то захочет предложить лучшее решение. - person Aaron Bertrand; 29.02.2012
comment
@AaronBertrand: На самом деле так получилось, что я увидел еще одну проблему с моим кодом, интегрированным с решением #temp. Поэтому я переключился на решение Mikaels. - person user393148; 29.02.2012

person    schedule
comment
PS, если вы думаете, что это должно быть проще кодировать, вы не одиноки! Пожалуйста, проголосуйте за добавление функции GROUP_CONCAT() в SQL Server и объясните, что эта функция сэкономит ваше время и избавит вас от использования неуклюжих и сложных обходных путей для выражения простой и общей потребности: connect.microsoft.com/SQLServer/feedback/details/247118/< /а> - person Aaron Bertrand; 28.02.2012