我的应用程序无法正常运行。 我们发现系统错误,但供应商声称此问题无法解决。
该问题与数据库中被覆盖的数据有关。
系统每天从外部数据源收集数据。 收集的数据包含过去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
答案 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')