Joining tables without a common column in sql server - sql-server

TABLE1
ID
----
1
2
3
4
5
TABLE2
Name
----
Z
Y
X
W
V
Expected Output:
ID Name
-------------------------
1 NULL
2 NULL
3 NULL
4 NULL
5 NULL
NULL Z
NULL Y
NULL X
NULL W
NULL V
I need a solution for the above scenario by using JOINS in SQL Server.

Using FULL OUTER JOIN, you can get the expected result.
Since there are no common fields, no records from Table1 should match with Table2 and vice versa. So perhaps ON 0 = 1 as the join condition also will work as expected. Thanks Bart Hofland
So the query below also will work:
SELECT T1.Id, T2.[Name]
FROM Table1 T1
FULL OUTER JOIN Table2 T2 ON 0 = 1;
or
SELECT T1.Id, T2.[Name]
FROM Table1 T1
FULL OUTER JOIN Table2 T2 ON T2.[Name] = CAST(T1.Id AS VARCHAR(2));
Demo with the sample data:
DECLARE #Table1 TABLE (Id INT);
INSERT INTO #Table1 (Id) VALUES
(1),
(2),
(3),
(4),
(5);
DECLARE #Table2 TABLE ([Name] VARCHAR(1));
INSERT INTO #Table2 ([Name]) VALUES
('Z'),
('Y'),
('X'),
('W'),
('V');
SELECT T1.Id, T2.[Name]
FROM #Table1 T1
FULL OUTER JOIN #Table2 T2 ON 0 = 1;
Output:
Id Name
-----------------
1 NULL
2 NULL
3 NULL
4 NULL
5 NULL
NULL Z
NULL Y
NULL X
NULL W
NULL V

I don't understand why you'd want this, but to get your expected results you could do this. This is not a join, though.
SELECT ID, NULL as NAME from Table1
UNION ALL
SELECT NULL, NAME from Table2
Edited to add
Since the question specifically requests a solution with a join, Arulkumar's answer of FULL OUTER JOIN is a better fit, and you don't have to worry about what the column data types are.

Related

Counting from 2 tables

I have 2 tables.
A
Id Name
1 ab
2 cd
3 eg
4 fg
B
FkID
1
2
2
1
1
2
4
Since 3 is not there in B in the FKID column. I need to find the count in table A which has value in table B which have a value in FKID also.
So th total count should be 3. In my query, I am getting 7 after the left join.
You don't need a join, you can do it with EXISTS:
select count(*) from a
where exists (
select 1 from b
where b.fkid = a.id
)
I believe EXISTS is more efficient than a join, but if you need a join then it has to be an INNER JOIN like this:
select count(distinct a.id)
from a inner join b
on b.fkid = a.id
Using COUNT(DISTINCT B.FkId) the result can be achiveable. The COUNT is not considering the NULL values, so the following query will work.
SELECT COUNT(DISTINCT B.FkId) AS Occurence
FROM TableA A
LEFT JOIN TableB B ON B.FkId = A.Id;
or it can be achiveable with INNER JOIN too
SELECT COUNT(DISTINCT B.FkId) AS Occurence
FROM TableA A
INNER JOIN TableB B ON B.FkId = A.Id;
Demo with sample data:
DECLARE #TableA TABLE (Id INT, [Name] VARCHAR (2));
INSERT INTO #TableA (Id, [Name]) VALUES
(1, 'ab'),
(2, 'cd'),
(3, 'eg'),
(4, 'fg');
DECLARE #TableB TABLE (FkId INT);
INSERT INTO #TableB (FkId) VALUES
(1),
(2),
(2),
(1),
(1),
(2),
(4);
SELECT COUNT(DISTINCT B.FkId) AS Occurence
FROM #TableA A
LEFT JOIN #TableB B ON B.FkId = A.Id

SQL Server - Can someone explain this Query?

