Difference between "IF EXISTS" and "IF NOT EXISTS" in SQL? - sql

I am very new to SQL. I want to know what happens when i use "IF EXISTS" or "IF NOT EXISTS".
For ex: what is the difference between the following two statements:
Statement 1: (EXISTS)
IF EXISTS( SELECT ORDER_ID FROM DBO.ORDER_DETAILS WHERE ORDER_ID = 11032 )
BEGIN
DELETE FROM DBO.ORDER_DETAILS WHERE ORDER_ID = 11032
END
Statement 2: (NOT EXISTS)
IF NOT EXISTS( SELECT ORDER_ID FROM DBO.ORDER_DETAILS WHERE ORDER_ID = 11032 )
BEGIN
DELETE FROM DBO.ORDER_DETAILS WHERE ORDER_ID = 11032
END
What will the IF EXISTS or IF NOT EXISTS return?
Which is better among these both?
When to use IF EXISTS and when to use IF NOT EXISTS

Here are 4 examples illustrating when you would use IF EXISTS and when you would use IF NOT EXISTS:
A) Delete related records from more than 1 table:
IF EXISTS (SELECT TOP(1) 1 FROM Table1 WHERE ORDER_ID = 11032) BEGIN
DELETE FROM Table1 WHERE ORDER_ID = 11032
DELETE FROM Table2 WHERE ORDER_ID = 11032
-- possibly more statements following here ...
END
B) Update record in more than 1 table if it exists:
IF EXISTS (SELECT TOP(1) 1 FROM Table1 WHERE ORDER_ID = 11032) BEGIN
UPDATE Table1 SET Field1='X' WHERE ORDER_ID = 11032
UPDATE Table2 SET Field2='Y' WHERE ORDER_ID = 11032
-- possibly more statements following here ...
END
C) Insert record in more than 1 table if it does not exist:
IF NOT EXISTS (SELECT TOP(1) 1 FROM Table1 WHERE ORDER_ID = 11032) BEGIN
INSERT INTO Table1(Field1, Field2, ORDER_ID) VALUES ('A', 'B', 11032)
INSERT INTO Table2(Field3, Field4, ORDER_ID) VALUES ('X', 'Y', 11032)
-- possibly more statements following here ...
END
D) Upsert (=insert or update) record, depending on existence:
IF EXISTS (SELECT TOP(1) 1 FROM Table1 WHERE ORDER_ID = 11032) BEGIN
UPDATE Table1 SET Field1='X' WHERE ORDER_ID = 11032
-- possibly more statements following here ...
END
ELSE BEGIN
INSERT INTO Table1(Field1, Field2, ORDER_ID) VALUES ('X', 'B', 11032)
-- possibly more statements following here ...
END
Instead of the above statement (case D), you can also use the new MERGE statement, but I think it's a bit complicated to use.
NOTES:
If there is just one table affected, you would not use EXIST in any of the examples above, except in the upsert example D).
SELECT TOP (1) 1 FROM ... is more efficient, because it aborts after the 1st match is found, then it returns just number 1 (which is more efficient to select for instance a NVARCHAR(max) field)
You can see that only in example C) you are forced to use IF NOT EXISTS(...), all other examples are using IF EXISTS(...) which is more efficient.

You need the first statement. Basically "IF EXISTS" returns true if the query return 1 or more rows, so in you example it will return a single row (containing a field with value 1) so will execute the delete statement as you desire.

Both statements will return a boolean true/false result.
EXISTS returns true if the result set IS NOT empty.
NOT EXISTS Is a negated operation, so it returns true if the result set IS empty

If there are order_details with an order_id equal to 11032, your first statement will run :
DELETE FROM DBO.ORDER_DETAILS WHERE ORDER_ID = 11032
If there are not order_details with an order_id equal to 11032, then your second statement will run. Note that this is an empty set since you just checked that there were not orders with that order_id.
It's actually going to be easier, in this example, to just run the DELETE - the IF EXISTS and IF NOT EXISTS are superfluous.

IF EXISTS checks that the result set is not empty, and IF NOT EXISTS checks that the result set is empty.
Which is better among these both?
The one that gives you the appropriate semantics.
When to use "IF EXISTS" and when to use "IF NOT EXISTS"
When you need to check the non-emptiness or emptiness of a result set.

"EXISTS simply tests whether the inner query returns any row. If it does, then the outer query proceeds. If not, the outer query does not execute, and the entire SQL statement returns nothing." See here. NOT EXISTS is the negation of EXISTS of course.
What the first statement does is that it will issue a DELETE query if the order can be found. The second one does not have any sense as it will issue the query on the ORDER when it does not exist.

This is certainly one way to use an EXISTS. I'm not sure that the second one would do anything though.
However, you could just
DELETE FROM DBO.ORDER_DETAILS WHERE ORDER_ID = 11032
and remove the EXISTS altogether, unless you wanted to perform
IF EXISTS ( SELECT ORDER_ID FROM ORDERS WHERE ORDER_ID = 11032 ) BEGIN
DELETE FROM DBO.ORDER_DETAILS WHERE ORDER_ID = 11032
DELETE FROM DBO.ORDERS WHERE ORDER_ID = 11032
END
or your actual code was more complex than what is shown.
Your second statement will never delete anything since, if there are rows, it will evaluate to FALSE and not perform the DELETE and if there are not rows, it will evaluate to TRUE and execute the DELETE which will do nothing since there are no rows.
As far as performance, in the context in which you use the EXISTS neither one has a better performance since it's really just evaluating whether the result set from the SELECT is NULL or not.
There is another use of EXISTS in which NOT EXISTS is much less efficient than EXISTS and can be effectively replaced with a better performing phrase. I'm referring to when you use NOT EXISTS in the WHERE clause of a statment. In this cause you would be better off performing a LEFT JOIN (instead of the INNER JOIN you likely have) and filter WHERE rightTable.SomeColumn IS NULL.

Related

How to perform IF ELSE THEN T-SQL?

