is there a syntactic shortcut similar to coalesce for union? - sql

What I'm trying to do is:
select
A.Fuzz
,A.Fizz
,B.Whiz
from A
left outer join B
on A.Fuzzy B=Wuzzy
To replace:
select
A.Fuzz
,A.Fizz
,B.Whiz
from A
left outer join B
on A.Fuzzy B=Wuzzy
UNION ALL
select
B.wuzz
,A.Fizz
,B.Whiz
from A
left outer join B
on A.Fuzzy B=Wuzzy

May be this is something "near" what you think (done on MSSQL)?. Pls in every question post sample data, expected result, etc.
CREATE TABLE A (ID INT, DESC_A VARCHAR(10));
INSERT INTO A VALUES (1,'A');
INSERT INTO A VALUES (2,'B');
CREATE TABLE B (ID INT, DESC_B VARCHAR(10));
INSERT INTO B VALUES (2,'Z');
INSERT INTO B VALUES (3,'Y');
SELECT COALESCE(A.ID, B.ID) AS ID
, A.DESC_A
, B.DESC_B
FROM A
FULL JOIN B ON A.ID = B.ID
Output:
ID DESC_A DESC_B
1 A NULL
2 B Z
3 NULL Y

Related

What join to get all instances of a key shared by both tables?

What is the most efficient way to get the result with these two starting tables using T-SQL?
Table1
id
value1
1
A
2
B
Table2
id
value2
1
E
3
F
Desired result:
id
value1
value2
1
A
E
2
B
null
3
null
F
drop table if exists dbo.test1;
create table dbo.test1
(id int,
value1 varchar(50)
);
drop table if exists dbo.test2;
create table dbo.test2
(id int,
value2 varchar(50)
);
insert into dbo.test1
values
(1,'A'),
(2,'B');
insert into dbo.test2
values
(1,'E'),
(3,'F');
this works but seems very inefficient
Union all keys first, then join in the values from the other 2 tables
select p.id, a.value1, b.value2
from
(select id from test1
union
select id from test2) p
left join dbo.test1 a
on p.id = a.id
left join dbo.test2 b
on p.id = b.id
You can use FULL JOIN and COALESCE(), for SQL Server.
Example:
SELECT
COALESCE(a.id,b.id) AS id
,a.value1
,b.value2
FROM test1 AS a
FULL JOIN test2 AS b ON a.id = b.id
Fiddle https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=d1f62122bff5ca91fa31c25818cc58f7

Is there a way of this query working with JOINs or must I use a UNION?