I have a query that I can't understand. Can someone explain to me what is going on with all these commas ?
SELECT * FROM TABLE1
LEFT OUTER JOIN TABLE2 ON TABLE1.Column1 = TABLE2.Column1,
TABLE3, TABLE4, TABLE5, TABLE6
WHERE [...]
I don't get the part where a bunch or tables are listed. I figured out by the WHERE part that it was bound or at least used like in a "FROM" use. Can someone explain to me what is it and the name or at least have a link to the documentation of this form of link ?
Thanks a lot.
This means you Are Joining TABLE1 and TABLE2 using LEFT JOIN
So If there is a Matching value in TABLE2.Column1 for TABLE1.Column1 that Value will be displayed and if there is no Match, then the Column Will be there but Value will be NULL
For all other Tables, you are using a CROSS JOIN. So It will create a Cartesian Product with the Records obtained from the First Join
DECLARE #TABLEA TABLE
(
ColA INT
)
DECLARE #TABLEB TABLE
(
ColB INT
)
DECLARE #TABLEC TABLE
(
ColC INT
)
DECLARE #TABLED TABLE
(
ColD INT
)
INSERT INTO #TABLEA
VALUES(1),(2),(3)
INSERT INTO #TABLEB
VALUES(4),(5),(6)
INSERT INTO #TABLEC
VALUES(7),(8),(9)
INSERT INTO #TABLED
VALUES(10)
SELECT
*
FROM #TABLEA A
LEFT JOIN #TABLEB B
ON A.ColA = B.ColB
,#TABLEC,#TABLED
In the above Example, TableA and TableB are LEFT JOINed and then TABLEC AND TABLED are Cross Joined with the Result. So my Final Output will be
ColA ColB ColC ColD
----------- ----------- ----------- -----------
1 NULL 7 10
1 NULL 8 10
1 NULL 9 10
2 NULL 7 10
2 NULL 8 10
2 NULL 9 10
3 NULL 7 10
3 NULL 8 10
3 NULL 9 10
You Can Filter the Records from any of the tables using the WHERE Clause

Combine two tables into one table with separated values

This is a simple rather simple question, but for whatever reason I just can't get to a solution.
How do I join the two tables like such that I have get NULL values like this?
Table #T1
A
--
1
2
Table #T2
B
--
3
Desired result:
A B
----
1 NULL
2 NULL
NULL 3
EDIT:
My solution was this
SELECT #T1.A, #T2.B
FROM #t2
RIGHT JOIN #T1 ON 1 = 0
UNION
SELECT #T1.A, #T2.B
FROM #t2
LEFT JOIN #t1 ON 1 = 0
But it seems overly complicated. Anything better?
Use FULL JOIN
select *
from #t1 t1
full outer join #t2 t2 on t1.a = t2.b
or use UNION ALL
select a,Null as b
from #t1
union all
select NULL, b
from #t2
since there is no common records in both the tables, both the query results will look same. When there is a common record, the result will differ. Use the one that suits your requirement
This is the better/simple one
SELECT #T1.A, #T2.B
FROM #t2
FULL OUTER JOIN #T1 ON 1 = 0

Why does UNION returns only one null?

I understand null represents missing/unknown value, so a null is not equal to another null because two unknown things cannot be compared. For example
if null = null
select 'nulls are equal'
else
select 'nulls are not equal'
results in 'nulls are not equal' I used an = instead of is null or is not null here to emphasize the fact that two nulls cannot be compared.
Coming to UNION, UNION is supposed to eliminate duplicate values. I was expecting the below code to return two rows each with null since two null values are not equal, but I get only one null in the result set.
(select null as Col1)
union
(select null as Col1)
Why does SQL's interpretation of 'null as an unknown value' change in above two statements?
NULL is not comparable, but SQL generally does have the concept of "IS DISTINCT FROM"
SQL Server has a Connect item for it
1 IS DISTINCT FROM NULL = true
1 = null is false
For completeness, NULL IS DISTINCT FROM NULL = false
I would guess that DISTINCT and UNION use IS DISTINCT FROM (as Pரதீப் mentioned above)
Now, SQL Server does have IS DISTINCT FROM in INTERSECT and EXCEPT
DECLARE #t1 TABLE (t1col INT);
INSERT #t1 VALUES (1), (NULL), (2), (3), (3), (5), (5);
DECLARE #t2 TABLE (t2col INT);
INSERT #t2 VALUES (1), (NULL), (3), (4);
SELECT DISTINCT 't1 EXISTS t2', *
FROM #t1 t1 WHERE EXISTS (SELECT * FROM #t2 t2 WHERE t1.t1col = t2.t2col);
t1 EXISTS t2 1
t1 EXISTS t2 3
t1 EXISTS t2 3
SELECT DISTINCT 't1 INTERSECT t2', *
FROM #t1 INTERSECT SELECT 't1 INTERSECT t2', * FROM #t2;
t1 INTERSECT t2 NULL
t1 INTERSECT t2 1
t1 INTERSECT t2 3
INTERSECT and EXCEPT also remove duplicates because they do a semi-join
EXISTS is an anti-join BTW
For completeness
SELECT 't1 EXISTS t2', *
FROM #t1 t1 WHERE NOT EXISTS (SELECT * FROM #t2 t2 WHERE t1.t1col = t2.t2col);
t1 EXISTS t2 NULL
t1 EXISTS t2 2
t1 EXISTS t2 5
t1 EXISTS t2 5
SELECT 't1 EXCEPT t2', *
FROM #t1 EXCEPT SELECT 't1 EXCEPT t2', * FROM #t2;
t1 EXCEPT t2 2
t1 EXCEPT t2 5
Example taken from my answer Why does EXCEPT exist in T-SQL? with added NULLs
UNION is basically SELECT DISTINCT, so it would be eliminating duplicate NULL values, but it's not the same as Equal operation.
Using UNION ALL would give you all records including duplicating NULLs.
As for the first part of you question. NULL really equals NULL, but not with "=". This would give you result you expect:
if null IS null
select 'nulls are equal'
else
select 'nulls are not equal'
This is also helpful when dealing with nulls.
Try UNION ALL to retain everything in both sets without removing duplicates.

