4

我有一个这样的 SQL 表:

CC     Descr  C_NO     Vol   Wt

2050   Des1   123      20    40
2060   Des2   123      30    50
2050   Des1   125      20    40
2060   Des2   125      30    50
2050   Des1   126      20    40

我想要这样的输出:

2050
    Des1

 123
    20
    40
 125
    20
    40   
 126
    20
    40

2060
    Des2

 123
    30
    50
 125
    30
    50

如何使用 TSQL 代码做到这一点?

对于总是具有相似 Descr 值的每个相似 CC 值,它显示与输出部分中写入的序列中的特定 CC 值相关的所有 C_No、Vol 和 Wt 值。

4

4 回答 4

2

尝试这个

 DECLARE @t TABLE
(
    CC BIGINT,
    Descr NVARCHAR(10),
    C_NO INT,
    Vol SMALLINT,
    WT SMALLINT
)

INSERT INTO @t(CC,Descr,C_NO,Vol,WT)
VALUES  (2050,'Des1',123,20,40)
       ,(2060,'Des2',123,30,50)
       ,(2050,'Des1',125,20,40)
       ,(2060,'Des2',125,30,50)
       ,(2050,'Des1',126,20,40)



;WITH CTE1 AS(
    SELECT 
        t1.CC
        ,t1.Descr
        ,MergedColumn = STUFF(
            (SELECT 
                    ',' 
                    + CAST(C_NO AS VARCHAR(10)) + '/' + CAST(Vol AS VARCHAR(10)) + '/' + CAST(Wt AS VARCHAR(10)) 
            FROM @t AS t2
            WHERE t2.CC=t1.CC AND t2.Descr=t2.Descr
            FOR XML PATH('')),1,1,'')
FROM  @t t1
GROUP BY t1.CC,t1.Descr) 
,CTE2 AS
(
    SELECT
            X.CC
            ,X.Descr
            ,Y.SplitDataByComma         
    FROM
        (
            SELECT 
                    *,
                    CAST('<X>'+REPLACE(F.MergedColumn,',','</X><X>')+'</X>' AS XML) AS xmlfilter 
            FROM CTE1 F
        )X
    CROSS APPLY
    ( 
        SELECT fdata.D.value('.','varchar(50)') AS SplitDataByComma 
        FROM X.xmlfilter.nodes('X') AS fdata(D)
    )Y
)
,CTE3 AS
(
    SELECT
            X.CC
            ,X.Descr
            ,Y.SplitDataBySlash         
            , X.SplitDataByComma AS GrpID
            ,ROW_NUMBER() OVER( PARTITION  BY X.SplitDataByComma ORDER BY X.CC,X.Descr ) AS Rn
            ,X.SplitDataByComma + CAST(CC AS Varchar(200)) + CAST(Descr AS Varchar(200))   CC_Descr 
    FROM
        (
            SELECT 
                    *,
                    CAST('<X>'+REPLACE(F.SplitDataByComma,'/','</X><X>')+'</X>' AS XML) AS xmlfilter 
            FROM CTE2 F
        )X
    CROSS APPLY
    ( 
        SELECT fdata.D.value('.','varchar(50)') AS SplitDataBySlash 
        FROM X.xmlfilter.nodes('X') AS fdata(D)
    )Y
)
,CTE4 AS
(
    SELECT  
        Rn = ROW_NUMBER() OVER(PARTITION BY CC ORDER BY CC)     
        ,CC
        ,Descr      
        ,CASE WHEN  Rn = 1 THEN CAST (SplitDataBySlash AS VARCHAR(10)) ELSE ' '  END C_NO
        ,CASE WHEN  Rn = 1 THEN ' ' ELSE CAST (SplitDataBySlash AS VARCHAR(10)) END Vol_Wt
        ,GrpID  
    FROM Cte3
)
,CTE5 AS(
SELECT 
        CC =  CASE WHEN Rn > 1 THEN ' ' ELSE CAST(CC AS Varchar(200)) END 
        ,Descr =  CASE WHEN Rn > 1 THEN ' ' ELSE CAST(Descr AS Varchar(200)) END 
        ,C_NO
        ,Vol_Wt
        ,GrpID  
FROM Cte4)

SELECT  
          CHAR(10)      
        + REPLICATE(SPACE(1),10) 
        + CAST(CC as VARCHAR(100)) 
        + CHAR(10) 
        + REPLICATE(SPACE(1),15) 
        + Descr
        + CHAR(10)
        + REPLICATE(SPACE(1),10)
        + C_NO
        + CHAR(10) 
        + REPLICATE(SPACE(1),15)
        + Vol_Wt
FROM CTE5

在文本模式(CTRL + T)中,结果是

     2050
           Des1
      123
           20           
           40
      125
           20           
           40
      126
           20
           40

      2060
           Des2
      123
           30           
           50
      125
           30
           50

在 Grid Mode(CTRL + D) 中,结果是

(No column name)
      2050
           Des1
      123 
           20           
           40
      125           
           20           
           40
      126
           20
           40

      2060
           Des2
      123
           30
           50
      125
           30
           50

但是,SQL Server(或任何数据库)不是像其他人所说的那样进行格式化的地方。请调查此事。

于 2012-09-10T09:43:16.633 回答
1

我不会这样做的。TSQL 用于获取数据,然后使用应用程序代码格式化该数据。
但是,如果您在查询分析器中工作并且只想要那里的输出,您可以尝试以下操作:

DECLARE mytable_cursor CURSOR FOR 
SELECT CC, Descr, C_NO, Vol, Wt
FROM myTable
ORDER BY CC, Descr, C_NO

