有没有办法用子查询返回多个结果?

时间:2009-08-31 18:57:07

标签: sql tsql

我需要从子查询中返回多个结果,并且无法弄清楚。最终结果将在垂直轴上产生人名,基于横轴上的动作类别的各种动作。所以最终结果如下:

----------
**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 个答案:

答案 0 :(得分:9)

我使用用户定义函数执行此任务。 udf创建一个带有与参数匹配的所有元素的分隔字符串,然后从select语句中调用udf,以便为记录集中的每条记录提取分隔列表。

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

答案 1 :(得分:3)

您需要提供有关表格结构以及它们如何相互加入的更多信息。

这是一个关于将多行组合成一列的通用示例:

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)

答案 2 :(得分:1)

这是非常抽象和复杂的。我最初的反应是“透视查询”,但是我看得越多(在早期的回复中)我就越想:你能把这个传递给应用团队吗?你返回“基础”,他们编写并应用程序代码,使这种问题变得轻而易举。当然,你可以将它压缩到SQL,但这并不能使它成为正确的工作场所。

答案 3 :(得分:1)

根据您的查询,试试这个:

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

答案 4 :(得分:0)

您可能需要创建自定义聚合函数。 Microsoft有一篇知识库文章,其中包含示例代码here

答案 5 :(得分:0)

如果您不介意使用游标,可以编写自己的函数来执行此操作。这是一个适用于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