2015-08-19 3 views
0

Есть 2 таблицы: users и offers.T-SQL - Подзапрос возвращает более 1 значения

Мне нужно извлечь 3 предложения для каждого пользователя.

Я написал эту командную строку:

SELECT TOP 10 
    sellerID, 
    Country, 
    (SELECT TOP 3 ItemID 
    FROM Items i 
    JOIN Sellers s ON s.sellerID = i.UserID 
    ORDER BY CreatedDate) 
FROM 
    Sellers 
ORDER BY 
    Country desc 

Не уверен, что, если на самом деле возвращает то, что я ищу, но я получаю эту ошибку:

Subquery returned more than 1 value.
This is not permitted when the subquery follows =, !=, <, <= , > >, >= or when the subquery is used as an expression.`

Можно предложить решение или обходной путь?

+0

'Не уверен, что действительно возвращает то, что я ищу' - нет, это не так. См. Http://dba.stackexchange.com/q/86415/5203 – GSerg

ответ

1

CROSS APPLY является то, что вы необходимость. Пожалуйста, смотрите пример запроса:

SELECT TOP (10) S.SellerID, S.Country, I.ItemID 
FROM dbo.Sellers AS S 
CROSS APPLY (
    SELECT TOP (3) I.ItemID 
    FROM dbo.Items AS I 
    WHERE S.SellerID = I.UserID 
    ORDER BY I.CreatedDate 
    ) AS I 
ORDER BY S.Country DESC; 

Этот запрос вернет вас TOP (10) результаты. Если вы хотите получить TOP (10) пользователей и 3 пунктов для каждого пользователя (Это означает, что до 30 записей), используйте этот запрос вместо:

SELECT S.SellerID, S.Country, I.ItemID 
FROM (
    SELECT TOP (10) S.SellerID, S.Country 
    FROM dbo.Sellers AS S 
    ORDER BY S.Country DESC 
    ) AS S 
CROSS APPLY (
SELECT TOP (3) I.ItemID 
FROM dbo.Items AS I 
WHERE S.SellerID = I.UserID 
ORDER BY I.CreatedDate 
) AS I; 

Один из его использует именно то, что вы просите. Возврат TOP (n) подпунктов. Более реальные примеры жизни можно найти здесь: Real life example, when to use OUTER/CROSS APPLY in SQL

0

У вас есть подзапрос в предложении select. Он должен вернуть 1 строку. Попробуйте присоединиться к нему instead-

SELECT 
TOP 10 sellerID, 
Country, items.ItemID 
from Sellers 
left join 
(
    SELECT TOP 3 UserID, ItemID 
    from Items i 
    join Sellers s 
    on s.sellerID=i.UserID 
    order by CreatedDate 
) items 
on sellers.UserID = items.UserID 
order by Country desc 
+0

Нет, это возвращает items.ItemID только для первых 3 UserID, я могу представить, что это связано с внутренним предложением '' SELECT TOP 3 UserID ... . « – Joe

0

Непосредственная проблема в том, что вы задали select на выходные строки каждой из которых содержит значение для sellerId, Country и три значения для ItemID.

Подзапрос также не коррелирует с внешним запросом, то есть у вас есть вторая ссылка на таблицу Sellers, но ничего не сделали, чтобы сопоставить значения с внешним запросом.

Предполагая, что вы на самом деле хотите, верхние 3 пунктов для каждого до 10 стран, то это должно быть близко:

работа
-- Sample data. 
declare @Sellers as Table (SellerId Int, Country VarChar(16)); 
insert into @Sellers (SellerId, Country) values 
    (1, 'Canada'), (2, 'Italy'), (3, 'Elbonia'), (4, 'Maldives'), (5, 'Fiji'), 
    (6, 'Ecuador'), (7, 'Chile'), (8, 'Mexico'), (9, 'Palau'), (10, 'Yap'), 
    (11, 'Saba'); 
declare @Items as Table (ItemId Int, UserId Int, CreatedDate Date); 
insert into @Items (ItemId, UserId, CreatedDate) values 
    (1, 3, '20150308'), (2, 3, '20150619'), (3, 3, '20120908'), (4, 3, '20140228'), 
    (2, 9, '20150308'), (3, 9, '20150619'), (4, 9, '20120908'), (5, 9, '20140228'), 
    (3, 6, '20150308'), (4, 6, '20150619'), (4, 6, '20120908'), (6, 6, '20140228'); 

select * from @Sellers; 
select * from @Items; 

-- Show the intermediate results. 
with AllSellersAndItems as 
    (select S.SellerId, S.Country, I.ItemId, 
    Row_Number() over (partition by S.SellerId order by I.CreatedDate) as ItemSequence, 
    Dense_Rank() over (order by Country) as SellerSequence 
    from @Sellers as S inner join 
     @Items as I on I.UserId = S.SellerId) 
    select * from AllSellersAndItems; 

-- The real query. 
with AllSellersAndItems as 
    (select S.SellerId, S.Country, I.ItemId, 
    Row_Number() over (partition by S.SellerId order by I.CreatedDate) as ItemSequence, 
    Dense_Rank() over (order by Country) as SellerSequence 
    from @Sellers as S inner join 
     @Items as I on I.UserId = S.SellerId) 
    select SellerId, Country, ItemId, SellerSequence, ItemSequence 
    from AllSellersAndItems 
    where SellerSequence <= 10 and ItemSequence <= 3 
    order by Country desc 
0

этот запрос для Вас:

SELECT TOP 10 sellerID, Country, items.ItemID 
    from Sellers 
    left join Items On Items.UserID = Sellers.sellerID 
        And Items.ItemID in (Select Top 3 I_1.ItemID From Items As I_1 
             Where I_1.UserID = Sellers.sellerID 
             Order by CreatedDate) 
    ORDER BY Country desc 
+0

Спасибо, это работает, но около 100 000 продавцов и 1 миллион предметов занимают в среднем 12 секунд, тогда как решение с« CROSS APPLY »занимает 6 секунд – Joe

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