【问题标题】:How to display the multiple values in a single column with line by line in SQL SERVER 2008 R2?如何在 SQL SERVER 2008 R2 中逐行显示单个列中的多个值?
【发布时间】:2013-02-18 09:38:13
【问题描述】:

我正在使用 SQL SERVER 2008 R2。我想获取多个值并同时逐行显示在单列中,如果存在值,否则它会显示一些值,并且可能在单列上显示“12 个值”。

例如,下面的屏幕截图,它显示了除了 cmets 之外的相同数据的记录。我想显示为 单个记录,,但 cmets 应显示 ASN 及时性、ASN 准确性、问题报告 这两个值。这三个值使用相同的shipsite “0096a”逐行显示。

我的示例查询,

SELECT 
    D30.SPGD30_SHIP_SITE_C AS SHIPSITE,  
    D30.SPGD30_RATING_MONTH_Y AS RATINGMONTH,  
    D30.SPGD30_PRIOR_SCORE_R AS PRIOR, 
    D30.SPGD30_REVISED_SCORE_R AS REVISED,  
    CASE WHEN (CHARINDEX('-',D30.SPGD30_TRACKED_ADJUSTMENT_X) > 0 ) THEN CONVERT( VARCHAR(8), CAST(D30.SPGD30_TRACKED_ADJUSTMENT_X AS DATETIME) , 1) ELSE D30.SPGD30_TRACKED_ADJUSTMENT_X END ADJUSTMENTS,  
    J02.SPGJ02_MSG_CODE_X AS COMMENTS,  
    D30.SPGD30_LAST_TOUCH_Y AS LASTUPDATED,  
    D30.SPGD30_LAST_TOUCH_C AS LASTUPDATEDCDSID   
FROM  
    CSPGD30_TRACKING D30, 
    CSPGD31_TRACKING_RATING_ELEMNT D31,  
    CSPGA04_RATING_ELEMENT_MSTR A04 , 
    CSPGJ02_MSG_OBJ J02  
WHERE  
    D30.SPGA02_BUSINESS_TYPE_C = D31.SPGA02_BUSINESS_TYPE_C  
AND 
    D30.SPGA03_REGION_C = D31.SPGA03_REGION_C  
AND 
    D30.SPGD30_SHIP_SITE_C = D31.SPGD30_SHIP_SITE_C  
AND 
    D30.SPGD30_RATING_MONTH_Y = D31.SPGD30_RATING_MONTH_Y  
AND 
    D30.SPGD30_TRACKED_ADJUSTMENT_X = D31.SPGD30_TRACKED_ADJUSTMENT_X  
AND 
    D30.SPGD30_LAST_TOUCH_Y = D31.SPGD30_LAST_TOUCH_Y  
AND 
    D31.SPGA04_RATING_ELEMENT_D = A04.SPGA04_RATING_ELEMENT_D  
AND 
    A04.SPGJ02_MSG_K = J02.SPGJ02_MSG_K  
AND 
    D30.SPGA02_BUSINESS_TYPE_C = 'serv'  
AND 
    D30.SPGA03_REGION_C = 'ap'  
AND 
    D30.SPGD30_SHIP_SITE_C = '0134a'  
ORDER BY   
    D30.SPGD30_SHIP_SITE_C ASC  ,
    D30.SPGD30_RATING_MONTH_Y DESC  ,
    D30.SPGD30_LAST_TOUCH_Y DESC 

【问题讨论】:

  • 你想要的结果是什么?栏目很多,你要显示哪些栏目?
  • 我想在单个列中显示多个值(12 级元素)。例如,如果存在 8 个评级元素,我们将在单个列中仅显示 8 个评级元素。
  • @Adalarasan_Serangulam 您能否发布一些示例数据和所需的结果而不是图像?更好的是使用您的表结构、示例数据创建 SQL Fiddle
  • 您真的需要这个作为 SQL 查询还是为了在 SSRS 报告上显示?

标签: sql sql-server sql-server-2008 sql-server-2005 sql-server-2008-r2


【解决方案1】:

我发现有两种方法可以做到这一点。

首先,您可以在相关子查询中使用FOR XML PATHSTUFF。这会将CSPGJ02_MSG_OBJ 中的值连接成一个字符串:

