SQL Server : skip update if variable is NOT NULL - sql

I have a problem with a SQL Server database. I want to update the values of an ID only if the value is null, if there is a value it should be skipped -> not updated.
I don't know how to realise this "if else" in SQL Server - could somebody give me a hint?
Thanks in advance.
This is my pseudo code:
UPDATE dbo.mytable
IF FIELD1 IS NOT NULL SKIP --Don't update
ELSE IF FIELD1 IS NULL
SET FIELD1 (SELECT DISTINCT FIELD1
FROM mytable
WHERE {Some ID} = '123'
AND FIELD1 IS NOT NULL)
WHERE {Some ID} = '123'
AND FIELD1 IS NULL

UPDATE t
SET t.FIELD1 = ( SELECT DISTINCT TOP 1 FIELD1
FROM mytable t2
WHERE SomeID = '123'
AND FIELD1 IS NOT NULL )
FROM dbo.mytable t
WHERE FIELD1 IS NULL
AND SomeId = '123'

I think you want something like this:
UPDATE dbo.mytable
SET FIELD1 = ?
WHERE FIELD1 IS NULL;
The ? is a placeholder for the value you want to set it to.
If you want to set the value to the "123" value:
UPDATE dbo.mytable
SET FIELD1 = (SELECT t2.FIELD1 FROM dbo.mytable t2 WHERE t2.ID = 123)
WHERE FIELD1 IS NULL;

You can simply write the below query
UPDATE dbo.mytable
SET ID = 123
WHERE ID IS NULL
Hope this will help you. It will only update the ID when the value in ID field is NULL.

