以编程方式从常规查询生成Microsoft SQL Server的前n个查询

时间:2012-01-03 21:41:32

标签: sql-server

我有一个程序可以生成一些标准SQL,例如SELECT * FROM TEST ORDER BY X 并将它(作为一个字符串)传递给一个函数以及一个整数来创建一个有限的查询(也是一个字符串)。对于Oracle(针对该应用程序开发),此函数返回SELECT * FROM ( sq ) WHERE ROWNUM <= n给出:

SELECT * FROM (SELECT * FROM TEST ORDER BY X) WHERE ROWNUM <= 10

有效。

不幸的是,我无法弄清楚如何编写Microsoft SQL Server的等效函数(我不是MS SQL专家)。

我试过了:

SELECT TOP 10 FROM (SELECT * FROM TEST ORDER BY X)

但这导致:

Error: Incorrect syntax near the keyword 'from'.

然后我尝试了:

SELECT TOP 10 * FROM (SELECT * FROM TEST ORDER BY X)

让我获得了:

Error: The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.

这令人沮丧,因为我指的是TOP ....

我尝试了一些其他的霰弹枪变种,包括:

SELECT TOP (10) * FROM (SELECT * FROM TEST ORDER BY X)
SELECT TOP 10 * FROM (SELECT * FROM TEST ORDER BY X) SUBQUERY
SELECT TOP 10 * FROM (SELECT * FROM TEST ORDER BY X) AS SUBQUERY
SELECT * FROM (SELECT * FROM TEST ORDER BY X) WHERE ROW_NUMBER <= 10

但当然,它们都不起作用。

根本没有希望吗?

6 个答案:

答案 0 :(得分:4)

使用SET ROWCOUNT。这使得工作变得非常简单。

SET ROWCOUNT 10

SELECT * FROM [TEST] ORDER BY [X]

SET ROWCOUNT 0

答案 1 :(得分:2)

您可以在此处正确使用CTE(公用表格式)和排名函数。

; WITH CTE_RowNumbers AS 
(
    SELECT *, RANK() OVER (ORDER BY X) AS ROWNUM FROM Users
)
SELECT * FROM CTE_RowNumbers WHERE ROWNUM < 10;

只需用变量替换10。

这将在MS SQL中提供与从Oracle中的ROWNUM函数获得的结果完全相同的结果。

请注意:此代码段中的ROWNUM只是一个别名,而不是MSSQL中的函数,真正的功能在于使用公共表表达式和使用的排名函数。

更新:蒙面CTE - 用变量替换[VAR-Name]

 ; WITH CTE_RowNumbers AS 
    (
        SELECT [VAR-ColumnList], RANK() OVER (ORDER BY [VAR-OrderByList]) AS ROWNUM FROM [VAR-Table]
    )
    SELECT [VAR-ColumnList] FROM CTE_RowNumbers WHERE ROWNUM < [VAR-ResultSize];

从查询中提取输入变量:

SELECT [VAR-ColumnList] FROM [VAR-Table] ORDER BY [VAR-OrderByList]

您还需要为[VAR-ResultSize]指定一个值,它的外观是不变的并且在您的函数中设置了?

注意:如果您需要在订单中添加DESC或ASC,可以提供更大的灵活性,只需扩展您的脚本并将其作为变量包含在内。

答案 2 :(得分:1)

子查询是集合,因此是无序的,因此除非您还使用ORDER BY,否则不能将它们与TOP一起使用。

如果要限制返回的行数,并且不关心它们是哪些行,则可以编辑任何内部ORDER BY(如果有的话),然后为子查询提供别名

原始查询:

SELECT * FROM TEST ORDER BY X

编辑并包装以返回10行:

SELECT TOP 10 * FROM (SELECT * FROM TEST) AS EXPR

或者您可以将TOP子句应用于子查询:

SELECT TOP 10 * FROM (SELECT TOP 10 * FROM TEST ORDER BY X) AS EXPR

不幸的是,这不能保证返回与:

相同的结果
SELECT TOP 10 * FROM TEST ORDER BY X

为此,您需要在子查询之外移动ORDER BY:

SELECT TOP 10 * FROM (SELECT * FROM TEST) AS EXPR ORDER BY X

您还可以参数化要返回的行数:

SELECT TOP (@nrows) * FROM (SELECT * FROM TEST) AS EXPR

使用SQL Server 2012,您几乎可以实现您真正追求的目标,除非在这种情况下需要ORDER BY

SELECT * FROM TEST ORDER BY X OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY

答案 3 :(得分:0)

您可以尝试临时表:

select * into #temp from test order by x
select top 10 * from #temp where ...

答案 4 :(得分:0)

我认为这就是你要找的东西(我假设是SQL Server 2005及以上版本):

SELECT * FROM 
  (SELECT *,ROW_NUMBER() OVER (ORDER BY x) rownum FROM test) tmp 
WHERE rownum BETWEEN 1 AND 10

其中'x'是要排序的列,并'测试'要从中选择的表。此外,'count'列通常也可用于返回,尤其是在您进行分页时:

SELECT * FROM 
  (SELECT *,COUNT(*) OVER() cnt,ROW_NUMBER() OVER (ORDER BY x) rownum FROM test) tmp 
WHERE rownum BETWEEN 1 AND 10

答案 5 :(得分:-1)

做一件非常简单直接的事情: - &gt;&gt;

  1. 删除order by子句和
  2. 在内部查询后使用关键字“AS”。
  3. 例如:SELECT TOP 10 * FROM(SELECT * FROM TEST)AS X