【问题标题】:How to limit rows in the table ? How to insert row on the top? SQL Server如何限制表中的行数?如何在顶部插入行? SQL 服务器
【发布时间】:2021-02-21 23:38:34
【问题描述】:

首先 - 我想限制我在数据库中插入的行。 IE。我想在我的表中最多有 100 行(我不想有版本计数(*),如果 >100,删除...)

次要的 - 我想要将(插入时)推入表格之类的东西。即:

ID |  Name    |      City
 0 |   Mike   |    New York


ID |  Name    |      City
1  |   David  |      Pekin   -> as insert on the top!
0  |   Mike   |    New York


ID |  Name    |      City
2  |   Marcus |     Warsaw  -> as next
1  |   David  |      Pekin   
0  |   Mike   |    New York

最好的问候 大卫

【问题讨论】:

  • 表格没有顶部和底部,数据的显示顺序基于您SELECT中的ORDER BY
  • 我想要..我不想要...?? SO 不是“想要的网站”..
  • "如何在顶部插入行?SQL Server",Sql Server 不能这样工作。 “如何限制表格中的行数”,可以在会破坏您的性能的解决方法中完成,因此它不是可取的。再考虑一下您的要求。
  • 开箱即用无法限制行数。您将需要自己实现行排序和清除的逻辑;然后您可以使用INSERT trigger 自动运行它。
  • @MarekGrzenkowicz 你可能会觉得this answer 很有趣,它可以通过索引视图巧妙地完成

标签: sql sql-server


【解决方案1】:

您的两个条件都可以用于 100 行表。或者,甚至是 1,000 行的表。但是,下面的示例不是生产表的推荐操作。

RE:“最多有 100 行” 创建表,然后添加一个 INSTEAD OF INSERT 触发器,在允许插入之前检查表的大小。

RE:“类似于将(插入时)推入表中。” 使用聚集主键(推荐)创建表,但使用 DESC 键(不推荐用于除了小的、很少使用的表之外的任何东西)。 CLUSTERED 索引是物理排序的。因此,添加下一个更大的数字(如在 IDENTITY 序列中)会将新条目推到索引的顶部。 SELECT 将按磁盘顺序返回行。对于具有聚集索引的 100 行表而言,磁盘顺序和索引顺序是相同的。

代码:
注意:下面的代码将 max_size 限制为 3 以进行演示。为您的示例设置 @max_size = 100

-->-- create table with descending order for primary key.  will act like a push down stack
IF OBJECT_ID('dbo.so_limit_size') IS NOT NULL DROP TABLE dbo.so_limit_size
CREATE TABLE dbo.so_limit_size ( 
    id TINYINT IDENTITY(1,1)
    , name VARCHAR(100) 
    , city VARCHAR(100)
    , CONSTRAINT pk_so_limit_size PRIMARY KEY CLUSTERED (id DESC) -- DESC makes it work like a push down stack
    )

INSERT INTO dbo.so_limit_size (name, city)
VALUES
( 'Mike', 'New York City' )
, ( 'David', 'Pekin' )
, ( 'Marcus', 'Warsaw' )


SELECT * FROM dbo.so_limit_size  -- 3 rows

GO
CREATE TRIGGER dbo.limit_size ON dbo.so_limit_size
INSTEAD OF INSERT AS
    SET NOCOUNT ON
    -- purpose:  limit size of table to @max_size.  insert batch of 1 or more that exceeds @max_size will not be allowed

    DECLARE @max_size TINYINT = 3  -- size limit of table

    DECLARE @existing_count TINYINT = (SELECT COUNT(*) FROM dbo.so_limit_size)
        , @insert_count TINYINT = (SELECT COUNT(*) FROM Inserted )
    PRINT 'existing_count = ' + LOWER(@existing_count) + ' new insert count = ' + LOWER(@insert_count)

    IF @existing_count + @insert_count >= 3
    BEGIN
        PRINT 'insert will cause table count to exceed max_size.  insert aborted.  max_size = ' + LOWER(@max_size) 
    END     
    ELSE
    BEGIN
        PRINT 'table count less than max_size.  insert allowed.  max_size = ' + LOWER(@max_size)  --<<-- demonstration, print is not a recommended practice for a trigger
        INSERT INTO dbo.so_limit_size (name, city)
        SELECT name, city FROM inserted
    END