UPDATE dbo.mytable
SET FIELD1 = (SELECT DISTINCT FIELD1
FROM mytable
WHERE {Some ID} = '123'
AND FIELD1 IS NOT NULL)
WHERE {Some ID} = '123'
AND FIELD1 IS NULL --here your IF condition will get filter [[IF FIELD1 IS NOT NULL SKIP --Don't update]]

Related

Triggers Mutually Exclusive Boolean Fields

I have two boolean (bit) fields that I want to remain mutually exclusive. They can both be false, but if one gets set to true the other must be set to false.
I tried to create 2 triggers but wound up creating an infinite loop (that stopped after 32 iterations). Apparently they trigger each other. Here is the code I tried:
CREATE OR ALTER TRIGGER dbo.TriggerNameA
ON dbo.TableName
AFTER UPDATE
AS
IF UPDATE(FieldA)
BEGIN
UPDATE dbo.TableName
SET FieldB =
CASE WHEN dbo.TableName.FieldA = 1
THEN 0
ELSE 1
END
FROM dbo.TableName INNER JOIN inserted ON dbo.TableName.ID = inserted.ID
END;
;
GO
CREATE OR ALTER TRIGGER dbo.TriggerNameB
ON dbo.TableName
AFTER UPDATE
AS
IF UPDATE(FieldB)
BEGIN
UPDATE dbo.TableName
SET FieldA =
CASE WHEN dbo.TableName.FieldB = 1
THEN 0
ELSE 1
END
FROM dbo.TableName INNER JOIN inserted ON dbo.TableName.ID = inserted.ID
END;
;
GO
Any idea how to avoid the infinite loop?
Using a Check constraint removes the need for a trigger:
SQL Fiddle
MS SQL Server 2017 Schema Setup:
create table MyTable
(
ID int Identity,
FieldA bit,
FieldB bit,
CONSTRAINT Chk_Fields CHECK (FieldA <> 1 OR FieldB <> 1)
)
INSERT INTO MyTable(FieldA, FieldB)
VALUES (0,0),(0,1),(1,0)
Query 1:
select *
from MyTable
Results:
| ID | FieldA | FieldB |
|----|--------|--------|
| 1 | false | false |
| 2 | false | true |
| 3 | true | false |
Query 2:
INSERT INTO MyTable(FieldA, FieldB)
VALUES (1,1),(0,1),(1,0)
Results:
The INSERT statement conflicted with the CHECK constraint "Chk_Fields". The conflict occurred in database "db_18_941bc9", table "dbo.MyTable".
Query 3:
UPDATE MyTable
SET FieldB = 1
WHERE ID = 3
Results:
The UPDATE statement conflicted with the CHECK constraint "Chk_Fields". The conflict occurred in database "db_18_941bc9", table "dbo.MyTable".
EDIT As #CharlieFace mentions in his comment, the equivalent check
constraint of (FieldA = 0 OR FieldB = 0) is more readable
Okay, I apologize for my previous answer, but I'm sure I got it now. Thanks to #DB<>Fiddle for pointing out that it still was experiencing recursion (or nesting, not sure).
So I used the trigger_nestlevel function. Tested and now (finally) it works:
create table MyTable
(
ID int Identity,
FieldA bit,
FieldB bit
)
go
CREATE OR ALTER TRIGGER dbo.Trigger1
ON dbo.MyTable
AFTER UPDATE
AS
IF TRIGGER_NESTLEVEL() = 1
BEGIN
IF UPDATE(FieldA)
BEGIN
UPDATE dbo.MyTable SET dbo.MyTable.FieldB = 0
FROM dbo.MyTable INNER JOIN inserted ON dbo.MyTable.ID = inserted.ID;
END;
END;
;
GO
CREATE OR ALTER TRIGGER dbo.Trigger2
ON dbo.MyTable
AFTER UPDATE
AS
IF TRIGGER_NESTLEVEL() = 1
BEGIN
IF UPDATE(FieldB)
BEGIN
UPDATE dbo.MyTable SET dbo.MyTable.FieldA = 0
FROM dbo.MyTable INNER JOIN inserted ON dbo.MyTable.ID = inserted.ID;
END;
END;
;
GO
INSERT INTO MyTable(FieldA, FieldB)
VALUES (0,0)
SELECT * FROM MyTable;
-- 0 0
UPDATE MyTable
SET FieldA = 1
WHERE ID = 1;
SELECT * FROM MyTable;
-- 1 0
UPDATE MyTable
SET FieldB = 1
WHERE ID = 1;
SELECT * FROM MyTable;
-- 0 1
Then I can go back and forth and they continue to switch the way I need. Whew!
Here's an alternative using an INSTEAD OF TRIGGER to ensure that on an UPDATE only one of the fields is set to 1. I have made a decision in the trigger that if FieldA in the virtual INSERTED table is set to 1 then I set FieldB to zero:
SetUp
create table MyTable
(
ID int Identity,
FieldA bit,
FieldB bit
)
CREATE TRIGGER TriggerNameA ON MyTable
INSTEAD OF UPDATE
AS
IF UPDATE(FieldA)
BEGIN
MERGE [MyTable] AS t1
USING (SELECT * FROM INSERTED) AS t2
ON t1.ID = t2.ID
WHEN MATCHED THEN
UPDATE SET t1.[FieldA] = t2.FieldA,
t1.[FieldB] = CASE WHEN t2.FieldA = 1 THEN 0 ELSE t2.FieldB END;
END
ELSE IF UPDATE(FieldB)
BEGIN
MERGE [MyTable] AS t1
USING (SELECT * FROM INSERTED) AS t2
ON t1.ID = t2.ID
WHEN MATCHED THEN
UPDATE SET t1.[FieldB] = t2.FieldB,
t1.[FieldA] = CASE WHEN t2.FieldB = 1 THEN 0 ELSE t2.FieldA END;
END;
-- Add Else for cases where FieldA & FieldB weren't updated if required
Result 1
INSERT INTO MyTable(FieldA, FieldB)
VALUES (0,0),(0,1),(1,0);
SELECT * FROM MyTable
ID FieldA FieldB
1 False False
2 False True
3 True False
Result 2
UPDATE MyTable
SET FieldB = 1
WHERE ID = 1
SELECT * FROM MyTable
ID FieldA FieldB
1 False True
2 False True
3 True False
Result 3
UPDATE MyTable
SET FieldB = 1
WHERE ID = 3
SELECT * FROM MyTable
ID FieldA FieldB
1 False True
2 False True
3 False True
Result 4
UPDATE MyTable
SET FieldA = 1
WHERE ID = 2
SELECT * FROM MyTable
ID FieldA FieldB
1 False True
2 True False
3 True False
DB<>Fiddle
Edited to Update fieldA or FieldB depending on what column is updated
in the UPDATE statement

Selecting a specific value within a case statement

I need help with selecting a specific value within a CASE Statement.
For an example
SELECT CASE WHEN Field1 >= (Field2 = 1) THEN Answer
WHEN Field1 < (Field2 = 1) THEN No Answer
ELSE Question END AS Field3
I want to be able to select a specific value in Field2 within the CASE Statement
could be you are looking for
SELECT CASE WHEN Field1 >= Field2 AND Field2 = 1 THEN Answer
WHEN Field1 < Field2 AND Field2 = 1 THEN No Answer
ELSE Question END AS Field3
or more simply
SELECT CASE WHEN Field1 >= 1 THEN Answer
WHEN Field1 < 1 THEN No Answer
ELSE Question END AS Field3
-- 1. You don't specify the fields types.
-- 2. You do a comparison of Field1 with a logical expression (Field2=1). i guess it fails.
-- 3. I will assume Answer, No answer and Question will be the desired string result, and have to be quoted.
-- 4. A Table name is missing. I will assume Field1 and Field2 are fields from MyTable
-- 5. I' am assuming Field1 and Field2 of the same type, and be varchar(10) for example.
DECLARE #Field2 varchar(10) = 1
SELECT
CASE WHEN Field1 >= Field2 THEN 'Answer'
WHEN Field1 < Field2 THEN 'No Answer'
ELSE 'Question'
END AS Field3
FROM MyTable
WHERE Field2 = #Field2

IF ELSE workaround in Sqlite

I am trying to do a simple upsert query in SQL. This query works in SQL Server
IF (EXISTS (SELECT * FROM TableName WHERE SomeId = #SomeId AND SomeOtherId = #SomeOtherId))
BEGIN
UPDATE TableName
SET "SomeColumn" = #SomeValue
WHERE SomeId = #SomeId AND SomeOtherId = #SomeOtherId;
END
ELSE
BEGIN
INSERT INTO TableName VALUES (#SomeId, #SomeOtherId, #SomeValue);
END
However, our Unit tests run on Sqlite and in general we want to write vanilla SQL, so this IF ELSE won't work.
I was trying to pull it off with CASE WHEN but I can't get it right. Can somebody post a working Sqlite query?
Thanks in advance,
Marko
If there is (or you can create) a unique constraint for the combination of the columns SomeId and SomeOtherId, then you might use UPSERT like this:
INSERT INTO TableName(SomeId, SomeOtherId, SomeColumn)
VALUES(#SomeId, #SomeOtherId, #SomeValue)
ON CONFLICT(SomeId, SomeOtherId) DO
UPDATE SET SomeColumn = #SomeValue;
If not then use 2 statements:
UPDATE TableName
SET SomeColumn = #SomeValue
WHERE SomeId = #SomeId AND SomeOtherId = #SomeOtherId;
INSERT INTO TableName (SomeId, SomeOtherId, SomeColumn)
SELECT #SomeId, #SomeOtherId, #SomeValue
WHERE NOT EXISTS (
SELECT 1 FROM TableName
WHERE SomeId = #SomeId AND SomeOtherId = #SomeOtherId
);
The UPDATE statement will succeed only if there is a row under the conditions you specify, otherwise it will do nothing.
The INSERT statement will succeed only if there is not a row under the conditions you specify, otherwise it will do nothing.

How can I make this pl/sql cursor more efficient?

Hi guys I have a pl/sql cursor that takes too long to execute. I want to know how can I make the same process but with better performance and probably better code. I am new to PL/SQL.
Declare
Cursor Cursor1 is
select * from table1 where
field1 IS NULL
or
field2 IS NULL or field3 IS NULL or field4 is null or field5 IS NULL or field6 IS NULL;
Begin
For i in Cursor1 loop
if i.field1 IS NULL then
update table1 set field1=0 where recordId=i.recordId;
end if;
if i.field2 IS NULL then
update table1 set field2=0 where recordId=i.recordId;
end if;
if i.field3 IS NULL then
update table1 set field3=0 where recordId=i.recordId;
end if;
if i.field4 IS NULL then
update table1 set field4=0 where recordId=i.recordId;
end if;
if i.field5 IS NULL then
update table1 set field5=0 where recordId=i.recordId;
end if;
if i.field6 IS NULL then
update table1 set field6=0 where recordId=i.recordId;
end if;
End loop;
End;
The question basically is how can I update a field of one specific record, taking into account the conditions of the field. The thing is that the update can occur in the same record many times if the condition apply for many fields in the record.
Thanks...
It's possible to do the same with one UPDATE
UPDATE table1 SET
field1 = COALESCE(field1, 0)
, field2 = COALESCE(field2, 0)
, field3 = COALESCE(field3, 0)
, field4 = COALESCE(field4, 0)
, field5 = COALESCE(field5, 0)
, field6 = COALESCE(field6, 0)
WHERE field1 IS NULL OR field2 IS NULL OR field3 IS NULL
OR field4 IS NULL OR field5 IS NULL OR field6 IS NULL
Here's another take on this:
UPDATE TABLE1
SET FIELD1 = NVL(FIELD1, 0),
FIELD2 = NVL(FIELD2, 0),
FIELD3 = NVL(FIELD3, 0),
FIELD4 = NVL(FIELD4, 0),
FIELD5 = NVL(FIELD5, 0),
FIELD6 = NVL(FIELD6, 0);
Rationale: any query which performs this update is going to do a full table scan anyways because it's looking for NULLs, which won't be indexed in the usual case, and even if they ARE indexed there's a fair chance the optimizer will choose a full table scan anyways. Why waste time checking six different fields for NULLs?
Share and enjoy.
Try executing couple of updates like this, avoiding the usage of a cursor:
update table1 set field1=0 where field1 IS NULL;
update table1 set field2=0 where field2 IS NULL;
update table1 set field3=0 where field3 IS NULL;
update table1 set field4=0 where field4 IS NULL;
update table1 set field5=0 where field5 IS NULL;
update table1 set field6=0 where field6 IS NULL;
I don't think that there is a more efficient way to do this.

SQL update, string to numeric

In an SQL Server database, I have to update some fields, the query is (, is the decimal separator) :
UPDATE MyTbable
SET
Field1 = CAST('111,11' AS DEC(18,4)),
Field2 = CAST('222,22' AS DEC(18,4)),
Field3 = CAST('333,33' AS DEC(18,4))
WHERE Id = '1'
I receive the error :
Error converting data type varchar to numeric. I tried with the cast, same problem
Field1,Field2 and Field3 are numeric 38,2
Any idea ?
Thanks,
Take the commas out.
UPDATE MyTbable
SET
Field1 = CAST(REPLACE('111,11',',','.') AS DEC(18,4)),
Field2 = CAST(REPLACE('222,22',',','.') AS DEC(18,4)),
Field3 = CAST(REPLACE('333,33',',','.') AS DEC(18,4))
WHERE Id = '1'
Use . instead of ,
UPDATE MyTbable
SET
Field1 = CAST('111.11' AS DEC(18,4)),
Field2 = CAST('222.22' AS DEC(18,4)),
Field3 = CAST('333.33' AS DEC(18,4))
WHERE Id = '1'
If you want to select these values afterwards as string and with comma then do that:
select replace(cast(Field1 as varchar(30)), '.',','),
replace(cast(Field2 as varchar(30)), '.',','),
replace(cast(Field2 as varchar(30)), '.',','),
where Id = '1'
remove the commas in you query like :
UPDATE MyTbable
SET
Field1 = CAST('11111' AS DEC(18,4)),
Field2 = CAST('22222' AS DEC(18,4)),
Field3 = CAST('33333' AS DEC(18,4))
WHERE Id = '1'
or you can rmove the comma using replace:
replace('111,11',',','.')