@@ ROWCOUNT无法按预期工作

时间:2015-11-23 10:45:30

标签: sql-server stored-procedures

我的应用程序无法正常运行。 我们发现系统错误,但供应商声称此问题无法解决。

该问题与数据库中被覆盖的数据有关。

系统每天从外部数据源收集数据。 收集的数据包含过去3天的数据记录。

SQL Insert会覆盖已插入SQL数据库的现有数据,但是存储过程无法阻止数据被覆盖吗?

表dbo.PointValue包含以下内容:

PointID DataTime    DataValue   DataValueType   DataValueStatus
32  2015-08-14 23:00:00.000 8,07    NULL    NULL

如果存在点ID和DataTime,则不应插入数据。

我认为这部分存储过程可能会导致此问题

UPDATE PointValue 
SET 
DataValue = @data_val,
DataValueType = @data_value_type,
DataValueStatus = @data_value_status
WHERE (PointID = @point_id) AND (DataTime = @data_time)

IF @@ROWCOUNT = 0

但我不是SQL和存储过程的专家。

请注意,有关如何防止数据被覆盖的任何意见都非常受欢迎。

以下完成商店程序:

USE [i96X]
GO
/****** Object:  StoredProcedure [dbo].[usp_insertLogDataXML]    Script Date: 23-11-2015 10:33:34 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO

ALTER PROCEDURE [dbo].[usp_insertLogDataXML]
@xml VARCHAR(MAX)
AS

DECLARE @iDoc INT -- A handle to the prepared XML document

-- Prepare the XML document in memory
SET NOCOUNT ON
EXECUTE sp_xml_preparedocument @iDoc OUTPUT, @xml

-- 18/02/2005 : We may find a condition where the XML document contains 2 duplicate times for
-- the same point id, this is likely to happen at the summer time -> standard time change. We
-- cannot violate the primary key constraint, so make sure we check whether a value already
-- exists for this point id and time before inserting.

--
-- 07/07/2006
-- DataValue type changed from float to varchar(10)
-- and converted back to float after replacing comma with decimal point
--

DECLARE log_data_cursor CURSOR FOR
SELECT theXML.PointID, theXML.DataTime, theXML.DataValue, theXML.DataValueType, theXML.DataValueStatus
FROM OpenXML(@iDoc, '/root/P',1) WITH
(
PointID         int     '@i',
DataTime        DATETIME    '@t',
DataValue       varchar(10) '@v',
DataValueType   int '@y',
DataValueStatus int '@s'
) theXML


DECLARE @point_id int
DECLARE @data_time DATETIME
DECLARE @data_val varchar(10)
DECLARE @data_value float

DECLARE @data_value_type int
DECLARE @data_value_status int


OPEN log_data_cursor

FETCH NEXT FROM log_data_cursor
INTO @point_id, @data_time, @data_val, @data_value_type, @data_value_status

WHILE @@FETCH_STATUS = 0
BEGIN

-- replace the , with . in @data_val
SET @data_val = REPLACE(@data_val,N',',N'.')

-- change the @data_val here to float
SET @data_value = CAST(@data_val AS float)

-- if data type and status is equal to -1, then set them to NULL
IF @data_value_type = -1
    SET @data_value_type = NULL

IF @data_value_status = -1
    SET @data_value_status = NULL

UPDATE PointValue 
SET 
DataValue = @data_val,
DataValueType = @data_value_type,
DataValueStatus = @data_value_status
WHERE (PointID = @point_id) AND (DataTime = @data_time)

IF @@ROWCOUNT = 0
BEGIN

    -- Nothing already there for this point / time so we are
    -- safe to do an insert.

    INSERT INTO PointValue (PointID, DataTime, DataValue, DataValueType, DataValueStatus)
    VALUES (@point_id, @data_time, @data_val, @data_value_type, @data_value_status)
END

FETCH NEXT FROM log_data_cursor
INTO @point_id, @data_time, @data_val, @data_value_type, @data_value_status
END

CLOSE log_data_cursor
DEALLOCATE log_data_cursor

-- Remove the XML document
EXECUTE sp_xml_removedocument @iDoc

1 个答案:

答案 0 :(得分:1)

由于UPDATE子句中的AND (DataTime = @data_time)WHERE阻止可能会失败。由于DataTime包含timestamp@data_time可能不包含时间戳,因此可能会失败。

该示例将帮助您理解:

-- Create the temporary table 
CREATE TABLE #DateTimeTest(DataTime DATETIME)
-- Inserting few entries for testing
INSERT INTO #DateTimeTest (DataTime) 
VALUES ('2015-11-23 04:55:00'), ('2015-11-23 05:00:00'), ('2016-11-24 06:00:00')
-- Declare the datetime variable
DECLARE @TestDataTime AS DATETIME = '2015-11-23';
-- Select the records for the given datetime variable
SELECT * FROM #DateTimeTest WHERE DataTime = @TestDataTime
-- Drop the temp table
DROP TABLE #DateTimeTest

即使我有SELECT * FROM #DateTimeTest WHERE DataTime = @TestDataTime的记录,2015-11-23也不会返回数据。

但是如果你添加时间段,下面的查询将返回数据:

SELECT * FROM #DateTimeTest 
WHERE DataTime BETWEEN @TestDataTime + ' 00:00:00' AND @TestDataTime + ' 23:59:59'

因此,如果您更改UPDATE块,则在您的代码中,它将起作用:

UPDATE PointValue 
SET 
DataValue = @data_val,
DataValueType = @data_value_type,
DataValueStatus = @data_value_status
WHERE (PointID = @point_id) 
     AND (DataTime BETWEEN @data_time + ' 00:00:00' AND @data_time + ' 23:59:59')