Is it possible to perform IF ELSE THEN in SQL Server ?
For example I want to perform IF my result of query is NOT NULL (My row is exist). It will continue to THEN statement
ELSE if my result of query is NULL (My row is doesn't exist), it will continue to another THEN statement
For T-SQL Example, this is just dummy SQL script
IF (SELECT * FROM TABLE_A) IS NOTNULL THEN
(INSERT INTO TABLE_B)
ELSE
(DIDN'T PERFORM ANY QUERY)
Thank you
You could check if the table returns any rows and then perform SELECT INTO operation
IF EXISTS (SELECT 1 FROM TABLE_A)
BEGIN
SELECT * INTO TABLE_B FROM TABLE_A
END;
You could use your SELECT statement in the WHERE clause of your INSERT, like so:
INSERT INTO TABLE_B(...)
SELECT ...
FROM ...
WHERE EXISTS(SELECT * FROM TABLE_A);
and then test wether anything was inserted with IF ##ROWCOUNT > 0 THEN.
Assuming you just want to insert specific rows from A into B, then you can use:
INSERT INTO TABLE_B ( . . . ) -- list the columns here
SELECT . . .
FROM TABLE_A;
If there are no rows, then nothing gets inserted. It is that simple.
Actually, it is simpler than that. Using IF introduces race conditions in your code. The TABLE_A could change between the execution of the IF and the INSERT, so the code is not thread-safe. This code does not have that problem.

Oracle SQL, trying to get one value from a select/join to use to update one column in one table?

I have one table with the following columns:
T_RESOLVED_DATE
I_HOUSEHOLD_NUMBER
I_RESOLVED_SET_NUMBER
I_STATION_CODE
I_RESOLVED_START_MIN
I_DURATION
I_PERSON_NUMBER
I_COVIEW_DEMO_ID
Initially, I_COVIEW_DEMO_ID is set to null.
Then I have another table with the following columns:
T_RESOLVED_DATE
I_HOUSEHOLD_NUMBER
I_PERSON_NUMBER
I_AGE
T_GENDER
I_COVIEW_DEMO_ID
I am trying to update I_COVIEW_DEMO_ID in the first table by using the value of I_COVIEW_DEMO_ID in the second table where the T_RESOLVED_DATE, I_HOUSEHOLD_NUMBER, and I_PERSON_NUMBER are equal in both tables. The first table may contain multiple rows with the same DATE, HOUSEHOLD_NUMBER, and PERSON_NUMBER, because the rows can vary by the rest of the columns.
I have tried to do a select and a group by which seems to get me part way there, but I am getting a "single-row subquery returns more than one row" error when I try to update the columns in the first table. This is what I've tried, along with variations of it:
UPDATE
Table1
SET
I_COVIEW_DEMO_ID =
(SELECT
b.I_COVIEW_DEMO_ID
FROM Table1 a,
Table2 b
WHERE a.I_HOUSEHOLD_NUMBER = b.I_HOUSEHOLD_NUMBER AND
a.I_PERSON_NUMBER = b.I_PERSON_NUMBER AND
a.T_RESOLVED_DATE = b.T_RESOLVED_DATE
GROUP BY b.I_COVIEW_DEMO_ID);
Any suggestions?
I was able to get it to work using this statement:
MERGE INTO table1 a
USING
(
SELECT DISTINCT
T_RESOLVED_DATE,
I_HOUSEHOLD_NUMBER,
I_PERSON_NUMBER,
I_COVIEW_DEMO_ID
FROM
table2
) b
ON
(
a.T_RESOLVED_DATE = b.T_RESOLVED_DATE
AND a.I_HOUSEHOLD_NUMBER = b.I_HOUSEHOLD_NUMBER
AND a.I_PERSON_NUMBER = b.I_PERSON_NUMBER
) WHEN MATCHED THEN
UPDATE SET
a.I_COVIEW_DEMO_ID = b.I_COVIEW_DEMO_ID;
As per our discussion on the comments this would be a simple PLSQL block to do what you need. I'm doing direct from my head without test, so you may need to fix some sintaxe mistake.
BEGIN
FOR rs IN ( SELECT I_HOUSEHOLD_NUMBER,
I_PERSON_NUMBER,
I_COVIEW_DEMO_ID,
T_RESOLVED_DATE
FROM Table2 ) LOOP
UPDATE Table1
SET I_COVIEW_DEMO_ID = rs.I_COVIEW_DEMO_ID
WHERE I_PERSON_NUMBER = rs.I_PERSON_NUMBER
AND I_HOUSEHOLD_NUMBER = rs.I_HOUSEHOLD_NUMBER
AND T_RESOLVED_DATE = rs.T_RESOLVED_DATE;
END LOOP;
--commit after all updates, if there is many rows you should consider in
--making commits by blocks. Define a count and increment it whithin the for
--after some number of updates you commit and restart the counter
COMMIT;
END;

Delete all rows from a table that are present in a View

The queries I would like to perform:
BEGIN TRANSACTION
INSERT INTO TABLE_B SELECT * FROM TABLE_A WHERE SOME_COLUMN = 'something'
DELETE FROM TABLE_A WHERE COLUMN IN (
SELECT * FROM TABLE_A WHERE SOME_COLUMN = 'something'
)
END TRANSACTION
As you can see, there is a redundant SELECT statement in the DELETE query that I would like to replace (if possible), thus improving efficiency.
I was thinking to create a View with the rows in the first query and then scan the View with the rows in the second table. If some condition matches, then delete the row from the second table.
Could I get some pointers on how this could be done? If there is anything wrong I am doing, please criticize.
This is what you want, I think:
delete from table_a
where some_column = 'something'
As written, your query would probably generate a syntax error. The "SELECT *" would return all columns in table_a, and it presumably has more than one column.
Generally, you should be able to do joins in the delete statement, but you'd need to specify the table from which you're deleting rows:
delete table_a
from table_a left join table_b on (table_a.column_a = table_b.column_b)
where table_b.column_b = 'some_value'

IF-Statement in SQLite: update or insert?

I Can't run this query with SQLite
if 0<(select COUNT(*) from Repetition where (Word='behnam' and Topic='mine'))
begin
update Repetition set Counts=1+ (select Counts from Repetition where (Word='behnam' and Topic='mine'))
end
else
begin
insert Repetition(Word,Topic,Counts)values('behnam','mine',1)
end
It says "Syntax error near IF"
How can I solve the problem
SQLite does not have an IF statement (see the list of supported queries)
Insetad, check out out ERIC B's suggestion on another thread. You're effectively looking at doing an UPSERT (UPdate if the record exists, INSERT if not). Eric B. has a good example of how to do this in SQLite syntax utilizing the "INSERT OR REPLACE" functionality in SQLite. Basically, you'd do something like:
INSERT OR REPLACE INTO Repetition (Word, Topic, Counts)
VALUES ( 'behnam', 'mine',
coalesce((select Counts + 1 from Repetition
where Word = 'behnam', AND Topic = 'mine)
,1)
)
Another approach is to INSERT ... SELECT ... WHERE ... EXISTS [or not] (SELECT ...);
I do this sort of thing all the time, and I use jklemmack's suggestion as well. And I do it for other purposes too, such as doing JOINs in UPDATEs (which SQLite3 does not support).
For example:
CREATE TABLE t(id INTEGER PRIMARY KEY, c1 TEXT NOT NULL UNIQUE, c2 TEXT);
CREATE TABLE r(c1 TEXT NOT NULL UNIQUE, c2 TEXT);
INSERT OR REPLACE INTO t (id, c1, c2)
SELECT t.id, coalesce(r.c1, t.c1), coalesce(r.c2, t.c2)
FROM r LEFT OUTER JOIN t ON r.c1 = t.c1
WHERE r.c2 = #param;
The WHERE there has the condition that you'd have in your IF. The JOIN in the SELECT provides the JOIN that SQLite3 doesn't support in UPDATE. The INSERT OR REPLACE and the use of t.id (which can be NULL if the row doesn't exist in t) together provide the THEN and ELSE bodies.
You can apply this over and over. If you'd have three statements (that cannot somehow be merged into one) in the THEN part of the IF you'd need to have three statements with the IF condition in their WHEREs.
This is called an UPSERT (i.e. UPdate or inSERT). It has its forms in almost every type of database. Look at this question for the SQLite version: SQLite - UPSERT *not* INSERT or REPLACE
One way that I've found is based on SQL WHERE clause true/false statement:
SELECT * FROM SOME_TABLE
WHERE
(
SELECT SINGLE_COLUMN_NAME FROM SOME_OTHER_TABLE
WHERE
SOME_COLUMN = 'some value' and
SOME_OTHER_COLUMN = 'some other value'
)
This actually means execute some QUERIES if some other QUERY returns 'any' result.

T-SQL cursor and update

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.
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...).
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
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)
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
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.