存储过程失败,违反 PRIMARY KEY 约束

Stored Procedure fails, Violation of PRIMARY KEY constraint

我真的不太了解 SP 或 TSQL 来解决这个问题,希望这里有人可以提供帮助。我们有一个存储过程,可以通过一些插入等获取一些统计信息,但由于 "Violation of PRIMARY KEY constraint" 而失败。这是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

能否分享 table 对 api_kpi_value 的定义?根据您的错误,主键重复,因此失败。

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

 -- 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;

这里的问题是我是个白痴。这项工作实际上 运行 很好,但问题是如果工作失败,它正在执行 "retry" 并且第二次尝试 运行 它显示此错误消息,因为它已经 运行 一次。第一条错误消息是 "Null value is eliminated by an aggregate or other SET operation",我刚刚添加了 ansi_warnings,所以现在工作应该 运行 没问题。感谢您帮助@dataconsumer