2016-08-31 2 views
0

Мое приложение - это кассовый аппарат. Следующий запрос принимает TransactionID и возвращает одну или несколько строк товаров, продаваемых в этой одной транзакции, т.е. для TransactionID = 28715:Возврат SQL Sub Query с переменной внутри Выберите

DECLARE @SalesItems varchar(250); 
DECLARE @TransactionID int; 
SET @TransactionID = 28715; 


Select @SalesItems = coalesce(@SalesItems + ', ', '') + CAST(TransactionsPosLines.Description as varchar(250)) 
From 
    TransactionsPosLines 
    where TransactionsPosLines.TransactionId = @TransactionID 

select @SalesItems 

и возвращает:

"Widget A, Widget B, Widget C" as a single string. 

У меня также есть конец операционного дня отчет, который я хочу добавить в конец отчета о транзакции (Widget A и т. д.).

 Select 
      Transactions.TransactionId, 
      Transactions.TransactionDate, 
      Transactions.MoneyIn, 
      Transactions.MoneyOut, 
      Transactions.Description, 
      PaymentMethods.PaymentMethodName, 
      Transactions.TransactionRef, 
      Membership.Username, 
      Tills.Description As 'Till Name', 
      Transactions.Reason, 
    -- FOR THIS LAST COLUMN HERE I WANT TO SHOW THE OUTPUT OF THE QUERY ABOVE 
====>  SalesItems 
     From 
      Transactions Left Outer Join 
      Tills 
      On Transactions.TillId = Tills.TillId Inner Join 
      PaymentMethods 
      On Transactions.PaymentMethodId = PaymentMethods.PaymentMethodsID Inner Join 
      Membership 
      On Transactions.UserId = Membership.UserId Inner Join 
     Where 
      Transactions.TransactionDate >= @DateStart And 
      Transactions.TransactionDate <= @DateEnd 

Так что, когда я запускаю этот отчет я получаю что-то вроде этого:

TransactionId TransactionDate MoneyIn MoneyOut Description PaymentMethodName TransactionRef Username Till Name Reason SalesItems 
28715 31/08/2016 09:07 119.99 0 Sale - Card Card 24881 Chantal Till1 Null Widget A, Widget B, Widget C 
+0

Huh ???? Это не имеет никакого смысла для меня вообще. Переменные являются скалярными, они не могут содержать несколько значений. И вы не можете назначить переменной значение, подобное этому в середине запроса. Как указано, это совсем не ясно, что вы пытаетесь сделать. –

+0

@SeanLange, что присваивание переменных действительно работает: http://dba.stackexchange.com/questions/68089/how-to-use-coalesce-with-multiple-rows-and-without-preceding-comma – Matt

+0

@Matt смотреть ближе, один столбец в инструкции select присваивает переменную, а остальные возвращают значения в наборе результатов. Это НЕ работает. Конечно, вы можете использовать оператор select для назначения значений переменной, но не в контексте, размещенном здесь. –

ответ

1

CROSS ОТНОСИТЬСЯ С FOR XML конкатенации МЕТОД:

Select 
    t.TransactionId, 
    t.TransactionDate, 
    t.MoneyIn, 
    t.MoneyOut, 
    t.Description, 
    p.PaymentMethodName, 
    t.TransactionRef, 
    m.Username, 
    tl.Description As 'Till Name', 
    t.Reason, 
    c.SalesItems 
From 
    Transactions t 
    LEFT JOIN Tills tl 
    ON t.TillId = tl.TillId 
    INNER JOIN PaymentMethods p 
    ON t.PaymentMethodId = p.PaymentMethodID 
    INNER JOIN Membership m 
    On t.UserId = m.UserId 
    CROSS APPLY 
    (SELECT STUFF(
     (SELECT ',' + CAST(tp.Description AS VARCHAR(100)) 
     FROM 
      TransactionPostLines tp 
     WHERE t.TransactionId = tp.TransactionId 
     FOR XML PATH('')) 
     ,1,1,'') as SalesItems) c 
Where 
    t.TransactionDate >= @DateStart 
    AND t.TransactionDate <= @DateEnd 

AS Sub Выберите в колонке Определение:

Select 
    t.TransactionId, 
    t.TransactionDate, 
    t.MoneyIn, 
    t.MoneyOut, 
    t.Description, 
    p.PaymentMethodName, 
    t.TransactionRef, 
    m.Username, 
    tl.Description As 'Till Name', 
    t.Reason, 
    STUFF(
     (SELECT ',' + CAST(tp.Description AS VARCHAR(100)) 
     FROM 
      TransactionPostLines tp 
     WHERE t.TransactionId = tp.TransactionId 
     FOR XML PATH('')) 
     ,1,1,'') as SalesItems 
From 
    Transactions t 
    LEFT JOIN Tills tl 
    ON t.TillId = tl.TillId 
    INNER JOIN PaymentMethods p 
    ON t.PaymentMethodId = p.PaymentMethodID 
    INNER JOIN Membership m 
    On t.UserId = m.UserId 
Where 
    t.TransactionDate >= @DateStart 
    AND t.TransactionDate <= @DateEnd 

Примечание используя псевдонимы таблиц делает код более удобным читать и писать!

+0

Отлично, спасибо. Точно, что я был после. Какой метод был бы лучшим (или правильным) способом сделать это? – Belliez

+0

, что более личное предпочтение. некоторые говорят, что используют CROSS APPLY, потому что это делает вашу цель более известной и показывает отношения в разделе, но на самом деле не имеет значения, вы можете посмотреть планы выполнения, но я бы предположил, что они будут одинаковыми. – Matt

1

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

Select 
     Transactions.TransactionId, 
     Transactions.TransactionDate, 
     Transactions.MoneyIn, 
     Transactions.MoneyOut, 
     Transactions.Description, 
     PaymentMethods.PaymentMethodName, 
     Transactions.TransactionRef, 
     Membership.Username, 
     Tills.Description As 'Till Name', 
     Transactions.Reason, 
-- HERE >> 
     --SalesItems = 
     dt.salesItems 
    From 
     Transactions Left Outer Join 
     Tills 
     On Transactions.TillId = Tills.TillId Inner Join 
     PaymentMethods 
     On Transactions.PaymentMethodId = PaymentMethods.PaymentMethodsID Inner Join 
     Membership 
     On Transactions.UserId = Membership.UserId 
     cross apply (
    select distinct stuff((
    Select ',' + CAST(TransactionsPosLines.Description as varchar(250)) 
From 
    TransactionsPosLines 
    where TransactionsPosLines.TransactionId = Transactions.TransactionId 
    FOR XML PATH('')),1,1,'') as salesItems 
) as dt 
    -- TransactionsPosLines 
    -- On TransactionsPosLines.TransactionId = Transactions.TransactionId 
    Where 
     Transactions.TransactionDate >= @DateStart And 
     Transactions.TransactionDate <= @DateEnd