2011-11-28 2 views
0

Я изо всех сил пытаюсь это проработать весь день - это кажется довольно простым, но мне чего-то не хватает!Фильтрация результатов, возвращаемых SQL-запросом

У меня есть запрос, который возвращает некоторые данные, два из возвращаемых им столбцов - это «PackageWeight» и «PackageGroup». По сути, я хочу отфильтровать эти данные, чтобы показать только одну строку для каждой «PackageGroup» - это должна быть строка с наибольшим значением в столбце «PackageWeight».

Кажется простым, но я просто не могу заставить его работать на SQL Server, используя комбинацию TOP 1 и GROUP BY. Я должен что-то упустить!

SELECT VendorID, PackageID, PackageWeight, PackageGroup 
    FROM (SELECT VendorID, COUNT(*) AS qty 
      FROM VendorServices 
     GROUP BY VendorID 
     ) cs 
    JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
      FROM PackageServices 
      JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
      GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
     ) ps ON cs.qty >= ps.qty 
    WHERE (SELECT COUNT(*) 
      FROM VendorServices cs2 
      JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
     WHERE cs2.VendorID = cs.VendorID 
      AND ps2.PackageID = ps.PackageID 
     ) = ps.qty 

Этот запрос возвращает мне полный набор данных, который мне нужно отфильтровать. Однако мои попытки до сих пор не удалось :(

Любая помощь очень ценится

EDIT - Благодаря вкладчикам ниже, до сих пор у меня есть следующий запрос:

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup, 
    RANK() over (partition by PackageGroup order by PackageWeight desc) as [rank] 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
WHERE [rank] = 1 
ORDER BY VendorID 

До сих пор, так Я все еще взгляну на оператор APPLY, предложенный @gbn, поскольку это для меня новичок, и мне все еще нужно провести некоторое тестирование, чтобы убедиться, что этот запрос работает в 100% случаев. Однако исходные указания хороши!

Спасибо всем, кто внес свой вклад до сих пор.

EDIT 2 - К сожалению, после заполнения базы данных более подробными данными этот запрос не работал. Кажется, что пропустили некоторые записи.

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

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

Буду считать вас более свежим, поскольку я думаю, что я могу быть в ситуации «Не вижу дерева для деревьев»!

Спасибо всем.

+1

возможно дубликат [SQL Server - ВЫБРАТЬ TOP 5 строк для каждого FK] (http://stackoverflow.com/questions/1450603/sql-server-select-top-5-rows -for-each-fk) или http://stackoverflow.com/q/1164483/27535. И еще десятки: http://stackoverflow.com/questions/tagged/greatest-n-per-group – gbn

+1

какую версию SQL Server вы используете? – Lamak

+0

@Lamak - SQL Server 2008. – JimmE

ответ

1

Можете ли вы попробовать это? Это не пуленепробиваемый, если у вас несколько записей с одинаковым весом в одной группе. Есть и другие способы справиться с этим.

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
where result_cte.PackageWeight = (select top 1 highestweight.PackageWeight from result_cte highestweight 
           where highestweight.PackageGroup = result_cte.PackageGroup 
           order by highestweight.PackageWeight desc) 

Или вы можете сделать это:

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup, 
    ROW_NUMBER() over (partition by PackageGroup order by PackageWeight desc) as [row] 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
where [row] = 1 
+0

по сравнению с запросом на основе ROW_NUMBER или APPLY, это очень грязно, даже если оно работает – gbn

+0

Я не хочу решать проблему автора. Я просто хочу показать разные методы, чтобы получить желаемый результат. Запросы, которые я вам предоставил, должны быть проверены для правильного результата. –

+0

@ Eric.K.Yung - Большое спасибо. Я немного изменил это значение, чтобы использовать RANK(), а не ROW_NUMBER(), поскольку ROW_NUMBER(), похоже, не возвращал строки, где у клиентов не было пакета из каждой группы. Я вставлю обновленный запрос в качестве редактирования в OP. – JimmE

0

Вы готовы принять один произвольный поставщика и PackageID, если несколько пакетов имеют одинаковый максимальный вес в группе? Если все в порядке, просто поставить агрегат на них, а также PackageWeight:

SELECT max(VendorID), max(PackageID), max(PackageWeight), PackageGroup 
... 
GROUP BY PackageGroup 

В противном случае, вам нужно будет сделать, как E.Y. предлагает и делает вложенный запрос, чтобы сначала найти максимальный вес для каждой группы и обрабатывать дубликаты, если таковые имеются, самостоятельно.

+0

К счастью, характер приложения таков, что каждый пакет имеет уникальный вес в группе. Фактически это причина того, что взвешивание/группировка существует в первую очередь - обеспечить соблюдение бизнес-правил при назначении пакетов клиентам. – JimmE

0

Вы можете использовать функцию MAX:

SELECT * FROM #one 
lbs groups 
5 0 
4 0 
1 0 
9 1 
2 1  

SELECT groups,MAX(lbs) 
FROM #one 
GROUP BY groups 

groups (No column name) 
0 5 
1 9 
0

Благодаря сообщению Eric.K.Yung - я, наконец, решил это, используя свой запрос, но при добавлении VendorID (эффективно CustomerID) к «раздела» на части запроса. Это обеспечило возврат пакетов для всех клиентов.

Спасибо всем, кто внес свой вклад. Окончательный запрос:

with result_cte as 
(
SELECT VendorID, PackageID, PackageWeight, PackageGroup, 
    ROW_NUMBER() over (partition by PackageGroup, VendorID order by PackageWeight desc) as [row] 
FROM (SELECT VendorID, COUNT(*) AS qty 
    FROM VendorServices 
    GROUP BY VendorID 
    ) cs 
JOIN (SELECT PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup, COUNT(*) AS qty 
    FROM PackageServices 
    JOIN lookupPackages ON PackageServices.PackageID = lookupPackages.PackageID 
    GROUP BY PackageServices.PackageID, lookupPackages.PackageWeight, lookupPackages.PackageGroup 
    ) ps ON cs.qty >= ps.qty 
WHERE (SELECT COUNT(*) 
    FROM VendorServices cs2 
    JOIN PackageServices ps2 ON cs2.ServiceTypeID = ps2.ServiceID 
    WHERE cs2.VendorID = cs.VendorID 
    AND ps2.PackageID = ps.PackageID 
    ) = ps.qty 
) 

select * 
from result_cte 
where [row] = 1 
+0

В зависимости от того, насколько ваш окончательный запрос отличается от ответа, он основан на или, по сути, на других ответах здесь, вы можете подумать о добавлении его в свой ответ. Я имею в виду, кто-то может найти его полезным, как любое другое правильное решение, размещенное в этом потоке. –

+0

@AndriyM - Конечно, большое спасибо. В мой ответ добавлен последний запрос. – JimmE

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