conditional union multiple tables - sql

This is based on union tables on value
declare #t1 table (val int,datatype1 int,datatype2 int ,datatype3 int)
declare #t2 table (val int,datatype1 int ,datatype2 int ,datatype3 int )
declare #t3 table (val int,datatype1 int ,datatype2 int ,datatype3 int )
insert into #t1 values (10,1,0,0),(31,1,0,0),(20,1,0,0)
insert into #t2 values (31,0,1,0),(4,0,1,0)
insert into #t3 values (31,0,0,1),(5,0,0,1);
Below is the changes in requirement(case):
1. need to union #t1,#t2 & #t3
(if same value exist #t1 & #t2 multiple rows and #t2 & t3 only 1 row)
2. if any duplicate value (there is no chance dup in same table)
i) suppose 31 in #t1 , 31 in #t2 then multiple rows are allowed
ii) suppose 31 in #t2 & #t3 then only one records i.e #t3 updated to #t2
iii) if 31 in #t1 ,#t2,#t3 only 2 records i.e #t1,#t2 records with #t3 details updated to #t2 records
Now i) & iii) are working fine
select val,
max(datatype1) datatype1,
max(datatype2)datatype2,
max(datatype3)datatype3
from (
select 't1' AS tab_name, * from #t1
union all
select 't2' AS tab_name,* from #t2
union all
select 't3' AS tab_name,* from #t3
) as data
group by val, CASE WHEN tab_name in ('t2') THEN 1 END
order by val;
But Current Result showing multiple records for case 2 also any help
Expected Result:

Your question is very hard to follow. I'm a bit lost on the conditions, but this rather simple query returns the results that you specify:
select val,
max(datatype1) as datatype1,
max(datatype2) as datatype2,
max(datatype3) as datatype3,
max(datatype4) as datatype4
from (select 't1' AS tab_name, t1.* from t1
union all
select 't2' AS tab_name, t2.* from t2
union all
select 't3' AS tab_name, t3.* from t3
) data
group by val;
Here is a db<>fiddle.
I wonder if the culmination of all your results is a relatively simple aggregation.

Related

Update statement with Where Not Exists

