仅显示前n个记录并添加' ...' FOR XML

时间:2014-05-20 07:31:36

标签: sql sql-server-2008-r2

我想只列出几条记录(比如说3)并添加......如果使用FOR XML PATH('')在一行中有更多记录。

到目前为止,我已写过

;WITH SRC AS (
    select 'A' grp, 'abc' rec
    union select 'A', 'def'
    union select 'A', 'ghi'
    union select 'A', 'jkl'
    union select 'B', 'mno'
)
SELECT (
SELECT STUFF((
SELECT TOP 3 ',' + rec FROM SRC
WHERE SRC.grp = tableA.grp
FOR XML PATH('')
), 1, 1, '') + CASE WHEN (SELECT COUNT(1) FROM SRC WHERE SRC.grp = tableA.grp) > 3 THEN ',...' ELSE '' END
)
FROM (SELECT 'A' grp) tableA

上述工作但我想知道是否有办法不从SRC中选择两次来完成作业(一个用于数据,一个用于计数),因为在某些情况下where子句可能是一个大的子句

我也不能将where子句移动到CTE中,因为条件取决于另一个选择的结果(例如从tableA中选择)。

使用MS SQL SERVER 2008 R2

谢谢

1 个答案:

答案 0 :(得分:1)

使用组的前4行创建XML。粉碎前三个节点并返回第四行...

with SRC as 
(
    select 'A' grp, 'abc' rec
    union select 'A', 'def'
    union select 'A', 'ghi'
    union select 'A', 'jkl'
    union select 'B', 'mno'
    union select 'B', 'pqr'
)
select (
       select ','+S2.X.value('.', 'nvarchar(max)')
       from (
            select top(4) S.rec, '...' as eli
            from SRC as S
            where S.grp = tableA.grp
            for xml path('X'), type
            -- order by ?
            ) as S1(X)
         cross apply S1.X.nodes('(X[position() lt 4]/rec, X[position() eq 4]/eli)/text()') as S2(X)
       for xml path(''), type
       ).value('substring(text()[1], 2)', 'nvarchar(max)')
from (select 'A') as tableA(grp);

这是如何运作的?

最里面的查询使用前四行创建XML。

select top(4) S.rec, '...' as eli
from SRC as S
where S.grp = tableA.grp
for xml path('X'), type
-- order by ?

看起来像这样

<X>
  <rec>abc</rec>
  <eli>...</eli>
</X>
<X>
  <rec>def</rec>
  <eli>...</eli>
</X>
<X>
  <rec>ghi</rec>
  <eli>...</eli>
</X>
<X>
  <rec>jkl</rec>
  <eli>...</eli>
</X>

然后使用nodes()

粉碎XML
S1.X.nodes('(X[position() lt 4]/rec, X[position() eq 4]/eli)/text()') as S2(X)

X[position() lt 4]/rec为您提供前三个rec节点的X值,X[position() eq 4]/eli为您提供eli第四行的值。

将碎片XML作为表格的结果。

abc
def
ghi
...

然后使用for xml path进行常规XML连接,并在substring(text()[1], 2)子句中使用values()删除第一个逗号。

另一种方式:

您可以在案例中使用row_number()来确定我返回的第四行的时间。请注意,我在order by函数和嵌套查询中都添加了row_number()子句,以确保返回哪些行。

with SRC as 
(
    select 'A' grp, 'abc' rec
    union select 'A', 'def'
    union select 'A', 'ghi'
    union select 'A', 'jkl'
    union select 'B', 'mno'
    union select 'B', 'pqr'
)
select (
       select top(4) ','+case when row_number() over(order by S.rec) = 4 then '...' else S.rec end
       from SRC as S
       where S.grp = tableA.grp
       order by S.rec
       for xml path(''), type
       ).value('substring(text()[1], 2)', 'nvarchar(max)')
from (select 'A') as tableA(grp);