I am probably trying to use JOINs for purposes they were not intended here.
Here's my (simplified) table structure:
Table A
ID
Table C ID
IsStatic (bit)
Table B
ID
Table A ID (nullable)
Table C ID
Table C
ID
My goal is to get all of Table B rows joined to Table A rows where Table B's Table A ID column has a value and equals Table A's ID column value.
I also need all of Table B rows where Table B's Table A ID column has no value.
I also need all of Table A rows with there were no joined Table B rows and Table A's IsStatic column is true.
Table C must also be associated with Table A or Table B. If Table B does not have a value for TableAID then it's value for TableCID should equal TableC's ID value. Otherwise TableA's TableCID should equal TableC's ID value.
Here's some SQL to create some TABLE variables and populate with sample data:
DECLARE #TableA TABLE (TableAID int, TableCID int, IsStatic bit)
DECLARE #TableB TABLE (TableBID int, TableAID int, TableCID int)
DECLARE #TableC TABLE (TableCID int)
INSERT INTO #TableC (TableCID) VALUES (1)
INSERT INTO #TableC (TableCID) VALUES (2)
INSERT INTO #TableA (TableAID, TableCID, IsStatic) VALUES (1, 1, 0)
INSERT INTO #TableA (TableAID, TableCID, IsStatic) VALUES (2, 2, 1)
INSERT INTO #TableA (TableAID, TableCID, IsStatic) VALUES (3, 2, 1)
INSERT INTO #TableA (TableAID, TableCID, IsStatic) VALUES (4, 2, 0)
INSERT INTO #TableB (TableBID, TableAID, TableCID) VALUES (1, NULL, 1)
INSERT INTO #TableB (TableBID, TableAID, TableCID) VALUES (2, 1, 1)
INSERT INTO #TableB (TableBID, TableAID, TableCID) VALUES (3, 2, 2)
Here's my (simplified) query that didn't quite work:
SELECT
a.TableAID,
b.TableBID
FROM #TableC c
LEFT OUTER JOIN #TableB b ON
(b.TableAID IS NOT NULL OR (b.TableAID IS NULL AND b.TableCID = c.TableCID))
LEFT OUTER JOIN #TableA a ON
a.TableCID = c.TableCID
AND ((a.IsStatic = 1 AND b.TableBID IS NULL)
OR (b.TableBID IS NOT NULL AND b.TableAID = a.TableAID))
The result of this query using the sampel data is:
TableAID TableBID
-----------------
NULL 1
1 2
NULL 3 (not required)
NULL 2 (not required)
2 3
The required result is:
TableAID TableBID
-----------------
NULL 1
3 NULL (missing)
2 3
1 2
Problem with this query is that if TableB.TableAID has no value then the Table A rows where TableA.IsStatic is true without any matching TableB rows are never included. Also some TableB rows are being included and they shouldn't be.
The only other way I can see of doing this is with a union with a not exists but I was hoping to do this in a more efficient way.
Update: Adding a WHERE clause removes the "not required" rows but still omits the missing row.
WHERE (b.TableBID IS NULL OR b.TableAID IS NULL OR b.TableAID = a.TableAID)
The result of the same query with the where clause is:
TableAID TableBID
-----------------
NULL 1
1 2
2 3
select b.TableAID, b.TableBID
from #TableB b
left join #TableA a on a.TableAID = b.TableAID
inner join #TableC c on c.TableCID = case when a.TableAID IS NULL then b.TableCID else a.TableCID end
union all
select a.TableAID, NULL
from #TableA a
inner join #TableC c on c.TableCID = a.TableCID
left join #TableB b on b.TableAID = a.TableAID
where b.TableAID is NULL
and a.IsStatic = 1
What a mind twister. I think that this is another way to express it. You'll have to see if the performance is good or not:
select a.TableAID, b.TableBID
from (select a.*
from #TableA a
join #TableC c
on c.TableCID = a.TableCID) a
full outer join (select b.*
from #TableB b
join #TableC c
on c.TableCID = b.TableCID) b
on b.TableAID = a.TableAID
where b.TableBID is not null or a.IsStatic = 1
I should also mention that it's hard to know for sure if the above query really respects your requirements using the sample data you provided. To illustrate, if I use this simplified query below that simply ignores the #TableC table, I still get the right results with your sample data:
select a.TableAID, b.TableBID
from #TableA a
full outer join #TableB b
on b.TableAID = a.TableAID
where b.TableBID is not null or a.IsStatic = 1
EDIT: Funny discussion in the comments about the interpretation of OP' requirements... But if I had to address Anton's point:
select a.TableAID, b.TableBID
from (select a.*,
case when c.TableCID is not null then 1 end as has_c
from #TableA a
left join #TableC c
on c.TableCID = a.TableCID) a
full outer join (select b.*,
case when c.TableCID is not null then 1 end as has_c
from #TableB b
left join #TableC c
on c.TableCID = b.TableCID) b
on b.TableAID = a.TableAID
where (b.TableBID is not null or a.IsStatic = 1)
and (a.has_c = 1 or b.has_c = 1)

Complement of a SQL Join? T-SQL help needed