I am trying to do the following:
Set the status column to 1 when the row in the first table (variable) does not exist in the second one.
I tried this:
update #table1
set status=1
where NOT EXISTS (select top 1 1 from #table2 where #table1.foo=#table2.foo)
But this doesn't even compile, not recognizing #table1 in the Where statement.
Must declare the scalar variable "#table1".
Any clue about this?
Your approach is fine. You just need table aliases because the # is used to in SQL Server to represent variables (scalars or tables) and is hence problematic for aliases:
update t1
set status = 1
from #table1 t1
where not exists (select 1 from #table2 t2 where t2.foo = t1.foo);
Note that the top 1 is unnecessary in the subquery.
You can do this kind of thing by joining the two tables with a LEFT JOIN and checking the right side for NULL:
UPDATE t1
SET t1.status=1
FROM #table1 t1
LEFT JOIN #table2 t2
ON t1.foo = t2.foo
WHERE t2.foo IS NULL
The specific error you got is because you haven't got a statement declaring #table1 as a table variable, like DECLARE #table1 TABLE (foo int) for example. If table1 is not a variable, you don't need the #.
no need any top inside scaler query
update #table1
set status=1
where NOT EXISTS (select 1 from #table2 where #table1.foo=#table2.foo)
cause exists return boolean
you could use below query
update #table1
set status=1
where #table1.foo not in ( select foo from #table2 where foo is not null)
There are multiple ways - inner query with NOT IN and NOT EXISTS and JOIN query:
update tab1 set status = 1 where name not in (select name from tab2);
update tab1 set status = 1 where not exists (select 1 from tab2 where tab1.name=tab2.name);
update tab1 set status = 1 from tab1 left outer join tab2 on tab1.name = tab2.name where tab2.name is null;
Sample schema to run above queries;
create table tab1(name varchar(30), status int);
create table tab2(name varchar(30));
insert into tab1 values('a', 5);
insert into tab1 values('b', 6);
insert into tab1 values('c', 7);
insert into tab1 values('d', 8);
insert into tab2 values('a');
insert into tab2 values('d');
You have to declare table1 and table2 variables
DECLARE #table1 YOUR_TABLE1_NAME;
DECLARE #table2 YOUR_TABLE2_NAME;
update #table1
set status=1
where NOT EXISTS (select top 1 from #table2 where #table1.foo=#table2.foo)
You should use alias name for both table.
DECLARE #TABLE_1 TABLE (DEPT_NAME VARCHAR(50),DEP_ID INT)
INSERT INTO #TABLE_1(DEPT_NAME,DEP_ID)
SELECT 'IT',1 UNION ALL
SELECT 'HR',2 UNION ALL
SELECT 'ACCOUNT',3 UNION ALL
SELECT 'ADMIN',4 UNION ALL
SELECT 'SALES',5 UNION ALL
SELECT 'CEO',7
DECLARE #TABLE_2 TABLE (E_ID INT,EMP_NAME VARCHAR(50),DEP_ID INT)
INSERT INTO #TABLE_2(E_ID,EMP_NAME,DEP_ID)
SELECT 1,'JHON',1 UNION ALL
SELECT 2,'LITA',2 UNION ALL
SELECT 3,'MATT',1 UNION ALL
SELECT 4,'JEFF',1 UNION ALL
SELECT 5,'BROCK',2 UNION ALL
SELECT 6,'BOB',5 UNION ALL
SELECT 7,'SAM',4 UNION ALL
SELECT 8,'DAVID',3 UNION ALL
SELECT 9,'JACK',1 UNION ALL
SELECT 10,'GARY',4 UNION ALL
SELECT 11,'DONALD',6
SELECT * FROM #TABLE_1 A WHERE NOT EXISTS (SELECT DEP_ID FROM #TABLE_2 B WHERE A.DEP_ID=B.DEP_ID )

Full Outer Join Using Each Row Once

I'm wondering if anyone's come across a neat solution to this problem. I'm trying to select data from a couple of tables, having the records match up row by row. I'm basically after a full outer join, but there's one crucial difference. If I have four rows with a particular value in the column I'm joining on in one table, and three rows with this value in another, I only want the first three results to be joined, and the fourth to act as if there had been no match.
The reason for this is to create a reconciliation report which ensures transactions are not counted multiple times when comparing results. I can get around this issue by using a bit of grouping and some aggregate functions, but this hides some of the detail which I'd like to keep.
Below is an example to show the sort of thing I'm after, with the invalid/pseudo code in the comments illustrating how I'm thinking of this as working:
declare #t1 table (id bigint identity(1,1) primary key clustered, foreignKeyId bigint, otherData nvarchar(10))
declare #t2 table (id bigint identity(1,1) primary key clustered, foreignKeyId bigint, moreData nvarchar(10))
insert #t1 select 1, '1.1.1'
union all select 1, '1.1.2'
union all select 1, '1.1.3'
union all select 3, '1.3.1'
union all select 3, '1.3.2'
union all select 3, '1.3.3'
union all select 4, '1.4.3'
insert #t2 select 1, '2.1.1'
union all select 1, '2.1.2'
union all select 1, '2.1.3'
union all select 2, '2.2.1'
union all select 3, '2.3.1'
union all select 3, '2.3.2'
union all select 5, '2.5.1'
union all select 5, '2.5.2'
--demo of the functionality i'm hoping to acheive
--
/*
select t1.id id1
, t2.id id2
, t1.foreignKeyId fk1
, t2.foreignKeyId fk2
, t1.otherData otherData
, t2.moreData moreData
from #t1 t1
full funky join #t2 t2
on t1.foreignKeyId = t2.foreignKeyId
order by t1.id, t2.id --we'd need an order by to ensure the match could be applied in a predictable manner
*/
--
declare #funkyjoin table (id1 bigint, id2 bigint, fk1 bigint, fk2 bigint, otherData nvarchar(10), moreData nvarchar(10))
declare #id1 bigint, #id2 bigint
insert #funkyjoin (id1, fk1, otherData)
select id, foreignKeyId, otherData from #t1
while exists(select 1 from #t2)
begin
select top 1 #id2 = id from #t2 order by id
set #id1 = null
select top 1 #id1 = id1
from #funkyjoin
where fk2 is null
and fk1 in (select foreignKeyId from #t2 where id = #id2)
if #id1 is null
begin
insert #funkyjoin (id2, fk2, moreData)
select id, foreignKeyId, moreData
from #t2
where id = #id2
end
else
begin
update #funkyjoin
set id2 = #id2
, fk2 = fk1 --since we're joining on this we can just match it
, moreData = (select moreData from #t2 where id = #id2)
where id1 = #id1
end
delete from #t2 where id = #id2 --since this is only an example let's not worry about keeping our source data
end
select *
from #funkyjoin
order by coalesce(id1, id2)
I've written a similar solution for when this scenario occurs on spreadsheets previously: http://officemacros.codeplex.com/#WorksheetMergeMacro
If I understand correctly, this may be what you're after:
select *
from (
select *,
row_number() over (partition by foreignKeyId order by id) as n
from #t1
) t1
full outer join (
select *,
row_number() over (partition by foreignKeyId order by id) as n
from #t2
) t2 on t1.foreignKeyId = t2.foreignKeyId and t1.n = t2.n
The best way to use up the rows is to add a pseudo-row number (using ROW_NUMBER) and include that in the join.

interesting t-sql exercise

I am trying to resolve t-sql exercise
I need to update first table with values from second by joining by id. If I can not join then use value from default ID (default iD is the Id that is null)
please run it to see it
declare #t as table (
[id] INT
,val int
)
insert into #t values (null, null)
insert into #t values (2, null)
insert into #t values (3, null)
insert into #t values (4, null)
declare #t2 as table (
[id] INT
,val int
)
insert into #t2 values (null, 11)
insert into #t2 values (2, 22)
insert into #t2 values (3, 33)
select * from #t
select * from #t2
update t
set t.val = t2.val
from #t as t join #t2 as t2
on t.id = t2.id
or
(
(t.id is null or t.id not in (select id from #t2))
and t2.id is null
)
select * from #t
here is result
--#t
id val
---------------
NULL NULL
2 NULL
3 NULL
4 NULL
--#t2
id val
---------------
NULL 11
2 22
3 33
--#t after update
id val
---------------
NULL 11
2 22
3 33
4 NULL
how to make val in last row equal 11?
4 11
This solution left joins to t2 twice and then does a coalesce.
The ON on the second join matches on records that failed on the join and then looks for the "Default" case.
UPDATE t
set t.val = COALESCE(t2.val,t3.val)
from #t as t
LEFT join #t2 as t2
on t.id = t2.id
LEFT JOIN #t2 t3
ON t2.id is null and t3.id is null
See it working here
try this for the update...
update t
set t.val = t2.val
from #t as t join #t2 as t2
on t.id = t2.id
or
(
(t.id is null or not exists (select * from #t2 where id = t.id))
and t2.id is null
)
Problem is with not in operator and null values. This would also work...
update t
set t.val = t2.val
from #t as t join #t2 as t2
on t.id = t2.id
or
(
(t.id is null or t.id not in (select id from #t2 where id is not null))
and t2.id is null
)
Here's a technique that may help.
Start with the kind of simple code you want to be writing:
MERGE INTO #t AS target
USING source
ON target.id = source.id
WHEN MATCHED THEN
UPDATE
SET val = source.val;
Then write a table expression (source) that satisfies the requirements.
Requirement 1: "joining by id"
-- simple existential quantification e.g.
SELECT id, val
FROM #t2 AS T2
WHERE id IN ( SELECT id FROM #t )
Requirement 2: "If I can not join then use value from default ID (default iD is the Id that is null)"
-- first find the id values in the target that do not exist in the source:
SELECT id
FROM #t
EXCEPT
SELECT id
FROM #t2
then cross join the result with the row from the source where Id is null:
SELECT DT1.id, T2.val
FROM ( SELECT id
FROM #t
EXCEPT
SELECT id
FROM #t2 ) AS DT1,
#t2 AS T2
WHERE T2.id IS NULL
At this point you will want to query some test data to ensure each query satisfies its respective requirement.
Union the above two results to form a single table expression:
SELECT id, val
FROM #t2 AS T2
WHERE id IN ( SELECT id
FROM #t )
UNION
SELECT DT1.id, T2.val
FROM ( SELECT id
FROM #t
EXCEPT
SELECT id
FROM #t2 ) AS DT1,
#t2 AS T2
WHERE T2.id IS NULL
Then plug the table expression into the MERGE boilerplate code:
WITH source
AS
(
SELECT id, val
FROM #t2 AS T2
WHERE id IN ( SELECT id
FROM #t )
UNION
SELECT DT1.id, T2.val
FROM ( SELECT id
FROM #t
EXCEPT
SELECT id
FROM #t2 ) AS DT1,
#t2 AS T2
WHERE T2.id IS NULL
)
MERGE INTO #t AS target
USING source
ON target.id = source.id
WHEN MATCHED THEN
UPDATE
SET val = source.val;

return true if all the the records of first table exists in second table

i have two table:
declare #t1 table (id int)
declare #t2 table (id int)
insert into #t1
select 1 union select 3 union select 7
insert into #t2
select 1 union select 3 union select 7 union select 9 union select 4
select count(*) from #t1 t inner join #t2 t1 on t.id = t1.id
i get the result for above query as 3. i need true or false if all the records in t1 exists in t2.
this is a simplified example of the real table structure. the real tables may have millions of records, so please let me know some optimized way of doing it
SELECT CASE
WHEN EXISTS (SELECT id
FROM #t1
EXCEPT
SELECT id
FROM #t2) THEN 0
ELSE 1
END
declare #t1 table (id int)
declare #t2 table (id int)
insert into #t1
select 1 union select 3 union select 7
insert into #t2
select 1 union select 3 union select 7 union select 9 union select 4
if exists(
select id from #t2
except
select id from #t1
) print 'false'
else print 'all the records in t1 exists in t2'
Using exists (probably, it would be more efficient):
select
case
when not exists (select 1
from #t1 t1
where not exists(select 1 from #t2 t2 where t2.id = t1.id))
then cast(1 as bit)
else cast(0 as bit)
end
SELECT (CASE WHEN
(SELECT COUNT(*) from t1 where
not id IN (select id from t2)) = 0 THEN
convert(bit, 1)
ELSE convert(bit, 0) END)
Comparing count of matched rows to the total rows in #t1 may be more efficient. Sometimes you just need to try multiple methods and look at query plans to see which one works best in your situation. You'll need some test tables with a similar amount of data and proper indexes and such.
declare #t1 table (id int)
declare #t2 table (id int)
insert into #t1
select 1 union select 3 union select 7
insert into #t2
select 1 union select 3 union select 7 union select 9 union select 4
select case
when (select count(*) from #t1 t join #t2 t1 on t.id = t1.id) =
(select count(*) from #t1) then 1 else 0
end as rows_match

How to return table from T-SQL Stored Procedure

SQL Newbie here, and I'm having a hell of a time finding what should be a simple code example to answer what I think is a simple question.
I need to write a stored procedure that does three things in order:
1) Select rows from one table
2) Update rows in another table, using values from the results table in #1
3) Return the results table from #1.
What I can't find is any example about how to return a value like this from a stored procedure. Also, how to retrieve that returned table from the caller (which is another T-SQL script).
Have a look at this.
DECLARE #Table1 TABLE(
ID INT,
VAL int
)
INSERT INTO #Table1 (ID,VAL) SELECT 1, 1
INSERT INTO #Table1 (ID,VAL) SELECT 2, 2
INSERT INTO #Table1 (ID,VAL) SELECT 3, 3
DECLARE #Table2 TABLE(
ID INT,
VAL VARCHAR(MAX)
)
INSERT INTO #Table2 (ID,VAL) SELECT 1, 1
INSERT INTO #Table2 (ID,VAL) SELECT 2, 2
INSERT INTO #Table2 (ID,VAL) SELECT 3, 3
--Lets say this is the 2 tables
--now this will go into the sp
UPDATE #Table1
SET Val = t1.Val + t2.Val
FROM #Table1 t1 INNER JOIN
#Table2 t2 ON t1.ID = t2.ID
SELECT t1.*
FROM #Table1 t1 INNER JOIN
#Table2 t2 ON t1.ID = t2.ID
--and you can insert into a var table in the tsql script that calls the sp
DECLARE #Table1TSQL TABLE(
ID INT,
VAL int
)
INSERT INTO #Table1TSQL (ID,VAL) EXEC YourSP