I have a scenario where I want to update multiple columns of first table from multiple rows of second table. But the case only updates from first row from second table.
Any help to achieve this with out using cursor?
create table Table1 (ColA varchar(20), ColB varchar(20), ColC varchar(20))
insert into Table1 values (1, null, null)
create table Table2 (ColA varchar(20), ColB varchar(20), ColValue varchar(20))
insert into Table2 values (1, 2, 'X'), (1, 3, 'Y')
update Table1
set ColB = case
when T1.ColB = 2
then T1.ColValue
else T0.ColB
end,
ColC = case
when T1.ColB = 3
then T1.ColValue
else T0.ColC
end
from Table1 T0
inner join Table2 T1 on T0.ColA = T1.ColA
select * from Table1
Looking at the result, the statement has updated only ColB
UPDATE Table1
SET ColB = CASE WHEN T1.ColValue IS NOT NULL
THEN T1.ColValue
ELSE T0.ColB
END,
ColC = CASE WHEN T2.ColValue IS NOT NULL
THEN T2.ColValue
ELSE T0.ColC
END
FROM Table1 T0
INNER JOIN Table2 T1 ON T0.ColA = T1.ColA AND T1.ColB = 2
INNER JOIN Table2 T2 ON T0.ColA = T2.ColA AND T2.ColB = 3
Issue is : you are trying to update same row multiple times in the same query.
you can user Merge statement
refer
https://connect.microsoft.com/SQLServer/feedback/details/321926/merge-will-update-row-more-than-once-if-target-is-view-with-an-instead-of-trigger
There a number of ways that this could be done, here is one:
UPDATE t1
SET ColB = t2.ColValue
FROM Table1 AS t1
JOIN (SELECT * FROM Table2 WHERE Table2.ColB = 2) AS t2
ON t1.ColA = t2.ColA;
UPDATE t1
SET ColC = t2.ColValue
FROM Table1 AS t1
JOIN (SELECT * FROM Table2 WHERE Table2.ColB = 3) AS t2
ON t1.ColA = t2.ColA;
This does involve two passes over each table, but the syntax is very simple which is always a bonus.
If it is necessary to use a single statement try like this:
UPDATE t1
SET ColB = ISNULL((SELECT TOP 1 ColValue FROM Table2 WHERE Table2.ColA = t1.ColA AND Table2.ColB = 2), t1.ColB),
ColC = ISNULL((SELECT TOP 1 ColValue FROM Table2 WHERE Table2.ColA = t1.ColA AND Table2.ColB = 3), t1.ColC),
...
FROM Table1 AS t1;
Using ISNULL() to avoid updating where there is nothing in Table2.
I think this should do it:
update Table1
set ColB =
(
select max(case when t2.ColB = 2 then t2.ColValue else t1.ColB end)
from Table1 t1
inner join Table2 t2 on t1.ColA = t2.ColA
),
ColC =
(
select max(case when t2.ColB = 3 then t2.ColValue else t1.ColB end)
from Table1 t1
inner join Table2 t2 on t1.ColA = t2.ColA
)
Related
I have an SQL table that looks as follows:
col1 col2
a b
b a
c d
d c
f g
As you can see there are rows where both columns col1 and col2 are inverted. What I mean is that in the first row the values a and b are in both columns and in row 2 the values are also there, but the other way round.
I now want to delete one row of each of these pairs. I do not care which side of the pair is deleted. So either row 1 and row 3 or row 2 and row 4 should be deleted.
The result should looks as follows:
col1 col2
a b
c d
f g
or
col1 col2
b a
d c
f g
I achieved this with the following query that creates two artificial columns that contain the values in a sorted order and then applies a GROUP BY, but I assume there should be a nicer looking solution.
DELETE t1
FROM testtable t1
INNER JOIN (
SELECT CASE WHEN col1 < col2 THEN col1 ELSE col2 END AS first,
CASE WHEN col1 < col2 THEN col2 ELSE col1 END AS second
FROM testtable
GROUP BY CASE WHEN col1 < col2 THEN col1 ELSE col2 END, CASE WHEN col1 < col2 THEN col2 ELSE col1 END
) t2 ON t2.first = t1.col1 AND t2.second = t1.col2
I think you can simplify your query by adding conditions to the join:
DELETE T1
FROM #testable T1
INNER JOIN #testable T2 ON T1.col1 = T2.col2 AND T1.col2 = T2.col1 AND T1.col1 > T1.col2
You can use exists & not exists :
select t.*
from testtable t
where exists (select 1
from testtable t1
where t1.col1 > t.col1 and t1.col1 = t.col2
) or
not exists (select 1
from testtable t1
where t1.col1 < t.col1 and t1.col1 = t.col2
);
If you want to remove unwanted records then you can do :
delete t
from testtable t
where not exists (select 1
from testtable t1
where t1.col1 > t.col1 and t1.col1 = t.col2
) and
exists (select 1
from testtable t1
where t1.col1 < t.col1 and t1.col1 = t.col2
);
Assuming no actual duplicates, I would do:
delete t from testtable t
where col1 > col2 and
exists (select 1
from testtable t2
where t2.col1 = t.col2 and t2.col2 = t.col1
);
That is, delete the rows where col1 > col2 but only if the "paired" row already exists in the table.
I have 2 tables and structure is same on both tables.
Table 1:
ID Name Phone
1 xxx 111
2 yyy 222
Table 2:
ID Name Phone
1 xxx 111
3 zzz 333
I need to compare these two tables and display the results (based on ID column- where condition ID) as
Available in both tables
Table1 only
Table2 only
This should be like this,
ID Name Phone Status
----------------------------------------
1 xxx 111 Available in both
2 yyy 222 Available in T1 only
3 zzz 333 Available in T2 only
using HASHBYTES :Demo Here ..you dont need to consume table mutiple times,but only once
;with cte
as
(
select id,name,phone,hashbytes('sha1',concat(id,name,phone) )as tb1
from #t1
)
select isnull(c.id,b.id) as id,
isnull(c.name,b.name) as name,
isnull(c.phone,b.phone) as phone,
case when c.tb1 is null then 'exists in second table only'
when c.tb1 is not null and b.tb1 is not null then 'exists in both'
when b.tb1 is null then 'exists in first table only'
end as 'exidts' from cte c
full join
(
select id,name,phone,hashbytes('sha1',concat(id,name,phone) )as tb1
from #t2
) b
on
b.tb1=c.tb1
Try this:
declare #table1 table
(
name varchar(10),
phone varchar(10)
)
declare #table2 table
(
name varchar(10),
phone varchar(10)
)
INSERT INTO #table1 VALUES('xxx','111')
INSERT INTO #table1 VALUES('yyy','222')
INSERT INTO #table2 VALUES('xxx','111')
INSERT INTO #table2 VALUES('zzz','333')
SELECT t1.name, t1.phone, 'Available on both' FROM
#table1 t1 INNER JOIN #table2 t2
ON t1.name = t2.name and t1.phone = t2.phone
UNION
SELECT name, phone, 'Available on T1 only' FROM
#table1 t1 WHERE NOT EXISTS
(SELECT 1 FROM #table2 t2
WHERE t1.name = t2.name and t1.phone = t2.phone)
UNION
SELECT name, phone, 'Available on T2 only' FROM
#table2 t2 WHERE NOT EXISTS
(SELECT 1 FROM #table1 t1
WHERE t1.name = t2.name and t1.phone = t2.phone)
You can use combination of FULL JOIN and IS NULL to check availability from both tables -
SELECT ISNULL(t1.id, t2.id) AS Id
, ISNULL(t1.name, t2.name) AS Name
, ISNULL(t1.phone, t2.phone) AS Phone
, CASE
WHEN t1.id IS NULL THEN 'Available in T2 only'
WHEN t2.id IS NULL THEN 'Available in T1 only'
ELSE 'Available in both'
END AS Status
FROM Table1 AS t1
FULL JOIN Table2 AS t2 ON (t2.id = t1.id);
As this query uses only one JOIN operation and no sub queries it is very fast.
This could work:
CREATE TABLE #T1 ( ID INT, Name VARCHAR(10), Phone VARCHAR(10) )
CREATE TABLE #T2 ( ID INT, Name VARCHAR(10), Phone VARCHAR(10) )
INSERT INTO #T1 VALUES ( 1, 'xxx', '111' ), ( 2, 'yyy', '222' )
INSERT INTO #T2 VALUES ( 1, 'xxx', '111' ), ( 3, 'zzz', '333' )
SELECT #T1.ID, #T1.Name, #T1.Phone, 'Available on both' AS Status
FROM #T1 INNER JOIN #T2 ON #T1.ID = #T2.ID
UNION
SELECT #T1.ID, #T1.Name, #T1.Phone, 'Available on T1 only' AS Status
FROM #T1 LEFT JOIN #T2 ON #T1.ID = #T2.ID
WHERE #T2.ID IS NULL
UNION
SELECT #T2.ID, #T2.Name, #T2.Phone, 'Available on T2 only' AS Status
FROM #T1 RIGHT JOIN #T2 ON #T1.ID = #T2.ID
WHERE #T1.ID IS NULL
DROP TABLE #T1
DROP TABLE #T2
I have a Select with sub selects using Top 1 and where clause.
I tried to optimize the select by doing a Left Join of the sub selects but the query time took longer. Is subselect better in this case? I couldnt post my whole select because it is too long and confidential but I will try to recreate the important part below:
Sub Select
SELECT
(select top 1 colId FROM table1 WHERE col1 = b.Id and col2 = 3 Order by 1) Id3,
(select top 1 colId FROM table1 WHERE col1 = b.Id and col2 = 5 Order by 1) Id5,
(select top 1 colId FROM table1 WHERE col1 = b.Id and col2 = 7 Order by 1) Id7
FROM table2 b
Trying it w/ Left Join
SELECT
t1.colid id3,
t2.colid id5,
t3.colid id7
FROM table2 b
LEFT JOIN (
select colId, col1 FROM table1 WHERE col2 = 3
) t1 ON t1.col1 = b.Id
LEFT JOIN (
select colId, col1 FROM table1 WHERE col2 = 5
) t2 ON t1.col1 = b.Id
LEFT JOIN (
select colId, col1 FROM table1 WHERE col2 = 7
) t3 ON t1.col1 = b.Id
Is there a better way to do this? and why is it the Left join takes longer query time?
You can use ROW_NUMBER:
;WITH cte AS
(
SELECT a.colId,
rn = ROWN_NUMBER() OVER (PARTITION BY a.col2 ORDER BY a.col1)
FROM table1 a
LEFT JOIN table2 b on a.col1 = b.id
WHERE a.col2 IN (3,5,7)
)
SELECT *
FROM cte
WHERE rn = 1
This will give you the first row for each col2 value and you can restrict the values you want to 3,5,7.
I have 2 tables here:
table1
id name idfrom idto
1 test 2 3
2 test3 1 9
table2
id branch status
2 a from
1 b from
9 c to
3 d to
How do I select branch from table2 and table1 based on status in table2?
I want the result to look like this:
id name branchfrom branchto
1 test a d
2 test3 b c
I answer it doesn't mean I like it.
SELECT id, name, bfrom.branch branchfrom, bto.branch branchto
FROM table1 t1
INNER JOIN (SELECT id, branch
FROM table2
WHERE status = 'from') bfrom
ON t1.idfrom = bfrom.id
INNER JOIN (SELECT id, branch
FROM table2
WHERE status = 'to') bto
ON t1.idto = bto.id;
I use INNER JOIN as sample only. You must adjust with your requirement (which you didn't clearly specify).
Something like the following should do (assuming you're wanting to join on id in both tables):
select t1.id, t1.name, f.branch as branchfrom, t.branch as branchto
from table1 as t1
join table2 as f
on f.id = t1.id
and f.status = 'from'
join table2 as t
on t.id = t1.id
and t.status = 'to'
This should work for you:
select t1.id, t1.name, f.branch as branchfrom, f1.branch as branchto
from table1 as t1
join table2 as f
on t1.idfrom = f.id
join table2 as f1
on t1.idto = f1.id
Please see here for demo: SQL Fiddle Demo
I don't know if this is better or worse than what the other two people have suggested but
select
t1.name,
(select
t2.branch
from
table2 t2
where
t1.idfrom = t2.id
) as branchfrom,
(select
t2.branch
from
table2 t2
where
t1.idto = t2.id
) as branchto
from
table1 t1
Here is a fiddle
Use this Code:
CREATE TABLE #table1 (
id int,
name varchar(10),
idfrom int,
idto int
)
CREATE TABLE #table2 (
id int,
branch char,
statuss varchar(10)
)
INSERT INTO #table1
VALUES (1, 'test', 2, 3)
INSERT INTO #table1
VALUES (2, 'test3', 1, 9)
INSERT INTO #table2
VALUES (2, 'a', 'From')
INSERT INTO #table2
VALUES (1, 'b', 'From')
INSERT INTO #table2
VALUES (9, 'c', 'to')
INSERT INTO #table2
VALUES (3, 'd', 'to')
SELECT
a.id,
a.name,
(SELECT
b.branch
FROM #table2 b
WHERE a.idfrom = b.id
AND b.statuss = 'FROM')
AS BranchFrom,
(SELECT
b.branch
FROM #table2 b
WHERE a.idto = b.id
AND b.statuss = 'to')
AS BranchTo
FROM #table1 a
I am getting error in the below sql query.
if count is >1 i need to execute when statement, if not else statement.
SELECT CASE
WHEN (COUNT(VALUE) FROM TABLE1 WHERE ID=111)>1 )
THEN
SELECT VALUE FROM TABLE2 WHERE ID=111
ELSE
SELECT 2
Please help
Try this:
if (select count(*) from table1 where id = 111 group by id) > 1
select value from table2 where id = 111
else
select 2
Demo
The same thing, written using case when...
select
case
when (select count(*) from table1 where id = 111 group by id) > 1 then value
else 2
end
from table2
where id = 111
Try this sample code
DECLARE #Table1 TABLE
(
id INT,
value INT
)
INSERT #Table1
VALUES(1,
10)
INSERT #Table1
VALUES(2,
20)
DECLARE #TABLE2 TABLE
(
id INT,
c2 INT
)
INSERT #TABLE2
VALUES(1,
11 )
INSERT #TABLE2
VALUES(2,
22 )
SELECT CASE
WHEN (SELECT count(value)
FROM #Table1) > 0 THEN (SELECT T2.c2
FROM #TABLE2 T2
WHERE T1.id = T2.id)
ELSE (SELECT T2.id
FROM #TABLE2 T2
WHERE T1.id = T2.id)
END
FROM #Table1 t1
IF EXISTS(SELECT TOP 1 1 FROM TABLE1 WHERE ID='111' HAVING COUNT(VALUE)>1)
BEGIN
SELECT VALUE FROM TABLE2 WHERE ID=111
END
ELSE
BEGIN
SELECT 2
END