OPEN mytable_cursor;

FETCH NEXT FROM mytable_cursor 
INTO @CC, @Descr, @C_NO, @Vol, @Wt

SET @oCC = @CC
SET @oDescr = @Descr
SET @oC_NO = @C_NO

WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT @CC;
    WHILE @@FETCH_STATUS = 0 AND @oCC = @CC
    BEGIN    
        PRINT '    ' + @Descr;
        WHILE @@FETCH_STATUS = 0 AND @oDescr = @Descr
        BEGIN
            PRINT ' ' + @C_NO;
            WHILE @@FETCH_STATUS = 0 AND @oC_NO = @C_NO
            BEGIN
                PRINT '    ' + @Vol;
                PRINT '    ' + @WT;

                FETCH NEXT FROM mytable_cursor 
                INTO @CC, @Descr, @C_NO, @Vol, @Wt

            END
            SET @oC_NO = @C_NO
        END             
        SET @oDescr = @Descr
    END             
    SET @oCC = @CC
END     
CLOSE mytable_cursor;
DEALLOCATE mytable_cursor;

或者,您可以使用 GROUP BY ... WITH ROLLUP 和 CASE WHEN 来获取单个查询的结果。

这是一个用破折号代替空格的示例,以确保格式可见:

SELECT (CASE
        WHEN Descr IS NULL THEN CC
        WHEN C_NO IS NULL THEN '----' + Descr
        WHEN Vol IS NULL THEN '--' + C_NO
        WHEN Wt IS NULL THEN '------' + Vol
        ELSE '------' + Wt
        END)
FROM
    (SELECT CC, Descr, C_NO, Vol, Wt
    FROM my
    GROUP BY CC, Descr, C_NO, Vol, Wt
    WITH ROLLUP) AS x
WHERE CC IS NOT NULL
ORDER BY CC, Descr, C_NO, Vol, Wt
于 2012-09-07T17:25:33.157 回答
0

您不能在 tsql 代码中执行此操作。您需要在应用程序代码中执行此类操作。

于 2012-09-07T17:09:56.907 回答
0

以分层顺序表示数据的最佳方法之一是使用 XML。更重要的是,XML 的使用通常与出色的性能有关。

使用您的示例信息和代码的和平:

;WITH DistinctValues (CC,Descr ) AS
(
    SELECT DISTINCT CC,Descr 
    FROM @TableOne
)
SELECT  (
            SELECT  CC AS "CC/@CC"
                   ,Descr AS "CC/Descr"
                   ,(
                        SELECT C_NO AS "C_NO/@C_NO",
                               Vol AS "C_NO/Vol",
                               Wt AS "C_NO/Wt"
                        FROM @TableOne AS Data
                        WHERE Data.CC=DV.CC AND Data.Descr=DV.Descr
                        FOR XML PATH(''),TYPE
                   ) AS  "CC"
            FROM DistinctValues AS DV
            FOR XML PATH(''),TYPE
        )
FOR XML PATH('Source'),TYPE

我得到以下结果(以上面语句返回一行的形式):

<Source>
  <CC CC="2050">
    <Descr>Des1</Descr>
    <C_NO C_NO="123">
      <Vol>20</Vol>
      <Wt>40</Wt>
    </C_NO>
    <C_NO C_NO="125">
      <Vol>20</Vol>
      <Wt>40</Wt>
    </C_NO>
    <C_NO C_NO="126">
      <Vol>20</Vol>
      <Wt>40</Wt>
    </C_NO>
  </CC>
  <CC CC="2060">
    <Descr>Des2</Descr>
    <C_NO C_NO="123">
      <Vol>30</Vol>
      <Wt>50</Wt>
    </C_NO>
    <C_NO C_NO="125">
      <Vol>30</Vol>
      <Wt>50</Wt>
    </C_NO>
  </CC>
</Source>

请注意,T-SQL 中的 XML 函数与 XML 语言结构相结合,为您提供了大量可能的输出数据格式变化——您使用一个或多个节点,您可以将数据表示为属性或节点文本。随意组合它,并且您认为在您的应用程序级别中使用它是最容易的。

这是我用来生成先前 XML 结构的整个代码(只需复制和粘贴):

DECLARE @TableOne TABLE
(
    CC BIGINT,
    Descr NVARCHAR(10),
    C_NO INT,
    Vol SMALLINT,
    WT SMALLINT
)

INSERT INTO @TableOne(CC,Descr,C_NO,Vol,WT)
VALUES  (2050,'Des1',123,20,40)
       ,(2060,'Des2',123,30,50)
       ,(2050,'Des1',125,20,40)
       ,(2060,'Des2',125,30,50)
       ,(2050,'Des1',126,20,40)

;WITH DistinctValues (CC,Descr ) AS
(
    SELECT DISTINCT CC,Descr 
    FROM @TableOne
)
SELECT  (
            SELECT  CC AS "CC/@CC"
                   ,Descr AS "CC/Descr"
                   ,(
                        SELECT C_NO AS "C_NO/@C_NO",
                               Vol AS "C_NO/Vol",
                               Wt AS "C_NO/Wt"
                        FROM @TableOne AS Data
                        WHERE Data.CC=DV.CC AND Data.Descr=DV.Descr
                        FOR XML PATH(''),TYPE
                   ) AS  "CC"
            FROM DistinctValues AS DV
            FOR XML PATH(''),TYPE
        )
FOR XML PATH('Source'),TYPE

这就像一个魅力,它在 Microsoft SQL Server Management Studio 2012 上进行了测试。

于 2012-09-09T08:06:02.497 回答