SQL如何在输出COLUMN顺序很重要时有效地使用动态sql查询

时间:2012-10-14 17:48:10

标签: sql sql-server tsql dynamic-sql

我的问题是如何确保在使用动态查询获取数据时保持OUTPUT的ORDER。我有几个我正在使用的动态查询,我注意到当我在不同的机器上运行相同的查询时,我得到不同顺序的输出。目前,我将输出的数据存储到临时表中,该临时表假定输出的顺序与我本地机器上的输出顺序相同,但在生产时,它都被切换。如何对此进行更多控制,以便每次运行查询,输出的顺序是否保持?

当我在动态查询中使用Order BY时,我收到错误

Msg 1033,Level 15,State 1,Line 18 除非还指定了TOP,OFFSET或FOR XML,否则ORDER BY子句在视图,内联函数,派生表,子查询和公用表表达式中无效。

 DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @colsPivot as  NVARCHAR(MAX)

           IF EXISTS
                (
                            SELECT *
                            FROM tempdb.dbo.sysobjects
                            WHERE ID = OBJECT_ID(N'tempdb..#ibutes')
                )
                BEGIN
                            DROP TABLE #ibutes
                END
    Create table #ibutes
    (
                ProductID uniqueIdentifier,
            PAID uniqueidentifier, 
            Label nvarchar(50),
            Val nvarchar(3072),
            unit nvarchar(50) 
    )
    ;With Number
As
(
 Select 1 as rownum union all  Select 2 union all Select 3 union all Select 4 union all Select 5 union all Select 6 union all Select 7 union all Select 8 union all Select 9 union all Select 10 union all Select 11 union all Select 12 union all Select 13 union all Select 14 union all Select 15 union all Select 16 union all Select 17 union all Select 18 union all Select 19 union all Select 20 union all Select 21 
),
ProductDetail 
as 
(
   select P.ProdID, N.rownum from IDWProduct P cross join Number N
)
Insert into #ibutes
Select ProdID ,  PAVibuteID, COALESCE(PANAme,''), COALESCE(PAVValue,''), COALESCE(unitLabel,'') 
 from ProductDetail P
Left join 
(select Pr.*, PAName, row_number() over (partition by PAVProductID order by PAVID) as Rn from IDWProductibuteValues Pr  
inner join IDWibutes  on PAID = PAVibuteID Where PAIscustom = 0 AND PAIsManufacturerSpecific =0 AND PANAME NOT IN 
('Brand Name', 'Standard', 'Application', 'Sub Brand', 'Type', 'Special Features')) 
Pr ON rownum = Pr.Rn And PAVProductID = ProdID  
left join IDWUnitofMeasures on Pr.PAVunit = unitID 