I will try to make my question sound as unconfusing as possible. I appologize in advance for any wording mistakes as I try to phrase my question as best as I can:
Using T-SQL I need to write a join statement that gets me all the results that have a match in table A and table B
AND (!)
another join statement (or a continuation of the first join) that returns all the results from table A that DID NOT have a match in table B, BUT in this second result set I need to have one of the columns set to "N/A" to identify the records that didn't have a match.
In other words, I need something that would return everything in table A but would also identify the rows that weren't matched in B. That information is then used in a report.
Here is what I have so far:
I have the first part done:
LEFT OUTER JOIN dbo.chart B
ON B.UserName = A.user_name
That gets me the matching records and just the matching records
I tried adding this second join:
JOIN dbo.chart
ON NOT EXISTS (select * from B.UserName = A.user_name)
Hoping it would get me the non-matching records (I was planning to then use REPLACE on the column of interest to label that column "N/A") but there is something clearly wrong with my synthax as that generates exceptions.
My question is what do I need to change to get me the results you need. I do know that I need to have at least one join as I have other part of the query to work with. I just don't know if I need to have that one join return both sets of data of I actually do need a second one just for the non-matching records.
Hope this wasn't too confusing. Any help would be greatly appreciated.
Thank you!
Update: I would just like to emphasize that the reason I considered using a second join instead of getting all of the results at once is because I need to correctly identify and label those rows that weren't matched within everything that I get back.
I'm not sure where you are going with the second join. LEFT JOIN seems to do everything you want...
DECLARE #tableA TABLE (a_id INT) INSERT INTO #tableA VALUES (1), (2), (3), (4)
DECLARE #tableB TABLE (b_id INT) INSERT INTO #tableB VALUES (2), (3)
SELECT * FROM #tableA AS A LEFT JOIN #tableB AS B on A.a_id = b.b_id
a_id | b_id
------+------
1 | NULL
2 | 2
3 | 3
4 | NULL
Unless you mean that you're actually joining 3 tables together?
DECLARE #org TABLE (o_io INT) INSERT INTO #org VALUE (2), (3), (4)
DECLARE #tableA TABLE (a_id INT) INSERT INTO #tableA VALUES (1), (2), (3), (4)
DECLARE #tableB TABLE (b_id INT) INSERT INTO #tableB VALUES (2), (3)
SELECT
*
FROM
#org AS O
INNER JOIN
#tableA AS A
ON O.o_id = A.a_id
LEFT JOIN
#tableB AS B
ON A.a_id = b.b_id
o_id | a_id | b_id
------+------+------
2 | 2 | 2
3 | 3 | 3
4 | 4 | NULL
Sample data:
declare #TableA table
(
TableAID int,
TableAName varchar(10)
)
declare #TableB table
(
TableBID int,
TableBName varchar(10),
TableAID int
)
insert into #TableA values
(1, 'A 1'),
(2, 'A 2'),
(3, 'A 3')
insert into #TableB values
(1, 'B 1', 1),
(2, 'B 2', 2)
N/A instead of TableBName:
select A.TableAName,
coalesce(B.TableBName, 'N/A') as TableBName
from #TableA as A
left outer join #TableB as B
on A.TableAID = B.TableAID
Result:
TableAName TableBName
---------- ----------
A 1 B 1
A 2 B 2
A 3 N/A
Extra column for N/A:
select A.TableAName,
B.TableBName,
case when B.TableBID is null
then 'N/A'
else ''
end as TableBPresent
from #TableA as A
left outer join #TableB as B
on A.TableAID = B.TableAID
Result:
TableAName TableBName TableBPresent
---------- ---------- -------------
A 1 B 1
A 2 B 2
A 3 NULL N/A
Try using a union:
select A.id, b.id, b.desc from tablea A LEFT OUTER JOIN dbo.chart B
ON B.UserName = A.user_name
UNION
select a.id, 0, 'N/A' from tablea where NOT EXISTS (select * from B.UserName = A.user_name)

Parent Child Query without using SubQuery

