子查询以逗号分隔格式生成

时间:2014-03-13 15:35:20

标签: sql sql-server tsql

我正在尝试编写一个子查询,它将所有结果存储在一个用逗号分隔的单个列中。我的代码看起来像这样

SELECT column1, 
       column2, 
       CourseRequests=(SELECT INNERCourseRequests = 
                              COALESCE(CASE 
                                         WHEN innercourserequests 
                                              = '' THEN 
                                         crse_name 
                                         ELSE innercourserequests 
                                              + ',' + 
                                              crse_name 
                                       END, '') 
                       FROM   tor_studentcrserequest SCR 
                       WHERE  SCR.stud_pk = MS.tt_stud_pk 
                              AND SCR.delt_flag = 0), 
       column4 
FROM   tbl_mainstudent MS   

当我尝试执行存储过程时,出现错误Invalid column name 'INNERCourseRequests'.

这样做的正确方法是什么? TSR是对外部列的表的引用

编辑:我把它改为:

 CourseRequests=(SELECT INNERCourseRequests = 
 COALESCE(case when @INNERCourseRequests='' THEN CRSE_NAME ELSE
@INNERCourseRequests+','+CRSE_NAME end,'')

但是,现在我收到的错误是subquery returned more than 1 result,这是预期的。

2 个答案:

答案 0 :(得分:1)

您可以使用FOR XML以及一些REPLACE,如下所示:

SELECT column1, 
       column2, 
       CourseRequests=COALESCE(
                        REPLACE(REPLACE(REPLACE((
                       SELECT crse_name 
                       FROM   (
                                         SELECT 1, 22,  'first',  0
                               UNION ALL SELECT 2, 22,  'second', 1
                               UNION ALL SELECT 3, 22,  'third',  0
                               UNION ALL SELECT 4, 555, 'first',  1
                       ) SCR (id, stud_pk, crse_name, delt_flag)
                       WHERE  SCR.stud_pk = MS.tt_stud_pk 
                       AND SCR.delt_flag = 0
                       FOR XML PATH('')
                       ),'</crse_name><crse_name>', ','),
                     '</crse_name>', ''), -- remove end tag
                     '<crse_name>', ''), -- remove beginning tag
                      ''), -- optional COALESCE to ensure no NULLs
       column4 
FROM   (
                   SELECT  1, 'a', 'b', '2014-01-01'
         UNION ALL SELECT 22, 'd', 'e', '2014-02-02'
       ) MS (tt_stud_pk, column1, column2, column4)

输出

column1 column2 CourseRequests  column4  
a       b                       2014-01-01  
d       e       first,third     2014-02-02  

<强>解释
FOR XML PATH(&#39;&#39;)将子查询的结果展平为:
<crse_name>first</crse_name><crse_name>third</crse_name>

  1. 第一个REPLACE只转换仅在值之间找到的结束标记/开始标记组合(即逗号去的地方)
  2. 第二个REPLACE删除结束标记(不能在第一个REPLACE之前完成)
  3. 第三个REPLACE删除了开始标记(不能在第一次REPLACE之前完成)
  4. 注意:
    可能会有更优雅的方式来处理XML内容,因此您不需要所有REPLACE,但不确定,这确实有效。

答案 1 :(得分:0)

我很确定你无法用一个查询来做到这一点,而且我并不完全确定我所采用的策略 想出来是一种合法的策略 - 意思是,如果它没有记录,可能是SQL的未来版本 不支持这个。随着说:

从以下开始:

DECLARE @List varchar(max)

SELECT @List = isnull(@List + ', ', '') + InnerCourseRequests
 from tor_studentcrserequest
 where stud_pk = <TestValue>
  and delt_flag = 0

PRINT @List

这将为tor_studentcrserequest表生成一个逗号分隔的所有InnerCourseRequests列表,用于单个stud_pk。

接下来,将其变成一个函数:

DROP FUNCTION phkTest
GO
CREATE FUNCTION phkTest (@stud_pk  int)  --  Change datatype, if not int
RETURNS varchar(max)
AS
 BEGIN
    DECLARE @List varchar(max)

    SELECT @List = isnull(@List + ', ', '') + InnerCourseRequests
     from tor_studentcrserequest
     where stud_pk = @stud_pk
      and delt_flag = 0

    RETURN @List
 END
GO

(为delt_flag添加第二个参数,如果这可能会有所不同)

并将其添加到查询中:

SELECT distinct tt_stud_pk, dbo.phkTest(stud_pk)
 from tbl_mainstudent

(我使用我的一个表编写了所有这些,然后将表/列剪切并粘贴,因此可能会遇到一些语法问题。)

可能有一些方法可以提高大表的性能(OUTER APPLY,在调用函数之前选择不同的,等等),并且很可能会这样做最好通过程序代码完成,无论是首先查询数据。