SQL Server stored procedure select, exists, multiple tables

Any method to do this?
Table1
1
2
3
4
5
Table2
3 (with the condition)
4 (without the condition)
I want to:
Select all records from Table1 if it exists in Table 2, where...(condition)
Select all records from Table1 if it not exists in Table2
Combine both select results. Sort all results with their created date.
For example, the result should be:
Result
1
2
3
5
Hopefully this can help.
SELECT t1.* from table1 t1
JOIN table2 t2
ON t1.ID = t2.ID
UNION ALL
SELECT t1.* from table1 t1 where ID in
(
SELECT t2.ID from table1 t1 except Select t2.ID from table2 t2
)
ORDER BY t1.CreatedDate
You can achieve this by doing:
SELECT t1.id
FROM Table1 t1
LEFT JOIN Table2 t2 on t1.id = t2.id
WHERE condition OR t2.id IS NULL
ORDER BY t1.CreatedDate;
See fiddle (I assumed condition to be t2.id!=4, but it can be anything else depending on other data in your tables).
There could be multiple solution.
One way
we can get the result set using two different queries and at last combine both of the result-set using UNION
Another way,
First statement is saying that get all the result set from TABLE1 if it exists in TABLE2 as well with some criteria (condition in where clause)
means using INNER JOIN we can achieve this
Second statement is saying get all the result set from TABLE1 which are not present in TABLE2
means along with INNER JOIN ed query also include the TABLE1's data if not present in TABLE2
here we can take the help of LEFT OUTER JOIN (taking TABLE1 on the left side)
Assumption: (condition: t1.Id != 4)
Let's try to understand the query using both of the above mentioned ways
---- -- --Step1 Create table and insert records
---- create table1 with Id int identity columsn
--CREATE TABLE Table1 (Id INT IDENTITY(1,1), CreatedDate smalldatetime default(getdate()));
--go
---- insert 1st 5 integers into Table1
--INSERT INTO Table1 DEFAULT VALUES
--go 5
---- create Table2 with Id int column
--CREATE TABLE Table2 (Id INT , CreatedDate smalldatetime default(getdate()));
--go
---- insert records 3,5 into Table2
--INSERT INTO Table2(Id) VALUES (3), (4);
-- -- -- Solution: one way
; WITH cteMyFirstResult AS
(
-- 2.1. Select all records from Table1 if it exists in Table 2, where...(condition)
SELECT
Id, CreatedDate
FROM Table1 AS t1
WHERE t1.Id IN (SELECT Id FROM Table2 AS t2)
AND t1.Id != 4 -- assumption it can be any condition
),cteMySecondResult AS (
-- 2.2. Select all records from Table1 if it not exists in Table2
SELECT
Id, CreatedDate
FROM Table1 AS t1 WHERE t1.Id NOT IN (SELECT Id FROM Table2 AS t2)
)
-- 2.3. Combine both select results. Sort all results with their created date.
SELECT
Id, CreatedDate
FROM cteMyFirstResult
UNION
SELECT
Id, CreatedDate
FROM cteMySecondResult
ORDER BY CreatedDate;
-- -- Solution: Another way (with bug)
SELECT t1.Id, t1.CreatedDate
FROM Table1 AS t1
LEFT JOIN Table2 AS t2 on t1.id = t2.id
WHERE t1.Id != 4
Order by T1.CreatedDate;
-- in this query we are using the criteria after doing the join operation.
-- thus after filtering out the result set based on JOIN Condition this condition will get applied
-- and if there is any null record in the Table1 for column Id (used in join) will not come in the final result-set
-- to avoid this we can include NULL check along with our criteria
-- -- Solution: Another way
SELECT t1.Id, t1.CreatedDate
FROM Table1 AS t1
LEFT JOIN Table2 AS t2 on t1.id = t2.id
WHERE ( t1.Id != 4 ) OR t1.Id IS NULL -- include all your criteria within small-barcket)
Order by T1.CreatedDate;
Thanks for all responses.
I come out with the answer I want:
SELECT *
FROM Table1 t1
WHERE NOT EXISTS(SELECT 1 FROM Table2 t2
WHERE t1.ID = t2.ID
AND t2.CIF_KEY = #CifKey
AND t2.STATUS <> ''3'')
AND (condition in where clause)

Resources