简体   繁体   English

SQL:限制在SQL Server中可以查询的行数

[英]SQL: Limit the number of row can be queried in SQL Server

I would like to force limit the number of records being queried from the SQL Server in a way that I can report back the to user that they need to optimize their query. 我想以一种可以限制向SQL Server查询的记录数的方式来向用户报告他们需要优化查询的方式。

Intending to use it a reporting tool where let's say the user is not supposed to extract more than 10,000 records. 打算使用它作为报告工具,假设用户提取的记录不超过10,000条。

SET ROWCOUNT 10000 [THROW EXCEPTION IF MORE IS SELECTED]
//user's query
SELECT ....

Is this possible to do? 这可能吗?

您可以做的是重写SQL,以将TOP 10000添加到工具生成的任何SQL查询中。

I think you are asking if you can set something global that would cause an error if the result set contained more than a certain number of records. 我想您是在问,如果结果集包含的记录数量超过一定数量,是否可以设置全局变量,否则会导致错误。

I also think the answer to that is, "No." 我也认为答案是“不”。

However, depending on how you are constructing and executing the queries you could possible prepend SET ROWCOUNT 10001 -- note the 1 to prevent the runaway queries you want to avoid. 但是,根据您构造和执行查询的方式,可以在SET ROWCOUNT 10001之前添加前缀-注意1以防止要避免的失控查询。

Then append something like @Felipe suggested: 然后附加类似@Felipe的建议:

If @@ROWCOUNT = 10001 RAISERROR ('Too many results. Please, optimize your query', 1, 1); 如果@@ ROWCOUNT = 10001 RAISERROR(“结果太多。请优化您的查询”,1、1);

If you are running all queries through some sort of central processor that would be fairly easy. 如果您正在通过某种中央处理器运行所有查询,那将相当容易。

EDIT: 编辑:

This should demo the idea in SSMS: 这应该演示SSMS中的想法:

SET ROWCOUNT 2
SELECT 1 UNION SELECT 2
If @@ROWCOUNT = 2 RAISERROR ('Too many results. Please, optimize your query', 1, 1)

If you are not getting an error then it is being masked by something in you code. 如果没有收到错误,则说明该错误被代码中的某些内容掩盖了。

In your application you can create a variable that will be populated by the users say @Nrow if they select any value less than 1000 then select their value otherwise just change the value in your code to select TOP 1000 values, something like this.. 在您的应用程序中,您可以创建一个变量,该变量将由用户说@Nrow填充,如果他们选择的值小于1000,则选择其值,否则只需更改代码中的值以选择TOP 1000值即可,如下所示。

DECLARE @Nrow INT = 1000;               --<-- Users Value

SET @Nrow = CASE WHEN @Nrow > 1000      --<-- Your check
                 THEN 1000 
            ELSE @Nrow END

SELECT TOP (@Nrow) *                    --<-- Query
FROM dbo.TableName

I'm not sure I understand your question. 我不确定我是否理解您的问题。 If the user will simply provide the number of rows he wants, then John Nolan's answer is enough. 如果用户仅提供所需的行数,则John Nolan的答案就足够了。 But, if your client will provide his own query, then maybe @@ROWCOUNT will help you: 但是,如果您的客户提供自己的查询,那么@@ ROWCOUNT可能会帮助您:

*Your client's query goes here *您客户的查询在这里

If @@ROWCOUNT > 10000
    BEGIN
    RAISERROR ('Please, optimize your query', 1, 1);
    END

No, actually it isn't. 不,实际上不是。 All solutions with TOP and ROWCOUNT will simply limit the output after a query is already done executing, which I believe was what you wanted to avoid in the first place. 使用TOP和ROWCOUNT的所有解决方案都将仅在查询执行完成后限制输出,我相信这是您首先要避免的。

What you can is ask SQL Server to just produce an execution plan, and then check the cardinality estimates. 您可以要求SQL Server只是生成一个执行计划,然后检查基数估计。 However, keep in mind that estimates are just that, the estimates, and could be off. 但是,请记住,估算值仅仅是估算值,并且可能会超出估算值。

This uses dynamic SQL, so I don't know if that's a problem. 它使用动态SQL,所以我不知道这是不是一个问题。 It is set up to stop counting rows if the maximum is exceeded. 如果超过最大值,则设置为停止对行进行计数。 Also, I created a demo table. 另外,我创建了一个演示表。

