views:

70

answers:

5

I use a cursor to iterate through quite a big table. For each row I check if value from one column exists in other.

If the value exists, I would like to increase value column in that other table. If not, I would like to insert there new row with value set to 1.

I check "if exists" by:

IF (SELECT COUNT(*) FROM otherTabe WHERE... > 1)
   BEGIN
      ...
   END
ELSE
   BEGIN
      ...
   END

I don't know how to get that row which was found and update value. I don't want to make another select.

How can I do this efficiently?

I assume that the method of checking described above isn't good for this case.

+1  A: 

What about Update statement with inner join to perform +1, and Insert selected rows that do not exist in the first table.

Provide the tables schema and the columns you want to check and update so I can help.

Regards.

A_Nablsi
I posted some pseudo to this effect.
Brad
+2  A: 

This is just psuedo code because I have no idea of your table structure but I think you will understand... basically Update the columns you want then Insert the columns you need. A Cursor operation sounds unnecessary.

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
John Hartsock
+1 I should have invented x y tables :)
A_Nablsi
+2  A: 

Without a sample, I think this is the best I can do. Bottom line: you don't need a cursor. UPDATE where a match exists (INNER JOIN) and INSERT where one does not.

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)
Brad
+2  A: 

I think you'd be better off using a view for this -- then it's always up to date, no risk of mistakenly double/triple/etc counting:

CREATE VIEW vw_value_count AS
  SELECT st.value,
         COUNT(*) AS numValue
    FROM SOME_TABLE st
GROUP BY st.value

But if you still want to use the INSERT/UPDATE approach:

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
OMG Ponies
+4  A: 

Depending on the size of your data and the actual condition, you have two basic approaches:

1) use 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 (...);

the TOP is needed because when you're doing a huge update like this (you mention the table is 'big', big is relative, but lets assume truly big, +100MM rows) you have to batch the updates, otherwise you'll overwhelm the transaction log with one single gigantic transaction.

2) use a cursor, as you are trying. Your original question can be easily solved, simply always update and then check the count of rows updated:

UPDATE table 
  SET column += 1
WHERE ...;
IF @@ROW_COUNT = 0
BEGIN
   -- no match, insert new value 
   INSERT INTO (...) VALUES (...);
END

Note that this approach is dangerous though because of race conditions: there is nothing to prevent another thread from inserting the value concurrently, so you may end up with either duplicates or a constraint violation error (preferably the latter...).

Remus Rusanu