GO
INSERT INTO dbo.so_limit_size (name, city)
VALUES
( 'Zorba', 'Athens' ) -- will not be allowed if @max_size = 3


SELECT * FROM dbo.so_limit_size

【讨论】:

  • 阻止插入的触发器阻止添加新记录。我对 OP 要求的解释是,新记录应该推出最旧的记录
  • @Hans Kesting。这是一个有效的解释。问题只是将数字限制为 100。并且,问题的进一步状态不是“计数(*),如果 >100,则删除。”我将其解释为在 100 处停止。触发器在插入之前检查以确定它是否是一个有效的插入。如果不是有效的插入,则插入被阻止 - 不被删除。但是,可以修改答案中的触发器以删除最旧的行并插入最新的行(如果这是所需的行为)。该方法适用于任何一种情况。
【解决方案2】:

@Hans Kesting 指出,他对 100 行限制的解释“应该推出最旧的”。这是一个有效的解释。所以,我创建了一个答案。以下与我之前的答案相同,只是触发器现在删除插入之前最旧的行。表最大大小保持不变。有关使用降序键而不是触发器的聚集索引的解释,请参阅我的其他答案。

代码:

-->-- create table with descending order for primary key.  will act like a push down stack
IF OBJECT_ID('dbo.so_limit_size') IS NOT NULL DROP TABLE dbo.so_limit_size
CREATE TABLE dbo.so_limit_size ( 
    id TINYINT IDENTITY(1,1)
    , name VARCHAR(100) 
    , city VARCHAR(100)
    , CONSTRAINT pk_so_limit_size PRIMARY KEY CLUSTERED (id DESC) -- DESC makes it work like a push down stack
    )

INSERT INTO dbo.so_limit_size (name, city)
VALUES
( 'Mike', 'New York City' )
, ( 'David', 'Pekin' )
, ( 'Marcus', 'Warsaw' )


SELECT * FROM dbo.so_limit_size  -- 3 rows

GO
CREATE TRIGGER dbo.limit_size ON dbo.so_limit_size
INSTEAD OF INSERT AS
    SET NOCOUNT ON
    -- purpose:  limit size of table to @max_size.  insert batch of 1 or more that exceeds @max_size will not be allowed

    DECLARE @max_size TINYINT = 3  -- size limit of table

    DECLARE @existing_count TINYINT = (SELECT COUNT(*) FROM dbo.so_limit_size)
        , @insert_count TINYINT = (SELECT COUNT(*) FROM Inserted )
    PRINT 'existing_count = ' + LOWER(@existing_count) + ' new insert count = ' + LOWER(@insert_count)

    IF @existing_count + @insert_count >= 3
    BEGIN
        -- for FIFO stack, delete oldest rows before insert if @max_size exceeded
        PRINT 'insert will cause table count to exceed max_size.  oldest row(s) deleted before insert.  max_size = ' + LOWER(@max_size) 
        DELETE FROM dbo.so_limit_size
        WHERE Id IN ( SELECT TOP (@insert_count) Id FROM dbo.so_limit_size ORDER BY Id ASC )
        
        INSERT INTO dbo.so_limit_size (name, city)
        SELECT name, city FROM inserted

    END     
    ELSE
    BEGIN
        PRINT 'table count less than max_size.  insert allowed.  max_size = ' + LOWER(@max_size)  --<<-- demonstration, print is not a recommended practice for a trigger
        INSERT INTO dbo.so_limit_size (name, city)
        SELECT name, city FROM inserted
    END
GO
INSERT INTO dbo.so_limit_size (name, city)
VALUES
( 'Zorba', 'Athens' ) -- will not be allowed if @max_size = 3
, ('Sriram', 'Chennai')


SELECT * FROM dbo.so_limit_size

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多