--Create a table for test data (modeled after the Northwind Employees table).
CREATE TABLE EMPLOYEES
(
    EMPLOYEE_ID INT NOT NULL,
    LASTNAME VARCHAR(20) NOT NULL,
    FIRSTNAME VARCHAR(10) NOT NULL,
    TITLE VARCHAR(30),
    TITLE_OF_COURTESY VARCHAR(25),
    BIRTHDATE DATE,
    HIREDATE DATE,
    ADDRESS VARCHAR(60),
    CITY VARCHAR(15),
    REGION VARCHAR(15),
    POSTAL_CODE VARCHAR(10),
    COUNTRY VARCHAR(15),
    HOME_PHONE VARCHAR(24),
    EXTENSION VARCHAR(4),
    PHOTO VARCHAR(255),
    NOTES VARCHAR(2000),
    REPORTS_TO INT,
    CONSTRAINT PK_EMPLOYEES PRIMARY KEY (EMPLOYEE_ID)
);
GO
--end Create a table for test data (modeled after the Northwind Employees table).

--Insert some data
DECLARE @INSERT_DATA_ROW_COUNTER INT
SET @INSERT_DATA_ROW_COUNTER=0
SET NOCOUNT ON
WHILE @INSERT_DATA_ROW_COUNTER<1500
BEGIN
    INSERT INTO EMPLOYEES 
    (EMPLOYEE_ID, 
    LASTNAME,
    FIRSTNAME,
    TITLE,
    TITLE_OF_COURTESY,
    BIRTHDATE,
    HIREDATE,
    ADDRESS,
    CITY,
    REGION,
    POSTAL_CODE,
    COUNTRY,
    HOME_PHONE,
    EXTENSION,
    PHOTO,
    NOTES,
    REPORTS_TO)
    VALUES 
    (@INSERT_DATA_ROW_COUNTER + 1,
    'LAST' + CONVERT(VARCHAR(32), @INSERT_DATA_ROW_COUNTER + 1),
    'FIRST' + CONVERT(VARCHAR(32), @INSERT_DATA_ROW_COUNTER + 1),
    'TITLE' + CONVERT(VARCHAR(32), @INSERT_DATA_ROW_COUNTER + 1),
    'TITLE_OF_COURTESY' + CONVERT(VARCHAR(32), @INSERT_DATA_ROW_COUNTER + 1),
    DATEADD(YEAR, -25, GETDATE()),
    DATEADD(YEAR, -21, GETDATE()),
    'ADDRESS' + CONVERT(VARCHAR(32), @INSERT_DATA_ROW_COUNTER + 1),
    'CITY' + CONVERT(VARCHAR(32), @INSERT_DATA_ROW_COUNTER + 1),
    'REGION' + CONVERT(VARCHAR(32), @INSERT_DATA_ROW_COUNTER + 1),
    @INSERT_DATA_ROW_COUNTER + 100001,
    'COUNTRY' + CONVERT(VARCHAR(32), @INSERT_DATA_ROW_COUNTER + 1),
    CONVERT(VARCHAR(32), @INSERT_DATA_ROW_COUNTER + 5551230001),
    0,
    'PHOTO' + CONVERT(VARCHAR(32), @INSERT_DATA_ROW_COUNTER + 1),
    'NOTES' + CONVERT(VARCHAR(32), @INSERT_DATA_ROW_COUNTER + 1),
    1)
    SET @INSERT_DATA_ROW_COUNTER=@INSERT_DATA_ROW_COUNTER+1
END
SET NOCOUNT OFF
--end Insert some data

--This is your WHERE CLAUSE for the count and for the data retrieval
DECLARE @WHERE_CLAUSE VARCHAR(MAX)
SET @WHERE_CLAUSE='LASTNAME LIKE ''%0%'''

--This is the maximum number of rows that you would like to allow
DECLARE @MAX_ROW_COUNT int
SET @MAX_ROW_COUNT=400

DECLARE @COUNTROWS int
SET @COUNTROWS=-1
DECLARE @COUNT_SQL NVARCHAR(MAX)
SET @COUNT_SQL='select @COUNTROWS=count(*) from EMPLOYEES WHERE EMPLOYEE_ID IN (SELECT TOP ' + CONVERT(VARCHAR(64), @MAX_ROW_COUNT + 1) + ' EMPLOYEE_ID FROM EMPLOYEES WHERE ' + @WHERE_CLAUSE +')'
exec sp_executesql @COUNT_SQL, N'@COUNTROWS int output', @COUNTROWS output;
IF @COUNTROWS <= @MAX_ROW_COUNT
BEGIN
    DECLARE @SQL VARCHAR(MAX)
    SET @SQL='SELECT * FROM EMPLOYEES WHERE ' + @WHERE_CLAUSE
    EXEC (@SQL)
END
ELSE
BEGIN
    DECLARE @msg VARCHAR(255)
    SET @msg='The limit for this query is ' + CONVERT(VARCHAR(32), @MAX_ROW_COUNT) + ' rows. Change your query as required.'
    RAISERROR (@msg, 1, 1)
END
DROP TABLE EMPLOYEES
GO

select column_name from table_name limit no_of_rows; 从表名限制中选择列名。

it works in MySQL.....not sure about SQL server. 它在MySQL中工作.....不确定SQL Server。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM