0

我正在使用 SQL Server 存储过程来生成一个数据表,我将其用作 WPF 数据网格的数据源。数据位于父 [Sample] 子 [SampleConstituent] 关系的两个表中,我正在使用 PIVOT 为子表中的数据记录生成列。该查询使用参数,以便我可以过滤返回到数据网格的记录。

我的问题是我想根据最近的记录从查询中返回一个 TOP N 结果集。我有以下存储过程,一切正常,除了数据总是首先返回最旧的记录。因此,TOP N过滤器返回最旧的记录而不是最近的记录。Sample.SampleDateTime是我希望排序的父表中的列。

我已经尝试了很多次迭代,以至于我的新手大脑都陷入了困境!

ALTER PROCEDURE [dbo].[spSampleDisplayAllParams] 
-- Add the parameters for the stored procedure here
@fromDate DATE = '2013-01-01', 
@toDate DATE = '2100-01-01',
@ProductName NVARCHAR(50) = '%',
@SampleNumber NVARCHAR(50) = '%',
@numSamples NVARCHAR(50) = 200
AS
BEGIN
SET NOCOUNT ON;

DECLARE @cols AS NVARCHAR(MAX),
@query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(ConstituentName) 
                from SampleConstituent
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')
PRINT @cols

set @query 
  = 'SELECT top (' + @numSamples + ') * from  
     (SELECT TOP 100 PERCENT  s.SampleID, s.SampleNumber, s.SampleDateTime, s.ProductName, sc.ConstituentName, sc.ConstituentValue
FROM         dbo.Sample s INNER JOIN
                  dbo.SampleConstituent sc ON s.SampleID = sc.SampleID
WHERE (s.Active = 1) AND 
(s.ProductName Like  ''' + @ProductName + ''') AND
(s.SampleNumber Like  ''' + @SampleNumber + ''') AND
(s.SampleDateTime BETWEEN ''' + CONVERT(nvarchar(24), @FromDate, 121) +''' AND'''+     CONVERT(nvarchar(24), @ToDate, 121) +''')
ORDER BY s.SampleDateTime        )     x
     pivot 
     (
        max(ConstituentValue)
        for ConstituentName in (' + @cols + ')
     ) p  '

execute(@query)
END
4

2 回答 2

3

尝试在 pivot 之后下订单:

)     x
 pivot 
 (
    max(ConstituentValue)
    for ConstituentName in (' + @cols + ')
 ) p  ORDER BY SampleDateTime        '

为了更清楚你的查询应该是这样的:

 set @query 
= 'SELECT top (' + @numSamples + ') * from  
   (SELECT s.SampleID, s.SampleNumber, s.SampleDateTime, s.ProductName, sc.ConstituentName, sc.ConstituentValue
FROM         dbo.Sample s INNER JOIN
             dbo.SampleConstituent sc ON s.SampleID = sc.SampleID
WHERE (s.Active = 1) AND 
(s.ProductName Like  ''' + @ProductName + ''') AND
(s.SampleNumber Like  ''' + @SampleNumber + ''') AND
(s.SampleDateTime BETWEEN ''' + CONVERT(nvarchar(24), @FromDate, 121) +''' AND'''+         CONVERT(nvarchar(24), @ToDate, 121) +''')
)     x
   pivot 
   (
      max(ConstituentValue)
      for ConstituentName in (' + @cols + ')
   ) p ORDER BY SampleDateTime DESC'
--sort and order is placed after the pivot
于 2013-09-06T18:33:08.483 回答
2

您的订单在 TOP 100 PERCENT 里面。在这种情况下,ORDER BY 用于指示要包含哪些行,但是由于您说您想要所有这些行,SQL Server 很聪明,并且将 TOP 和 ORDER BY 都扔掉了。看看计划,我敢打赌任何地方都没有。这个:

SELECT * FROM 
  (SELECT TOP 100 PERCENT something FROM somewhere ORDER BY something) AS x;

与以下内容完全相同

SELECT * FROM 
  (SELECT something FROM somewhere) AS x;

在这两种情况下,SQL Server 都不会被告知以任何方式对最终结果进行排序。所以它没有,而是选择最有效的排序,而不是试图读懂你的想法。

如果要排序,则需要将其放在最外层的查询中,正如@Sonam 所标识的那样。这里有一些背景信息:

仅供参考,您应该尽最大努力保护自己免受 SQL 注入并使用正确的参数化查询。同样,不要从@Sonam的答案中获取任何东西,但这会更好:

SELECT @sql = N'SELECT TOP (@numSamples) * FROM 
(
  SELECT s.SampleID, s.SampleNumber, s.SampleDateTime, 
         s.ProductName, sc.ConstituentName, sc.ConstituentValue
  FROM dbo.Sample AS s 
  INNER JOIN dbo.SampleConstituent AS sc 
  ON s.SampleID = sc.SampleID
  WHERE (s.Active = 1) AND 
  (s.ProductName LIKE @ProductName) AND
  (s.SampleNumber LIKE @SampleNumber) AND
  (s.SampleDateTime >= @FromDate AND s.SampleDateTime < DATEADD(DAY, 1, @ToDate)
) AS x
PIVOT
(
  MAX(ConstituentValue) FOR ConstituentName IN (' + @cols + ')
) AS p
ORDER BY SampleDateTime DESC;';

DECLARE @params NVARCHAR(MAX) = N'@numSamples INT, @fromDate DATE, ' +
  '@toDate DATE, @ProductName NVARCHAR(50), @SampleNumber NVARCHAR(50)';

EXEC sp_executesql @sql, @params, @numSamples, @fromDate, @toDate,
  @ProductName, @SampleNumber;

请注意,您的创建@cols可能包括未出现在您选择的日期范围内的表中的组成名称(或与 where 子句的其他部分),所以如果您不想要一堆包含NULL每个值的列选择日期,您可能还希望将其中一些条件添加到该查询中。

于 2013-09-06T18:36:55.917 回答