2010-09-21 2 views
4

У меня есть запрос, который выводит результаты следующим образом:Создать агрегатную функцию для GROUP BY?

Person Food 
====== ====== 
Abner Apple 
Beth  Banana 
Beth  Peach 
Carlos Grape 
Carlos Kiwi 
Carlos Strawberry 
. .  . . 

А именно, он связывает человека с одним или более продуктов. Я хотел бы, чтобы функциональность агрегатной функции выбирала пищу, но ни одна из встроенных агрегатов (SUM, MAX, MIN и т. Д.) Не применима к ситуации.

Если у меня есть функция F(), что, учитывая список продуктов, либо:

  1. обеспечивает упорядоченный список продуктов , основанный на некоторой оптимизации
  2. обеспечивает оптимальный уникальный выбор от список

можно ли каким-либо образом применить к нему GROUP BY?

Есть ли у кого-нибудь пример запроса, который делает это по-другому, на случай, если это сон?

= = = =

EDIT: Допустим, что из вариантов, показанных выше, оптимальный список {киви, виноград, банан, клубника, яблоко, персик}, то выход должен сказать:

Abner Apple 
Beth Banana 
Carlos Kiwi 

т. Е. Одна запись на человека и еда для каждого являются первым вхождением в оптимальный список Пищи, связанной с этим Лицом в исходной таблице.

+1

Я знаю, что вы показали нам свой текущий выход, но можете ли вы показать, какой вы хотите получить? –

+1

Вы хотите выбрать одну еду из группы продуктов для данного человека? Какие критерии вы бы выбрали для этого выбора? –

+0

Если элемент в списке Оптимальный не отображается, что должно появиться в новом запросе? –

ответ

2
SELECT DISTINCT t.Person, f.Food FROM MyTable AS t 
CROSS APPLY(
SELECT TOP 1 Food FROM MyTable AS t1 WHERE t.Person = t1.Person 
ORDER BY <your method of rating and choosing goes here> 
) AS f 
+1

Я думаю, что OP также захочет вернуть Пищу, связанную с каждым человеком? –

+0

@ Джо Стефанелли: ты прав, я отредактировал мой ответ, спасибо! –

+0

Использование CROSS APPLY, скорее всего, является частью хорошего решения, но, на мой взгляд, этот ответ довольно груб, чтобы быть очень полезен для вопрошающего. Он серьезно собирается придерживаться своей функции F() в предложении ORDER BY? – ErikE

1

Вы имеете в виду, что хотите объединить эти продукты?

Попробуйте это:

select p.Person, stuff((select ', ' + f.Food [text()] from Food f where f.PersonId = p.Id order by f.Food for xml path('')),1,2,'') [Foods] 
from Person p 
+0

Возможно, вы захотите добавить ключевое слово 'distinct' в подзапросе, чтобы возвращать отдельные« продукты ». –

0

Вы могли бы обойтись без группы по с этим:

SELECT DISTINCT Person, F(Person) AS FoodFunction FROM TableName 

Вы должны были бы изменить функцию F(), так что она занимает человек (не список продуктов питания) и получить список продуктов питания через:

SELECT Food FROM TableName 
WHERE Person = @Person 
1

Обратите внимание, что в моих запросах здесь вы можете заменить таблицу OptimalFood своей функцией возврата к набору строк F() (если я правильно понимаю).

WITH PersonFood (Name, Food) AS (
    SELECT 'Abner', 'Apple' 
    UNION ALL SELECT 'Beth', 'Banana' 
    UNION ALL SELECT 'Beth', 'Peach' 
    UNION ALL SELECT 'Carlos', 'Grape' 
    UNION ALL SELECT 'Carlos', 'Kiwi' 
    UNION ALL SELECT 'Carlos', 'Strawberry' 
    UNION ALL SELECT 'Delilah', 'Passionfruit' 
), OptimalFood (Priority, Food) AS (
    SELECT 1, 'Kiwi' 
    UNION ALL SELECT 2, 'Grape' 
    UNION ALL SELECT 3, 'Banana' 
    UNION ALL SELECT 4, 'Strawberry' 
    UNION ALL SELECT 5, 'Apple' 
    UNION ALL SELECT 6, 'Peach' 
), Choices AS (
    SELECT 
     Selector = Row_Number() OVER (PARTITION BY F.Name ORDER BY Coalesce(O.Priority, 2147483647)), 
     F.Name, 
     Food = Coalesce(O.Food, '<None>') 
    FROM 
     PersonFood F 
     LEFT JOIN OptimalFood O ON F.Food = O.Food 
) 
SELECT 
    Name, 
    Food 
FROM Choices 
WHERE Selector = 1; 

Если у вас есть таблица со всеми людьми, перечисленных уже однажды, это может быть лучше:

WITH PersonFood (Name, Food) AS (
    SELECT 'Abner', 'Apple' 
    UNION ALL SELECT 'Beth', 'Banana' 
    UNION ALL SELECT 'Beth', 'Peach' 
    UNION ALL SELECT 'Carlos', 'Grape' 
    UNION ALL SELECT 'Carlos', 'Kiwi' 
    UNION ALL SELECT 'Carlos', 'Strawberry' 
    UNION ALL SELECT 'Delilah', 'Passionfruit' 
), OptimalFood (Priority, Food) AS (
    SELECT 1, 'Kiwi' 
    UNION ALL SELECT 2, 'Grape' 
    UNION ALL SELECT 3, 'Banana' 
    UNION ALL SELECT 4, 'Strawberry' 
    UNION ALL SELECT 5, 'Apple' 
    UNION ALL SELECT 6, 'Peach' 
), Person AS (
    SELECT DISTINCT Name FROM PersonFood 
) 
SELECT 
    P.Name, 
    Food = Coalesce(X.Food, '<None>') 
FROM 
    Person P 
    OUTER APPLY (
     SELECT TOP 1 O.Food 
     FROM 
     PersonFood F 
     INNER JOIN OptimalFood O ON F.Food = O.Food 
     WHERE P.Name = F.Name 
     ORDER BY O.Priority 
    ) X; 

Я хотел бы ожидать, что во всех этих случаях вы на самом деле с помощью цифровых клавиш, а чем варчарные струны. Я хотел желающий. :)

+0

Количество мысли, поставленное на ответ на этот вопрос, заслуживает +1. –

+0

Спасибо, Денис. Это действительно не так долго. Если Microsoft предоставит нам агенты First() и Last(), такие как Access, эти запросы будут быстрыми! См. [FIRST_VALUE, LAST_VALUE запрос на улучшение в Microsot Connect]. (Https://connect.microsoft.com/SQLServer/feedback/details/254395/over-clause-enhancement-request-first-value-last-value-functions) – ErikE

Смежные вопросы