SELECT D30.SPGD30_SHIP_SITE_C AS SHIPSITE,  
    D30.SPGD30_RATING_MONTH_Y AS RATINGMONTH,  
    D30.SPGD30_PRIOR_SCORE_R AS PRIOR, 
    D30.SPGD30_REVISED_SCORE_R AS REVISED,  
    CASE WHEN (CHARINDEX('-',D30.SPGD30_TRACKED_ADJUSTMENT_X) > 0 ) THEN CONVERT( VARCHAR(8), CAST(D30.SPGD30_TRACKED_ADJUSTMENT_X AS DATETIME) , 1) ELSE D30.SPGD30_TRACKED_ADJUSTMENT_X END ADJUSTMENTS,  
     STUFF((SELECT distinct '+ ' + J02.SPGJ02_MSG_CODE_X
            from CSPGJ02_MSG_OBJ J02
            where A04.SPGJ02_MSG_K = J02.SPGJ02_MSG_K 
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,2,'') COMMENTS,
    D30.SPGD30_LAST_TOUCH_Y AS LASTUPDATED,  
    D30.SPGD30_LAST_TOUCH_C AS LASTUPDATEDCDSID   
FROM CSPGD30_TRACKING D30
INNER JOIN CSPGD31_TRACKING_RATING_ELEMNT D31
    ON D30.SPGA02_BUSINESS_TYPE_C = D31.SPGA02_BUSINESS_TYPE_C  
    AND D30.SPGA03_REGION_C = D31.SPGA03_REGION_C  
    AND D30.SPGD30_SHIP_SITE_C = D31.SPGD30_SHIP_SITE_C  
    AND D30.SPGD30_RATING_MONTH_Y = D31.SPGD30_RATING_MONTH_Y  
    AND D30.SPGD30_TRACKED_ADJUSTMENT_X = D31.SPGD30_TRACKED_ADJUSTMENT_X  
    AND D30.SPGD30_LAST_TOUCH_Y = D31.SPGD30_LAST_TOUCH_Y  
INNER JOIN CSPGA04_RATING_ELEMENT_MSTR A04
    ON D31.SPGA04_RATING_ELEMENT_D = A04.SPGA04_RATING_ELEMENT_D  
WHERE D30.SPGA02_BUSINESS_TYPE_C = 'serv'  
    AND D30.SPGA03_REGION_C = 'ap'  
    AND D30.SPGD30_SHIP_SITE_C = '0134a'  
ORDER BY D30.SPGD30_SHIP_SITE_C ASC, D30.SPGD30_RATING_MONTH_Y DESC, D30.SPGD30_LAST_TOUCH_Y DESC;

第二种方法是使用CROSS APPLYFOR XML PATH

SELECT D30.SPGD30_SHIP_SITE_C AS SHIPSITE,  
    D30.SPGD30_RATING_MONTH_Y AS RATINGMONTH,  
    D30.SPGD30_PRIOR_SCORE_R AS PRIOR, 
    D30.SPGD30_REVISED_SCORE_R AS REVISED,  
    CASE WHEN (CHARINDEX('-',D30.SPGD30_TRACKED_ADJUSTMENT_X) > 0 ) THEN CONVERT( VARCHAR(8), CAST(D30.SPGD30_TRACKED_ADJUSTMENT_X AS DATETIME) , 1) ELSE D30.SPGD30_TRACKED_ADJUSTMENT_X END ADJUSTMENTS,  
    left(J02.comments, LEN(J02.comments)-1) AS COMMENTS,
    D30.SPGD30_LAST_TOUCH_Y AS LASTUPDATED,  
    D30.SPGD30_LAST_TOUCH_C AS LASTUPDATEDCDSID   
FROM CSPGD30_TRACKING D30
INNER JOIN CSPGD31_TRACKING_RATING_ELEMNT D31
    ON D30.SPGA02_BUSINESS_TYPE_C = D31.SPGA02_BUSINESS_TYPE_C  
    AND D30.SPGA03_REGION_C = D31.SPGA03_REGION_C  
    AND D30.SPGD30_SHIP_SITE_C = D31.SPGD30_SHIP_SITE_C  
    AND D30.SPGD30_RATING_MONTH_Y = D31.SPGD30_RATING_MONTH_Y  
    AND D30.SPGD30_TRACKED_ADJUSTMENT_X = D31.SPGD30_TRACKED_ADJUSTMENT_X  
    AND D30.SPGD30_LAST_TOUCH_Y = D31.SPGD30_LAST_TOUCH_Y  
INNER JOIN CSPGA04_RATING_ELEMENT_MSTR A04
    ON D31.SPGA04_RATING_ELEMENT_D = A04.SPGA04_RATING_ELEMENT_D  
CROSS APPLY
(
    select J02.SPGJ02_MSG_CODE_X  + ', '
    from CSPGJ02_MSG_OBJ J02
    where A04.SPGJ02_MSG_K = J02.SPGJ02_MSG_K  
    FOR XML PATH('')
) J02 (comments)
WHERE D30.SPGA02_BUSINESS_TYPE_C = 'serv'  
    AND D30.SPGA03_REGION_C = 'ap'  
    AND D30.SPGD30_SHIP_SITE_C = '0134a'  
ORDER BY D30.SPGD30_SHIP_SITE_C ASC, D30.SPGD30_RATING_MONTH_Y DESC, D30.SPGD30_LAST_TOUCH_Y DESC;

注意:您会注意到我将您的查询更改为使用JOIN 语法,而不是使用WHERE 子句中的连接的逗号分隔表。这是标准的 ANSI 语法。

【讨论】:

  • 它对我不起作用。它不会逐行显示。那我该怎么办。它显示了两条记录,(使用 SQL Server 2008 r2)
  • @Adalarasan_Serangulam 我的建议是使用您的表和一些示例数据创建一个 SQL Fiddle,或者使用每个表的完整表结构和示例数据编辑您的帖子。
  • @Adalarasan_Serangulam SQL Fiddle 将是最好的,因为这样我们将拥有一个工作数据模型。
【解决方案2】:

使用 XML PATH('')

SELECT 
    D30.SPGD30_SHIP_SITE_C AS SHIPSITE,  
    D30.SPGD30_RATING_MONTH_Y AS RATINGMONTH,  
    D30.SPGD30_PRIOR_SCORE_R AS PRIOR, 
    D30.SPGD30_REVISED_SCORE_R AS REVISED,  
    CASE WHEN (CHARINDEX('-',D30.SPGD30_TRACKED_ADJUSTMENT_X) > 0 ) THEN CONVERT( VARCHAR(8), CAST(D30.SPGD30_TRACKED_ADJUSTMENT_X AS DATETIME) , 1) ELSE D30.SPGD30_TRACKED_ADJUSTMENT_X END ADJUSTMENTS,  
    STUFF(JO2.COMMENTS, 1, 1, '') AS COMMENTS,  
    D30.SPGD30_LAST_TOUCH_Y AS LASTUPDATED,  
    D30.SPGD30_LAST_TOUCH_C AS LASTUPDATEDCDSID   
FROM  
    CSPGD30_TRACKING D30 
CROSS JOIN CSPGD31_TRACKING_RATING_ELEMNT D31
CROSS JOIN CSPGA04_RATING_ELEMENT_MSTR A04
CROSS APPLY (
    SELECT
        ',' + ISNULL(JO2.SPGJ02_MSG_CODE_X, '')
    FROM CSPGJ02_MSG_OBJ JO2  
    WHERE A04.SPGJ02_MSG_K = JO2.SPGJ02_MSG_K  
    FOR XML PATH('')
) AS JO2 (COMMENTS)
WHERE  
    D30.SPGA02_BUSINESS_TYPE_C = D31.SPGA02_BUSINESS_TYPE_C  
AND 
    D30.SPGA03_REGION_C = D31.SPGA03_REGION_C  
AND 
    D30.SPGD30_SHIP_SITE_C = D31.SPGD30_SHIP_SITE_C  
AND 
    D30.SPGD30_RATING_MONTH_Y = D31.SPGD30_RATING_MONTH_Y  
AND 
    D30.SPGD30_TRACKED_ADJUSTMENT_X = D31.SPGD30_TRACKED_ADJUSTMENT_X  
AND 
    D30.SPGD30_LAST_TOUCH_Y = D31.SPGD30_LAST_TOUCH_Y  
AND 
    D31.SPGA04_RATING_ELEMENT_D = A04.SPGA04_RATING_ELEMENT_D  
AND 
    D30.SPGA02_BUSINESS_TYPE_C = 'serv'  
AND 
    D30.SPGA03_REGION_C = 'ap'  
AND 
    D30.SPGD30_SHIP_SITE_C = '0134a'  
ORDER BY   
    D30.SPGD30_SHIP_SITE_C ASC  ,
    D30.SPGD30_RATING_MONTH_Y DESC  ,
    D30.SPGD30_LAST_TOUCH_Y DESC 

这将创建一个逗号分隔的 cmets 列表。

【讨论】:

  • 我写的是 0 而不是 O。很高兴有人给了我反对票...(是的,我想有趣的部分不是 CROSS APPLY 或 XML PATH,而是Oes 和 Zeroes...)
  • 我没有投反对票,但您能解释一下为什么您在 WHERE 子句中使用 CROSS JOIN 和连接条件,而不是正确、现代且更直观的 INNER JOIN 语法吗?
  • @Serge 如果 OP 是初学者,最好让他们远离这种类型的查询。问题中的原始形式更糟糕。
  • @Serge 他们是这样做的,我只是想知道你是否愿意在这些东西最好的时候揭晓。
  • @Serge I'm experienced enough to know standards/guidelines aren't always the best path to follow. 哦,请告诉我们为什么在这种情况下正确的INNER JOIN 不是最好的路径?你的CROSS JOIN 提供了哪些优势,除了继续鼓励应该避免的过时的编码实践?
【解决方案3】:

如果要在一列中显示多列,可以这样写:

SELECT CAST([MyIntegerId] AS varchar(10)) + ' - ' + [Column1]+ ' - ' +CAST([MyDateTimeColumn] AS varchar(10)) + ' - ' + [Column2] AS 'My Merged Column'
FROM Mytable

如果您想将多列分组为单个列作为字符串 - 这个article 应该可以帮助您:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-15
    • 2013-02-04
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    相关资源
    最近更新 更多