用"和#34替换最后一项的逗号分隔符;在Sql STUFF命令中

时间:2014-12-09 11:42:50

标签: sql-server reporting-services

如果我的查询输出是英格兰,美国,印度。

是否可以显示查询结果,例如英格兰,美国印度

这是我的问题:

Select stuff( ( Select Distinct ',' + Country as[text()] 
from tbl_Country 
where OrderNo in (Select Max(OrderNo) from Tbl_Literature where ID='AB123' 
                  Group By OrderNo) for XML path('') ),1,1,'')as Result 
from dbo.Tbl_Master as TP 
where 
  TP.OrderNo IN (select MAX(order No) from dbo.Tbl_Master where TP.ID = 'AB123') 

4 个答案:

答案 0 :(得分:2)

假设您指的是为了弥补SqlServer缺少GROUP_CONCAT所做的字符串聚合黑客攻击,您可以在此处使用此ingenious hack

WITH myStuffedCte AS
(SELECT 
    STUFF((
          SELECT ',' + Name
          FROM Country
          FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') AS SomeCol
)
SELECT ISNULL(reverse(replace(STUFF(reverse(SomeCol),
                      charindex(',',reverse(SomeCol)),0,'#'),'#,',' dna ')),
              SomeCol)
FROM myStuffedCte;

SqlFiddle here

使用GROUPING条件

更新了资料示例

为了以STUFF方式使用GROUP BY,您可以根据具有WHERE子句的外部查询行手动过滤内部STUFF子查询。

WITH myStuffedCte AS
(
    SELECT p.FirstName, p.LastName,
        STUFF((
              SELECT ',' + c.Name
              FROM Country c
              INNER JOIN PersonCountryVisits pcv
              ON pcv.CountryId = c.CountryId
              WHERE pcv.PersonId = p.PersonID -- Manual Filter step
              FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') AS SomeCol
    FROM Person p
)
SELECT FirstName, LastName,
   ISNULL(reverse(replace(STUFF(reverse(SomeCol),
          charindex(',',reverse(SomeCol)),0,'#'),'#,',' dna ')), 
          SomeCol) AS CountriesVisited
FROM myStuffedCte;

Updated Sql Fiddle example here

SqlClr替代Stuff,IFF你可以在你的SqlServer上使用SqlClr:
如果您有权访问启用了Sql-Clr的SqlServer,则可以放弃这两个hacks,而是将STUFF / FOR XML替换为GROUP_CONCAT simulation of SqlUserDefinedAggregate like this one,同时执行最后一个逗号替换为SqlFunction UDF,如下所示:

[SqlFunction]
public static SqlString ReplaceLast(SqlString source, SqlString find, SqlString replace, 
                                    int countFromRight)
{
    var splits = source.Value
        .Split(new[] {find.Value}, StringSplitOptions.None);

    var replacePoint = splits.Length - countFromRight;

    return (replacePoint > 0)
        ? new SqlString(
            string.Join(replace.Value,
                new[] { string.Join(find.Value, splits.Take(replacePoint)) }
                .Union(splits.Skip(replacePoint))))
        : source;
}

在这种情况下,样本查询变得更加可口:

SELECT FirstName, LastName, 
    dbo.ReplaceLast(dbo.GROUP_CONCAT(c.Name, ','), ',', ' and ', 1)
FROM  Person p 
    INNER JOIN PersonCountryVisits pcv
    ON pcv.PersonId = p.PersonID
    INNER JOIN Country c
    ON pcv.CountryId = c.CountryId
GROUP BY FirstName, LastName;

我已经提出了一个Gist on GitHub,它提供了创建GROUP_CONCATReplaceLast SqlClr函数的所有重要位。 (SqlFiddle不可用 - 没有SQLClr ......)

答案 1 :(得分:2)

正如你提到的stuff命令,我假设你使用FOR XML PATH('')连接你的项目,STUFF删除第一个分隔符,例如。

SELECT  STUFF(( SELECT  ', ' + Country
                FROM    InnerTable AS i
                WHERE   i.ID = o.ID
                ORDER BY Country
                FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
FROM    OuterTable AS o;

如果是这种情况,那么您可以使用ROW_NUMBER()来标识最后一行(通过使用子查询的反向排序),并将AND放在那里:

SELECT  STUFF(( SELECT  ', ' + CASE WHEN ROW_NUMBER() OVER(ORDER BY Country DESC) = 1 
                                    THEN 'and ' 
                                    ELSE '' 
                                END + Country
                FROM    InnerTable AS i
                WHERE   i.ID = o.ID
                ORDER BY Country ASC
                FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
FROM    OuterTable AS o;

n.b。上面会产生一个字符串serial comma(例如"英格兰,美国和印度"),但它不需要太多操作来改变它。

简单示例

SELECT  STUFF(( SELECT  ', ' + CASE WHEN ROW_NUMBER() OVER(ORDER BY Country DESC) = 1 
                                    THEN 'and ' 
                                    ELSE '' 
                                END + Country
                FROM    (VALUES ('America'), ('England'), ('India')) AS i (Country)
                ORDER BY Country ASC
                FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)'), 1, 2, '');

答案 2 :(得分:0)

试试这个:

    Declare @String varchar(100)

    set @String = 'England, America, India'

    SELECT reverse(replace(STUFF(reverse(@String),
           charindex(',',reverse(@String)),0,'#'),'#,',' dna '))

答案 3 :(得分:0)

使用SUBSTRING()。有关更多String功能

,请参阅this
 DECLARE @s AS VARCHAR(100)

 SET @s = 'England, America, India'

 SELECT SUBSTRING(@s, 0, LEN(@s) -  CHARINDEX(',', REVERSE(@s)) + 1 ) 
        + ' and' 
        + SUBSTRING(@s, LEN(@s) -  CHARINDEX(',', REVERSE(@s)) + 2, len(@s))