Let say I have two tables,
Table A
ID Name
-- ----
1 A
2 B
Table B
AID Date
-- ----
1 1/1/2000
1 1/2/2000
2 1/1/2005
2 1/2/2005
Now I need this result without using sub query,
ID Name Date
-- ---- ----
1 A 1/2/2000
2 B 1/2/2005
I know how to do this using sub query but I want to avoid using sub query for some reason?
If I got your meaning right and you need the latest date from TableB, then the query below should do it:
select a.id,a.name,max(b.date)
from TableA a
join TableB b on b.aid = a.id
group by a.id,a.name
SELECT a.ID, a.Name, MAX(B.Date)
FROM TableA A
INNER JOIN TableB B
ON B.ID = A.ID
GROUP BY A.id, A.name
It's a simple aggregation. Looks like you want the highest date per id/name combo.
create table #t1 (id int, Name varchar(10))
create table #t2 (Aid int, Dt date)
insert #t1 values (1, 'A'), (2, 'B')
insert #t2 values (1, '1/1/2000'), (1, '1/2/2000'), (2, '1/1/2005'), (2, '1/2/2005')
;WITH cte (AId, MDt)
as
(
select Aid, MAX(Dt) from #t2 group by AiD
)
select #t1.Id, #t1.Name, cte.MDt
from #t1
join cte
on cte.AId = #t1.Id

Alternative to using subqueries in SQL statements?

I have two tables:
TableA: (a temporary table)
ItemId (int)
TableB:
ItemId (int), ParentID (int)
I want to retrieve all items in Table A where the ParentID of any of the items in Table A doesn't exist as an ItemID. (i.e. I want to get the root of the items in TableA)
This query does what I want:
SELECT a.ItemID
FROM TableA a
INNER JOIN TableB b ON a.ItemId = b.ItemID
WHERE b.ParentID NOT IN ( SELECT * from TableA )
as does this one:
SELECT b.ItemID
FROM TableB b
WHERE b.ItemID IN ( SELECT * FROM TableA)
AND b.ParentID NOT IN ( SELECT * FROM TableA )
I am not satisfied with either of the queries, particularly because of the use of NOT IN/IN. Is there a way to do this without them? Perhaps a cleaner way that doesn't require subqueries?
Sample Data:
Table A
-------
2
3
5
6
Table B
--------
1 | NULL
2 | 1
3 | 1
4 | 3
5 | 3
6 | 3
Desired Result:
2
3
Thanks
Without subqueries:
SELECT ItemID
FROM TableA
INTERSECT
SELECT b.ItemID
FROM TableB AS b
LEFT OUTER JOIN TableA AS a
ON b.ParentID = a.ItemID
WHERE a.ItemID IS NULL;
...but is your fear of subqueries rational? :) I'd find this equivalent query easier to read and understand:
SELECT ItemID
FROM TableA
INTERSECT
SELECT ItemID
FROM TableB
WHERE NOT EXISTS (
SELECT *
FROM TableA AS a
WHERE a.ItemID = TableB.ParentID
);
Take a look at Select all rows from one table that don't exist in another table to see 5 different ways to do this kind of query by using
NOT IN
NOT EXISTS
LEFT and RIGHT JOIN
OUTER APPLY (2005+)
EXCEPT (2005+)
Here is a script that you can run
CREATE TABLE #TableA( ItemId int)
INSERT #TableA values(1)
INSERT #TableA values(2)
INSERT #TableA values(3)
INSERT #TableA values(4)
INSERT #TableA values(5)
INSERT #TableA values(6)
CREATE TABLE #TableB( ItemId int, ParentID int)
INSERT #TableB values(1,1)
INSERT #TableB values(2,2)
INSERT #TableB values(4,3)
INSERT #TableB values(5,4)
this will do it for parent
SELECT a.ItemID
FROM #TableA a
LEFT JOIN #TableB b ON a.ItemId = b.ParentID
WHERE b.ItemID IS NULL
SELECT a.ItemID
FROM #TableA a
WHERE NOT EXISTS (SELECT 1 FROM #TableB b WHERE a.ItemId = b.ParentID)
Output
ItemID
5
6
You can use outer joins. Something like this:
SELECT a.ItemID
FROM TableA a
INNER JOIN TableB b ON a.ItemId = b.ItemID
LEFT JOIN TableB parentB on a.ItemID = parentB.ParentID
WHERE parentB.ParentID IS NULL
Your Tables A and B seem to store a tree structure. I'd interpret table A as "Nodes" (storing elements of the tree) and Table B as "Edges" (linking a node to it's parent). The inner join variant is very elegant since it covers all cases of "no edge to parent", "edge to PrantID null" and "edge to non existant parent" at once.
cheers