【问题标题】:Stored Procedure fails, Violation of PRIMARY KEY constraint存储过程失败,违反 PRIMARY KEY 约束
【发布时间】:2019-11-21 09:22:52
【问题描述】:

我真的没有太多关于 SP 或 TSQL 的知识来解决这个问题,并希望这里有人可以提供帮助。我们有一个存储过程,它通过一些插入等获取一些统计信息,但由于“违反主键约束”而失败。这是SP:

SET ANSI_WARNINGS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[CalculateKPIs]
AS

  DECLARE @MaxRequests DECIMAL(19,2),
          @RequestDateTime DATETIME,
          @MaxRequestsBySecond CURSOR,
          @MaxRequestsByMinute CURSOR,
          @MaxRequestsByHour CURSOR,
          @MaxRequestsByDay CURSOR;

  -- Max requests per second
    SET @MaxRequestsBySecond = CURSOR READ_ONLY FOR
          SELECT TOP 1 SUM(request_count) AS requests, request_datetime
          FROM api_traffic_summary, api_kpi_value
          WHERE request_datetime > kpi_date AND kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Second'
          GROUP BY request_datetime
          HAVING SUM(request_count) > (SELECT kpi_value FROM api_kpi_value WHERE kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Second')
          ORDER BY 1 DESC;

  -- Max requests per minute
    SET @MaxRequestsByMinute = CURSOR READ_ONLY FOR
          SELECT TOP 1 SUM(request_count) AS requests, CONVERT(VARCHAR(16), request_datetime, 20)
          FROM api_traffic_summary, api_kpi_value
          WHERE request_datetime > kpi_date AND kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Minute'
          GROUP BY CONVERT(VARCHAR(16), request_datetime, 20)
          HAVING SUM(request_count) > (SELECT kpi_value FROM api_kpi_value WHERE kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Minute')
          ORDER BY 1 DESC;

  -- Max requests per hour
    SET @MaxRequestsByHour = CURSOR READ_ONLY FOR
          SELECT TOP 1 SUM(request_count) AS requests, CONVERT(VARCHAR(13), request_datetime, 20) + ':00'
          FROM api_traffic_summary, api_kpi_value
          WHERE request_datetime > kpi_date AND kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Hour'
          GROUP BY CONVERT(VARCHAR(13), request_datetime, 20)
          HAVING SUM(request_count) > (SELECT kpi_value FROM api_kpi_value WHERE kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Hour')
          ORDER BY 1 DESC;

  -- Max requests per day
    SET @MaxRequestsByDay = CURSOR READ_ONLY FOR
          SELECT TOP 1 SUM(request_count) AS requests, CONVERT(VARCHAR(10), request_datetime, 20) + ' 00:00:00'
          FROM api_traffic_summary, api_kpi_value
          WHERE request_datetime > kpi_date AND kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Day'
          GROUP BY CONVERT(VARCHAR(10), request_datetime, 20)
          HAVING SUM(request_count) > (SELECT kpi_value FROM api_kpi_value WHERE kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Day')
          ORDER BY 1 DESC;

  -- Get the number of developers
  INSERT INTO api_kpi_value 
  SELECT 'Usage', 'Developers', COUNT(1), 'Now', CONVERT(VARCHAR(10), DATEADD(DAY,-1, GETDATE()), 20) + ' 00:00:00'
  FROM api_subscriber_view;

  -- Get the number of all applications
  INSERT INTO api_kpi_value
  SELECT 'Usage', 'Applications', COUNT(1), 'All', CONVERT(VARCHAR(10), DATEADD(DAY,-1, GETDATE()), 20) + ' 00:00:00'
  FROM api_application_view;

  -- Get the number of active applications
  INSERT INTO api_kpi_value
  SELECT 'Usage', 'Applications', COUNT(DISTINCT application_name), 'Active', CONVERT(VARCHAR(10), DATEADD(DAY,-1, GETDATE()), 20) + ' 00:00:00' 
  FROM api_traffic_summary 
  WHERE request_datetime BETWEEN CONVERT(VARCHAR(10), DATEADD(DAY,-1, GETDATE()), 20) AND CONVERT(VARCHAR(10), GETDATE(), 20);

  -- Get the number of API's 
  INSERT INTO api_kpi_value
  SELECT 'Usage', 'APIs', COUNT(1), 'Now', CONVERT(VARCHAR(10), DATEADD(DAY,-1, GETDATE()), 20) + ' 00:00:00'
  FROM api_view;

  -- Get subscribers by API
  INSERT INTO api_kpi_value
  SELECT 'Subscribers', api_name + ':' + api_version, COUNT(1), 'Now', CONVERT(VARCHAR(10), DATEADD(DAY,-1, GETDATE()), 20) + ' 00:00:00'
  FROM api_subscription_view
  GROUP BY api_name, api_version;

  -- Update max requests per second
  OPEN @MaxRequestsBySecond;
  FETCH NEXT FROM @MaxRequestsBySecond
  INTO @MaxRequests, @RequestDateTime;

  IF @@FETCH_STATUS = 0
    UPDATE api_kpi_value
    SET kpi_value = @MaxRequests, kpi_date = @RequestDateTime
    WHERE kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Second';

  CLOSE @MaxRequestsBySecond;
  DEALLOCATE @MaxRequestsBySecond;

  -- Update max requests per minute
  OPEN @MaxRequestsByMinute;
  FETCH NEXT FROM @MaxRequestsByMinute
  INTO @MaxRequests, @RequestDateTime;

  IF @@FETCH_STATUS = 0
    UPDATE api_kpi_value
    SET kpi_value = @MaxRequests, kpi_date = @RequestDateTime
    WHERE kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Minute';

  CLOSE @MaxRequestsByMinute;
  DEALLOCATE @MaxRequestsByMinute;

  -- Update max requests per hour
  OPEN @MaxRequestsByHour;
  FETCH NEXT FROM @MaxRequestsByHour
  INTO @MaxRequests, @RequestDateTime;

  IF @@FETCH_STATUS = 0
    UPDATE api_kpi_value
    SET kpi_value = @MaxRequests, kpi_date = @RequestDateTime
    WHERE kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Hour';

  CLOSE @MaxRequestsByHour;
  DEALLOCATE @MaxRequestsByHour;

  -- Update max requests per day
  OPEN @MaxRequestsByDay;
  FETCH NEXT FROM @MaxRequestsByDay
  INTO @MaxRequests, @RequestDateTime;

  IF @@FETCH_STATUS = 0
    UPDATE api_kpi_value
    SET kpi_value = @MaxRequests, kpi_date = @RequestDateTime
    WHERE kpi_group = 'Requests' AND kpi_name  = 'Max' AND kpi_period =  'Day';

  CLOSE @MaxRequestsByDay;
  DEALLOCATE @MaxRequestsByDay;

我收到的错误是:

Violation of PRIMARY KEY constraint 'PK__API_KPI___348637B32645B050'. Cannot insert duplicate key in object 'dbo.API_KPI_VALUE'. 
The duplicate key value is (Usage, Developers, Now, Nov 20 2019 12:00AM). [SQLSTATE 23000] (Error 2627)  The statement has been terminated. [SQLSTATE 01000] (Error 3621).  
NOTE: The step was retried the requested number of times (1) without succeeding.  The step failed.

我知道错误消息准确地指出了问题所在,但我真的不明白为什么它一直失败。此数据库位于 SQL 2008 R2 上

【问题讨论】:

    标签: sql-server sql-server-2008 stored-procedures


    【解决方案1】:

    请您分享 api_kpi_value 的表定义吗?根据您的错误,主键重复,因此失败。

    您可以尝试分别运行这 2 个语句并检查哪个插入失败。

     -- Get the number of developers
      INSERT INTO api_kpi_value 
      SELECT 'Usage', 'Developers', COUNT(1), 'Now', CONVERT(VARCHAR(10), DATEADD(DAY,-1, GETDATE()), 20) + ' 00:00:00'
      FROM api_subscriber_view;
    
    
      -- Get the number of API's 
      INSERT INTO api_kpi_value
      SELECT 'Usage', 'APIs', COUNT(1), 'Now', CONVERT(VARCHAR(10), DATEADD(DAY,-1, GETDATE()), 20) + ' 00:00:00'
      FROM api_view;
    

    【讨论】:

    • SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[API_KPI_VALUE]( [kpi_group] [varchar](30) NOT NULL, [kpi_name] [varchar](100) NOT NULL, [kpi_value] [decimal](19, 2) NOT NULL, [kpi_period] [varchar](100) NOT NULL, [kpi_date] [datetime] NOT NULL, PRIMARY KEY CLUSTERED ([kpi_group] ASC, [kpi_name] ASC, [ kpi_period] ASC, [kpi_date] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO 我实际上在两个语句中都得到相同的错误
    • OK,所以主键值的组合 - PRIMARY KEY CLUSTERED ( [kpi_group] ASC, [kpi_name] ASC, [kpi_period] ASC, [kpi_date] ASC ) 是重复的。重复键值为 (Usage, Developers, Now, Nov 20 2019 12:00AM)。如果你需要时间戳,你可以用 select 'Usage', 'Developers', COUNT(1), 'Now', CONVERT(VARCHAR, DATEADD(DAY,-1, GETDATE()), 9) 替换插入中的选择跨度>
    【解决方案2】:

    这里的问题是我是个白痴。该作业实际上运行良好,但问题是如果作业失败,它正在“重试”,并且第二次尝试运行它会显示此错误消息,因为它已经运行了一次。第一个错误消息是“空值被聚合或其他 SET 操作消除”,我刚刚添加了 ansi_warnings off 所以现在作业应该可以正常运行。感谢您帮助@dataconsumer

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多