我使用游标迭代相当大的表。对于每一行,我检查一列中的值是否存在于其他行中。
如果值存在,我想在另一个表中增加value列。 如果没有,我想插入一个值为1的新行。
我通过以下方式检查“if exists”:
IF (SELECT COUNT(*) FROM otherTabe WHERE... > 1)
BEGIN
...
END
ELSE
BEGIN
...
END
我不知道如何获取找到的行并更新值。我不想再做一次选择。
我怎样才能有效地做到这一点?
我认为上述检查方法对这种情况并不好。
答案 0 :(得分:4)
根据数据大小和实际情况,您有两种基本方法:
1)使用MERGE
MERGE TOP (...) INTO table1
USING table2 ON table1.column = table2.column
WHEN MATCHED
THEN UPDATE SET table1.counter += 1
WHEN NOT MATCHED SOURCE
THEN INSERT (...) VALUES (...);
需要TOP
,因为当你做这样一个巨大的更新时(你提到的表是'大',大是相对的,但是假设真的很大,+ 100MM行)你必须批处理更新,否则你将用一个巨大的交易压倒事务日志。
2)使用光标,正如您尝试的那样。您可以轻松解决原始问题,只需始终更新,然后检查更新的行数:
UPDATE table
SET column += 1
WHERE ...;
IF @@ROW_COUNT = 0
BEGIN
-- no match, insert new value
INSERT INTO (...) VALUES (...);
END
请注意,由于竞争条件,这种方法很危险:没有什么可以防止另一个线程同时插入值,因此最终可能会出现重复或约束违规错误(最好是后者......)。
答案 1 :(得分:2)
这只是伪代码,因为我不知道你的表结构,但我想你会明白...基本上更新你想要的列然后插入你需要的列。光标操作听起来没必要。
Update OtherTable
Set ColumnToIncrease = ColumnToIncrease + 1
FROM CurrentTable Where ColumnToCheckValue is not null
Insert Into OtherTable (ColumnToIncrease, Field1, Field2,...)
SELECT
1,
?
?
FROM CurrentTable Where ColumnToCheckValue is not null
答案 2 :(得分:2)
没有样品,我认为这是我能做的最好的。底线:您不需要光标。 UPDATE
匹配存在(INNER JOIN
)和INSERT
,其中一个不匹配。
UPDATE otherTable
SET IncrementingColumn = IncrementingColumn + 1
FROM thisTable INNER JOIN otherTable ON thisTable.ID = otherTable.ID
INSERT INTO otherTable
(
ID
, IncrementingColumn
)
SELECT ID, 1
FROM thisTable
WHERE NOT EXISTS (SELECT *
FROM otherTable
WHERE thisTable.ID = otherTable.ID)
答案 3 :(得分:2)
我认为 you'd be better off using a view for this - 然后它总是最新的,没有错误的双重/三重/等计数的风险:
CREATE VIEW vw_value_count AS
SELECT st.value,
COUNT(*) AS numValue
FROM SOME_TABLE st
GROUP BY st.value
但是如果您仍想使用INSERT / UPDATE方法:
IF EXISTS(SELECT NULL
FROM SOMETABLE WHERE ... > 1)
BEGIN
UPDATE TABLE
SET count = count + 1
WHERE value = @value
END
ELSE
BEGIN
INSERT INTO TABLE
(value, count)
VALUES
(@value, 1)
END
答案 4 :(得分:1)
如何使用内连接执行+1的Update语句,并插入第一个表中不存在的选定行。
提供表格架构以及要检查和更新的列,以便我们提供帮助。
问候。