SQL Server: IF EXISTS ; ELSE - sql

I have a tableA:
ID value
1 100
2 101
2 444
3 501
Also TableB
ID Code
1
2
Now I want to populate col = code of table B if there exists ID = 2 in tableA. for multiple values , get max value.
else populate it with '123'. Now here is what I used:
if exists (select MAX(value) from #A where id = 2)
BEGIN
update #B
set code = (select MAX(value) from #A where id = 2)
from #A
END
ELSE
update #B
set code = 123
from #B
I am sure there is some problem in BEGIN;END or in IF EXIST;ELSE.
Basically I want to by-pass the else part if select statement in IF-part exist and vice- versa. For example if select statement of IF=part is:
(select MAX(value) from #A where id = 4)
It should just populate 123, coz ID = 4 do not exist !

EDIT
I want to add the reason that your IF statement seems to not work. When you do an EXISTS on an aggregate, it's always going to be true. It returns a value even if the ID doesn't exist. Sure, it's NULL, but its returning it. Instead, do this:
if exists(select 1 from table where id = 4)
and you'll get to the ELSE portion of your IF statement.
Now, here's a better, set-based solution:
update b
set code = isnull(a.value, 123)
from #b b
left join (select id, max(value) from #a group by id) a
on b.id = a.id
where
b.id = yourid
This has the benefit of being able to run on the entire table rather than individual ids.

Try this:
Update TableB Set
Code = Coalesce(
(Select Max(Value)
From TableA
Where Id = b.Id), 123)
From TableB b

I know its been a while since the original post but I like using CTE's and this worked for me:
WITH cte_table_a
AS
(
SELECT [id] [id]
, MAX([value]) [value]
FROM table_a
GROUP BY [id]
)
UPDATE table_b
SET table_b.code = CASE WHEN cte_table_a.[value] IS NOT NULL THEN cte_table_a.[value] ELSE 124 END
FROM table_b
LEFT OUTER JOIN cte_table_a
ON table_b.id = cte_table_a.id

Related

Checking whether two tables have identical content

How can I check and store in variable whether two tables have identical content?
I have table variable with data like
declare #table1 table (id int)
insert into #table1 (id) values (1), (2), (3)
and as the second table I have query
select T.id from SomeTable T
inner join #table1 T1 on T.id = T1.id
the query returns data:
id
-----
1
2
In this case I need write false(0) into declare #HasAccess BIT variable.
When the query returns data:
id
-----
1
2
3
then I need write true(1) into #HasAccess
Hmmm. There are various ways.
Given that you have one column, you can do:
select (case when count(*) = 0 then 1 else 0 end)
from t1 full join
t2
on t1.id = t2.id
where t1.id is null or t2.id is null;
This checks if an id doesn't match in either table.
Another way uses union all:
select (case when count(*) = 0 then 1 else 0 end)
from (select id, sum(in_t1) as num_t1, sum(in_t2) as num_t2)
from ((select id, 1 as in_t1, 0 as in_t2 from table1) union all
(select id, 0, 1 from table2)
) tt
group by id
) tt
where num_t1 <> 1 or num_t2 <> 1;
Another option (just for fun). This will compare the entire table fields and values.
I suspect not the best option for LARGE tables
Example
Select IsIdentical = case when (Select * from Table1 Order by id For XML Raw)
= (Select * from Table2 Order by id For XML Raw)
then 1 else 0 end
EDIT - Option with Inner Join
Select IsIdentical = case when (Select * from #Table1 Order by id For XML Raw)
= (Select A.*
From SomeTable A
Join #Table1 B on A.ID=B.ID
Order By id For XML Raw)
then 1 else 0 end
Using EXCEPT:
SET #HasAccess = ISNULL(
( SELECT 0
WHERE EXISTS(
SELECT ID /* add more columns here if needed */
FROM #table1
EXCEPT
SELECT ID /* add more columns here if needed */
FROM SomeTable )), 1 )
Explanation:
Return all IDs from #table1, except those found in SomeTable
Return 0 (false) if any records have been returned by [1].
If no records returned by [1] the main query will return NULL, hence the ISNULL
Advanatages
Can easily be extended to comparisons on more than one column.

SQL Query is updating with NULL values

I am using Oracle and I am trying to update a table(A) with data from another table(B). Not every field in B has a value so I have a number of NULL entries. When I run the update it says 6000 rows updated. Now there are 6000 rows in table B, however for this query only 14 have data in. When I select count(*) from both tables for this value they both return 14 rows each. Why is it reporting that 6000 rows have been updated?
UPDATE
table1 A
SET
phone_work = (
SELECT B.phone_work
FROM table2 B
WHERE B.id = A.applicant_id)
WHERE EXISTS (
SELECT 1
FROM table2 B
WHERE B.id = A.applicant_id);
I have also tried the following and I get the same result:
UPDATE
table1 A
SET
phone_work = (
SELECT B.phone_work
FROM table2 B
WHERE B.id = A.applicant_id
AND B.phone_work is not null
)
WHERE EXISTS (
SELECT 1
FROM table2 B
WHERE B.id = A.applicant_id);
Why is it reporting the update of 6000 rows? When I change the fields but use the same syntax it reports updating of the exact number of rows I expect e.g. a count of table B has 86 entries in the NAME field and it reports 86 rows updated. It seems that with the phone_work field I am getting every null value being counted as an update.
Perhaps you want to check for the non-NULL value in the exists:
UPDATE table1 A
SET phone_work = (SELECT B.phone_work
FROM table2 B
WHERE B.id = A.applicant_id
)
WHERE EXISTS (SELECT 1
FROM table2 B
WHERE B.id = A.applicant_id AND B.phone_work IS NOT NULL
);
Try this:
UPDATE
(
SELECT A.phone_work Aphone, B.phone_work Bphone
FROM table2 B, table1 A
WHERE B.id = A.applicant_id AND B.phone_work IS NOT NULL
)
SET
Aphone = Bphone;
Source: Oracle SQL: Update a table with data from another table

Update column of Table B based on column of Table A

I have a huge stored procedure and I am trying to optimize it .
I have a temporary table A , with column Id.
I have a main table B with columns Id & a boolean field Test
For all Id's in Table A , I need to make the Test = 1 in Table B.
example :
A
Id
--
1
2
3
I need to get table B as follows.
I already have the Id field in Table B , I only need to update the
Test Column
B
Id Test
-- ----
1 1
2 1
3 1
4
5
6
I am currently looping through Table A using a while loop and for each Id
I am updating the Test column in Table B .
WHILE (1 = 1)
BEGIN
-- Exit loop if no more Transactions
IF ##ROWCOUNT = 0 BREAK;
Update [B]
set Test = 1
where Id = (SELECT TOP 1 Id
FROM #B
WHERE Id > #Id1
ORDER BY Id)
END
PS : #Id1 is the input parameter of the stored procedure.
I cannot think of any other efficient way of doing it, but
my query is taking a lot of time to run..
Please let me know if there is a better way of doing the same thing.
This is pretty straight forward.
UPDATE [B]
SET [TEST] = 1
FROM [B] INNER JOIN [A]
ON [A].ID = [B].ID
Another alternative:
UPDATE b SET test = 1
FROM dbo.TableB AS b
WHERE EXISTS (SELECT 1 FROM dbo.TableA WHERE ID = b.ID);
You don't need to loop for this, just join those tables
UPDATE B
SET B.Test = 1
FROM TableB B
INNER JOIN TableA A
ON A.Id = B.ID
Here is an sqlfiddle with a live demo.
You can use in to find the records to update:
update b
set Test = 1
where Id in (select Id from #A)
Another alternative is to join the tables:
update x
set Test = 1
from b as x
inner join #A as a on a.id = x.id
If I'm understanding your question correctly, all you need to do is join A and B.
UPDATE TableB SET test = 1
FROM TableB b
INNER JOIN TableA a ON a.id = b.id
WHERE b.ID > #Id1
Basically you're looking to update everywhere where TableA and TableB intersect.
http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

Updating and join on multiple rows, which row's value is used?

Let's say I have the following statement and the inner join results in 3 rows where a.Id = b.Id, but each of the 3 rows have different b.Value's. Since only one row from tableA is being updated, which of the 3 values is used in the update?
UPDATE a
SET a.Value = b.Value
FROM tableA AS a
INNER JOIN tableB as b
ON a.Id = b.Id
I don't think there are rules for this case and you cannot depend on a particular outcome.
If you're after a specific row, say the latest one, you can use apply, like:
UPDATE a
SET a.Value = b.Value
FROM tableA AS a
CROSS APPLY
(
select top 1 *
from tableB as b
where b.id = a.id
order by
DateColumn desc
) as b
Usually what you end up with in this scenario is the first row that appears in the order of the physical index on the table. In actual practice, you should treat this as non-deterministic and include something that narrows your result to one row.
Here is what I came up with using SQL Server 2008
--drop table #b
--drop table #a
select 1 as id, 2 as value
into #a
select 1 as id, 5 as value
into #b
insert into #b
select 1, 3
insert into #b
select 1, 6
select * from #a
select * from #b
UPDATE #a
SET #a.Value = #b.Value
FROM #a
INNER JOIN #b
ON #a.Id = #b.Id
It appears that it uses the top value of a basic select each time (row 1 of select * from #b). So, it possibly depends on indexing. However, I would not rely on the implementation set by SQL, as that has the possibility of changing. Instead, I would suggest using the solution presented by Andomar to make sure you know what value you are going to choose.
In short, do not trust the default implementation, create your own. But, this was an interesting academic question :)
Best option in my case for updating multiple records is to use merge Query(Supported from SQL Server 2008), in this query you have complete control of what you are updating.
Also you can use output query to do further processing.
Example: Without Output clause(only update)
;WITH cteB AS
( SELECT Id, Col1, Col2, Col3
FROM B WHERE Id > 10 ---- Select Multiple records
)
MERGE A
USING cteB
ON(A.Id = cteB.Id) -- Update condition
WHEN MATCHED THEN UPDATE
SET
A.Col1 = cteB.Col1, --Note: Update condition i.e; A.Id = cteB.Id cant appear here again.
A.Col2 = cteB.Col2,
A.Col3 = cteB.Col3;
Example: With OputPut clause
CREATE TABLE #TempOutPutTable
{
PkId INT NOT NULL,
Col1 VARCHAR(50),
Col2 VARCHAR(50)
}
;WITH cteB AS
( SELECT Id, Col1, Col2, Col3
FROM B WHERE Id > 10
)
MERGE A
USING cteB
ON(A.Id = cteB.Id)
WHEN MATCHED THEN UPDATE
SET
A.Col1 = cteB.Col1,
A.Col2 = cteB.Col2,
A.Col3 = cteB.Col3
OUTPUT
INSERTED.Id, cteB.Col1, A.Col2 INTO #TempOutPutTable;
--Do what ever you want with the data in temporary table
SELECT * FROM #TempOutPutTable; -- you can check here which records are updated.
Yes, I came up with a similar experiment to Justin Pihony:
IF OBJECT_ID('tempdb..#test') IS NOT NULL DROP TABLE #test ;
SELECT
1 AS Name, 0 AS value
INTO #test
IF OBJECT_ID('tempdb..#compare') IS NOT NULL DROP TABLE #compare ;
SELECT 1 AS name, 1 AS value
INTO #compare
INSERT INTO #compare
SELECT 1 AS name, 0 AS value;
SELECT * FROM #test
SELECT * FROM #compare
UPDATE t
SET t.value = c.value
FROM #test t
INNER JOIN #compare c
ON t.Name = c.name
Takes the topmost row in the comparison, right-side table. You can reverse the #compare.value values to 0 and 1 and you'll get the reverse. I agree with the posters above...its very strange that this operation does not throw an error message as it is completely hidden that this operation IGNORES secondary values

Update Field based on another table's values

Is there a more elegant way to write the following Microsoft SQL Server 2008 command?
UPDATE TableB
SET TableBField2=0
WHERE TableBID IN(
SELECT TableBID
FROM TableB
JOIN TableA on TableB.TableAID=TableA.TableAID
WHERE TableBField2 < 0
AND TableAField1 = 0
)
In plain speak, what I'm doing is updating a table based on the value of a field in a joined table. I wonder if my use of IN() is considered inefficient.
This should be more efficient:
UPDATE TableB b
SET TableBField2=0
WHERE exists (
SELECT 1
FROM TableA
WHERE b.TableAID=TableA.TableAID
AND b.TableBField2 < 0
AND TableAField1 = 0
)
You can try something like this
UPDATE TableB
SET Field2 = 0
FROM TableB b INNER JOIN
TableA a ON b.TableB.TableAID=a.TableAID
WHERE b.Field2 < 0
AND a.Field1 = 0