--Select * from #ibutes

   select @colsUnpivot = stuff((select ','+quotename(C.name)
         from tempdb.sys.columns as C  
         where C.object_id = object_id('tempdb..#ibutes')  AND  C.name Not in ('ProductID')
         for xml path('')), 1, 1, '')

 --select @colsUnpivot

 select @colsPivot = STUFF((SELECT  ','  + quotename(c.name   + cast(t.rn as varchar(10)))
                    from
                    (
                      select row_number() over(partition by ProductID   order by ProductID) rn  from #ibutes
                    ) t
                     cross apply 
                      tempdb.sys.columns  as C
                   where C.object_id = object_id('tempdb..#ibutes')   AND  C.name Not in ('ProductID')
                   group by c.name, t.rn
                   order by t.rn
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

  --select @colsPivot
  set @query = 'select *
      from
      (
        select ProductID,
            col + cast(rn as varchar(10)) new_col,
            val
        from 
        (
          select   
           Cast (PAID as NVarchar(3072)) PAID
           ,Cast (ProductID as NVarchar(3072)) ProductID
           ,Cast (Label  as NVarchar(3072)) Label
           ,Cast (Val as NVarchar(3072)) Val
           ,Cast (unit as NVarchar(3072))  unit  
            ,row_number() over(partition by ProductID order by ProductID) rn
          from #ibutes

     ) x
        unpivot
        (
          val
          for col in ('+ @colsunpivot +')
        ) u
      ) x1
      pivot
      (
        max(val)
        for new_col in
          ('+ @colspivot +')
      ) p'

exec(@query)    

运行查询的结果

在我的本地/ DEV机上

========================

select *
      from
      (
        select ProductID,
            col + cast(rn as varchar(10)) new_col,
            val
        from 
        (
          select   
       Cast (PAID as NVarchar(3072)) PAID
       ,Cast (ProductID as NVarchar(3072)) ProductID
           ,Cast (Label  as NVarchar(3072)) Label
           ,Cast (Val as NVarchar(3072)) Val
           ,Cast (unit as NVarchar(3072))  unit  
            ,row_number() over(partition by ProductID order by ProductID) rn
          from #ibutes
     ) x
        unpivot
        (
          val
          for col in ([Label],[unit],[Val],[PAID])
        ) u
      ) x1
      pivot
      (
        max(val)
        for new_col in
          ([Label1],[unit1],[Val1],[PAID1],[Label2],[unit2],[Val2],[PAID2],[Label3],[unit3],[Val3],[PAID3],[Label4],[unit4],[Val4],[PAID4],[Label5],[unit5],[Val5],[PAID5],[Label6],[unit6],[Val6],[PAID6],[Label7],[unit7],[Val7],[PAID7],[Label8],[unit8],[Val8],[PAID8],[Label9],[unit9],[Val9],[PAID9],[Label10],[unit10],[Val10],[PAID10],[Label11],[unit11],[Val11],[PAID11],[Label12],[unit12],[Val12],[PAID12],[Label13],[unit13],[Val13],[PAID13],[Label14],[unit14],[Val14],[PAID14],[Label15],[unit15],[Val15],[PAID15],[Label16],[unit16],[Val16],[PAID16],[Label17],[unit17],[Val17],[PAID17],[Label18],[unit18],[Val18],[PAID18],[Label19],[unit19],[Val19],[PAID19],[Label20],[unit20],[Val20],[PAID20],[Label21],[unit21],[Val21],[PAID21])
      ) p 

关于生产机器,尽管它不同。请注意

顺序的变化

select *
      from
      (
        select ProductID,
            col + cast(rn as varchar(10)) new_col,
            val
        from 
        (
          select   
       Cast (PAID as NVarchar(3072)) PAID
       ,Cast (ProductID as NVarchar(3072)) ProductID
           ,Cast (Label  as NVarchar(3072)) Label
           ,Cast (Val as NVarchar(3072)) Val
           ,Cast (Unit as NVarchar(3072))  Unit  
            ,row_number() over(partition by ProductID order by ProductID) rn
          from #ibutes
     ) x
        unpivot
        (
          val
          for col in ([PAID],[Label],[Val],[Unit])
        ) u
      ) x1
      pivot
      (
        max(val)
        for new_col in
          ([PAID1],[Label1],[Val1],[Unit1],[PAID2],[Label2],[Val2],[Unit2],[PAID3],[Label3],[Val3],[Unit3],[PAID4],[Label4],[Val4],[Unit4],[PAID5],[Label5],[Val5],[Unit5],[PAID6],[Label6],[Val6],[Unit6],[PAID7],[Label7],[Val7],[Unit7],[PAID8],[Label8],[Val8],[Unit8],[PAID9],[Label9],[Val9],[Unit9],[PAID10],[Label10],[Val10],[Unit10],[PAID11],[Label11],[Val11],[Unit11],[PAID12],[Label12],[Val12],[Unit12],[PAID13],[Label13],[Val13],[Unit13],[PAID14],[Label14],[Val14],[Unit14],[PAID15],[Label15],[Val15],[Unit15],[PAID16],[Label16],[Val16],[Unit16],[PAID17],[Label17],[Val17],[Unit17],[PAID18],[Label18],[Val18],[Unit18],[PAID19],[Label19],[Val19],[Unit19],[PAID20],[Label20],[Val20],[Unit20],[PAID21],[Label21],[Val21],[Unit21])
      ) p

请注意btw本地机器的差异,其中订单似乎是按字母顺序排列的

[Label1的],[1单元],[VAL1],[PAID1],[Label2的],[UNIT2]。  。 。 。

在生产机器上,它不是

[PAID1],[Label1],[Val1],[Unit1],[PAID2],[Label2],[Val2],[Unit2],.. 。

7 个答案:

答案 0 :(得分:1)

我认为只有一个明显的答案。在动态查询中使用order by子句。

答案 1 :(得分:1)

简单地说,无论是否动态的所有查询都不能保证在不同的机器上出现相同的问题! 如果结果的顺序对您很重要,请使用ORDER BY

例如:

SELECT *
FROM TBL
ORDER BY FIRSTNAME

答案 2 :(得分:1)

如果您需要订单,请使用订单。
如果没有订单,则没有保证订单 如果有平局,则无法保证在平局上重复排序。
使用足够的列没有平局。

看来你指的是列的顺序而不是行。

如果您选择*,您将按表中定义的顺序排列 如果您需要控制列的顺序,请不要使用*。

select table1.col4, table1.col2 
from table1

答案 3 :(得分:0)

可能你可以试试这个

'select *
  from
  (
    select ProductID,
        col + cast(rn as varchar(10)) new_col,
        val
    from 
    (
      select top 100 percent
       Cast (PAID as NVarchar(3072)) PAID
       ,Cast (ProductID as NVarchar(3072)) ProductID
       ,Cast (Label  as NVarchar(3072)) Label
       ,Cast (Val as NVarchar(3072)) Val
       ,Cast (unit as NVarchar(3072))  unit  
        ,row_number() over(partition by ProductID order by ProductID) rn
      from #ibutes
      order by row_number() over(partition by ProductID order by ProductID) asc
 ) x
    unpivot
    (
      val
      for col in ('+ @colsunpivot +')
    ) u
  ) x1
  pivot
  (
    max(val)
    for new_col in
      ('+ @colspivot +')
  ) p'

答案 4 :(得分:0)

既然我们知道你在哪里添加ORDER BY,答案就更清楚了。 您正在尝试对其结果插入@colsPivot的查询进行排序,这就是问题所在。

ORDER BY主要用于排序最终结果,因此应该在最终查询(动态查询)上 例外情况是它是否用作“限制”查询的一部分(例如TOP 10)。

尝试将ORDER BY添加到动态查询中,并告诉我们它是否有效。

答案 5 :(得分:0)

为什么不改变以下内容:

set @query = 'select *
      from

类似

set @query = 'select *
      into #x
      from

你需要在动态sql之前明确创建#x,即

create table #x
(
blah int,
blah char(8)
)

然后在exec语句后再进行查询

select *
from #x
order by whatever 

答案 6 :(得分:0)

您可以尝试以下方法吗?

按以下方式将订单添加到第一个查询

select @colsUnpivot = stuff((select ','+quotename(C.name)
     from tempdb.sys.columns as C  
     where C.object_id = object_id('tempdb..#ibutes')  AND  C.name Not in ('ProductID')

ORDER BY c.column_id --Add this

     for xml path('')), 1, 1, '')

更改第二个查询的下面的顺序

select @colsPivot = STUFF((SELECT  ','  + quotename(c.name   + cast(t.rn as varchar(10)))
                from
                (
                  select row_number() over(partition by ProductID   order by ProductID) rn  from #ibutes
                ) t
                 cross apply 
                  tempdb.sys.columns  as C
               where C.object_id = object_id('tempdb..#ibutes')   AND  C.name Not in ('ProductID')
               group by c.name, t.rn

               ORDER BY c.column_id --Change this

        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')

希望有帮助...