Есть ли способ вернуть несколько результатов с помощью подзапроса? - PullRequest
6 голосов
/ 31 августа 2009

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

----------
**NAME            CATEGORY 1             CATEGORY 2**

Smith, John     Action 1, Action 2     Action 1, Action 2, Action 3


----------

Есть ли способ сделать это в одном запросе?

select
   name,
   (select action from actionitemtable where actioncategory = category1 and contact = contactid)
from
   contact c
   inner join actionitemtable a
     on c.contactid = a.contactid

Если в этом подзапросе будет возвращено более одного результата, я бы хотел отобразить его в виде строки, разделенной запятой, или списка действий и т. Д.

Спасибо.

Используется Microsoft Sql Server 2005.

Ответы [ 6 ]

9 голосов
/ 31 августа 2009

Я использую пользовательскую функцию для этой задачи. Udf создает строку с разделителями, все элементы которой соответствуют параметрам, затем вы вызываете udf из оператора select так, что вы вытягиваете список с разделителями для каждой записи в наборе записей.

CREATE FUNCTION dbo.ud_Concat(@actioncategory int, @contactid int)
RETURNS VARCHAR(8000)
AS
BEGIN
    DECLARE @sOutput VARCHAR(8000)
    SET @sOutput = ''

    SELECT @sOutput = COALESCE(@sOutput, '') + action + ', '
    FROM dbo.actionitemtable
    WHERE actioncategory=@actioncategory AND contact=@contact 
    ORDER BY action

    RETURN @sOutput
END

SELECT 
   name, 
   dbo.ud_Concat(category1, contactid) as contactList
FROM contact c
INNER JOIN actionitemtable a ON c.contactid = a.contactid
3 голосов
/ 31 августа 2009

вам нужно дать больше информации о структуре вашей таблицы и о том, как они соединяются друг с другом.

Вот общий пример объединения нескольких строк в один столбец:

declare @table table (name varchar(30)
                     ,ID int
                     ,TaskID char(3)
                     ,HoursAssigned int
                     )

insert into @table values ('John Smith'   ,4592 ,'A01'  ,40)
insert into @table values ('Matthew Jones',2863 ,'A01'  ,20)
insert into @table values ('Jake Adams'   ,1182 ,'A01'  ,100)
insert into @table values ('Matthew Jones',2863 ,'A02'  ,50)
insert into @table values ('Jake Adams'   ,2863 ,'A02'  ,10)


SELECT DISTINCT
    t1.TaskID
       ,SUBSTRING(
                  replace(
                          replace(
                                  (SELECT
                                       t2.Name
                                       FROM @Table AS t2
                                       WHERE t1.TaskID=t2.TaskID
                                       ORDER BY t2.Name
                                       FOR XML PATH(''))
                                 ,'</NAME>','')
                         ,'<NAME>',', ')
                 ,3,2000)  AS PeopleAssigned
    FROM @table AS t1

ВЫВОД:

TaskID PeopleAssigned
------ --------------------------------------
A01    Jake Adams, John Smith, Matthew Jones
A02    Jake Adams, Matthew Jones

(2 row(s) affected)
1 голос
/ 31 августа 2009

По вашему запросу попробуйте это:

SELECT [Name],
       STUFF(
         (
           SELECT ' ,' + [Action] 
           FROM   [AactionItemTable]
           WHERE  [ActionCategory] = category1 
                  AND [Contact] = contactid
           FOR XML PATH('')
         ), 1, 2, ''                
       ) AS [AdditionalData]
FROM   [Contact] C
       INNER JOIN [ActionItemTable] A
       ON C.[ContactId] = A.[ContactId]

Думаю, это самый простой способ сделать то, что вы хотите.

РЕДАКТИРОВАТЬ: если в подзапросе не найдено никаких действий, результатом [AdditionalData] будет NULL.

1 голос
/ 31 августа 2009

Это довольно абстрактно и сложно. Моей первоначальной реакцией был «сводный запрос», но чем больше я смотрел на него (и на более ранние ответы), тем больше я думал: можете ли вы передать его команде разработчиков? Вы возвращаете «базу», а они пишут и применяют процедурный код, который делает проблему такого рода несложной. Конечно, вы можете втиснуть его в SQL, но это не делает его подходящим местом для выполнения работы.

0 голосов
/ 31 августа 2009

Если вы не возражаете против использования курсоров, вы можете написать свою собственную функцию для этого. Вот пример, который будет работать с образцом БД Adventureworks:

CREATE FUNCTION CommaFunctionSample 
(
    @SalesOrderID int
)
RETURNS varchar(max)
AS
BEGIN

DECLARE OrderDetailCursor CURSOR LOCAL FAST_FORWARD
FOR
SELECT SalesOrderDetailID
FROM Sales.SalesOrderDetail
WHERE SalesOrderID = @SalesOrderID

DECLARE @SalesOrderDetailID INT

OPEN OrderDetailCursor

FETCH NEXT FROM OrderDetailCursor INTO @SalesOrderDetailID
DECLARE @Buffer varchar(max)
WHILE @@FETCH_STATUS = 0
BEGIN
    IF @Buffer IS NOT NULL SET @Buffer = @Buffer + ','
    ELSE SET @Buffer = ''

    SET @Buffer = @Buffer + CAST(@SalesOrderDetailID AS varchar(12))

    FETCH NEXT FROM OrderDetailCursor INTO @SalesOrderDetailID
END

CLOSE OrderDetailCursor
DEALLOCATE OrderDetailCursor

RETURN @Buffer
END

Так выглядит такая функция в запросе выбора:

SELECT AccountNumber, dbo.CommaFunctionSample(SalesOrderID)
FROM Sales.SalesOrderHeader
0 голосов
/ 31 августа 2009

Возможно, вам придется создать собственную функцию агрегирования. У Microsoft есть статья базы знаний с примером кода здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...