sorting two tables (full join) - sql

i'm joining tables like:
select * from tableA a full join tableB b on a.id = b.id
But the output should be:
row without null fields
row with null fields in tableB
row with null fields in tableA
Like:
a.id a.name b.id b.name
5 Peter 5 Jones
2 Steven 2 Pareker
6 Paul null null
4 Ivan null null
null null 1 Smith
null null 3 Parker

create table a(id number, name varchar2(10));
insert into a(id, name) values(5, 'Peter');
insert into a(id, name) values(2, 'Steven');
insert into a(id, name) values(6, 'Paul');
insert into a(id, name) values(4, 'Ivan');
create table b(id number, name varchar2(10));
insert into b(id, name) values(5, 'Jones');
insert into b(id, name) values(2, 'Pareker');
insert into b(id, name) values(1, 'Smith');
insert into b(id, name) values(3, 'Parker');
select * from a full join b on a.id = b.id
order by
case
when a.id is not null and b.id is not null then 0
when a.id is not null and b.id is null then 1
when a.id is null and b.id is not null then 2
else 3
end
;

Related

How can I override rows from another table?

I have two tables:
TableA
ID Name
-- ----
1 aaa
2 bbb
3 ccc
4 ddd
TableB
ID Name
-- --------
3 WWXXYYZZ
I want to select from both tables, but skip the rows which exist in TableB. The result should look like this:
ID Name
-- --------
1 aaa
2 bbb
3 WWXXYYZZ
4 ddd
I have tried union and join but did not figure out how to achieve this.
-- Did not work
select *
from TableA
union
select *
from TableB
-- Did not work
select *
from
(
select *
from TableA
) x
join
(
select *
from TableB
) y
on x.ID = y.ID
You could left join b on to a, and use coalesce to prefer b's rows:
SELECT a.id, COALESCE(b.name, a.name) AS name
FROM a
LEFT JOIN b ON a.id = b.id
You can do:
select a.id, coalesce(b.name, a.name)
from a left join b on a.id = b.id
One method is union all:
select b.*
from b
union all
select a.*
from a
where not exists (select 1 from a where a.id = b.id);
You can also choose from a and override with values from b:
select a.id, coalesce(b.name, a.name) as name
from a left join
b
on a.id = b.id;
A more complex method uses ROW_NUMBER which might be necessary if your query is significantly more complex than shown. It also handled the case where a row exists in TableB but not TableA (which is not clear from your question).
DECLARE #TableA TABLE (id INT, [Name] VARCHAR(12));
DECLARE #TableB TABLE (id INT, [Name] VARCHAR(12));
INSERT INTO #TableA (id, [Name])
VALUES
(1, 'aaa'),
(2, 'bbb'),
(3, 'ccc'),
(4, 'ddd');
INSERT INTO #TableB (id, [Name])
VALUES
(3, 'WWXXYYZZ'),
(5, 'TTTGGG');
SELECT id, [Name]
FROM (
SELECT id, [Name]
, ROW_NUMBER() OVER (PARTITION BY id ORDER BY [Priority] DESC) Rn
FROM (
SELECT id, [Name], 0 [Priority]
FROM #TableA
UNION ALL
SELECT id, [Name], 1 [Priority]
FROM #TableB
) X
) Y
WHERE Rn = 1;
Returns:
1 aaa
2 bbb
3 WWXXYYZZ
4 ddd
5 TTTGGG

How to join two tables with unequal number of rows for same primary key value

I want to join two same tables with different data for the same primary key value.
I am performing a full join between the two tables, as I want to see what information has changed for the same ID between two months. I tried using a group by clause as well, but that didn't work.
Select
a.ID, a.Value1,
b.Value
from
TableA a
full join
TableB b on a.ID = b.ID
Input data:
Table A Table B
ID Value ID Value
--------- ----------
1 A 1 A
1 B 1 B
2 A 1 C
Desired output:
ID VALUE1 Value2
-----------------
1 A A
1 B B
1 Null C
Current (wrong) output:
ID VALUE1 Value2
-----------------
1 A A
1 A B
1 A C
1 B A
1 B B
1 B C
I suspect that ALL combinations are desired, thus FULL Join is better.
Select Case When a.ID IS Null Then b.ID Else a.ID End as ID,
a.Value,
b.Value
from UnequalRowsTableA a
full join UnequalRowsTableB b on a.ID=b.ID and a.Value = b.Value
Results
ID Value Value
1 A A
1 B B
2 A NULL
1 NULL C
You can use TableB in FROM then TableA in LEFT JOIN and in your ON clause add the Value matching too, to achieve your expected result:
SELECT B.ID,
A.Value AS Value1,
B.Value AS Value2
FROM TableB B
LEFT JOIN TableA A ON A.ID = B.ID AND A.Value = B.Value;
Demo with sample data:
DECLARE #TableA TABLE (ID INT, [Value] VARCHAR (1));
INSERT INTO #TableA (ID, [Value]) VALUES
(1, 'A'), (1, 'B'), (2, 'A');
DECLARE #TableB TABLE (ID INT, [Value] VARCHAR (1));
INSERT INTO #TableB (ID, [Value]) VALUES
(1, 'A'), (1, 'B'), (1, 'C');
SELECT B.ID,
A.[Value] AS Value1,
B.[Value] AS Value2
FROM #TableB B
LEFT JOIN #TableA A ON A.ID = B.ID AND A.[Value] = B.[Value];
Output:
ID Value1 Value2
----------------------
1 A A
1 B B
1 NULL C

select if field match or if child record field match

I have a table Cities as
(Id, Name, ParentId)
where ParentId is the Id of a City (self related table)
I want to get the cities wheres the parentId is null (root)
if the name matches or child record name matches I wrote this
declare #cities table (Id, Name, ParentId)
insert into #cities (Id , Name)
select Id , Name from Cities
Where CHARINDEX(N'CD', Name) > 0 and ParentId is null
insert into #cities (Id , Name)
select Id , Name from Cities
Where Id in
(select distinct ParentId from Cities
where CHARINDEX(N'CD', Name) > 0 ParentId is not null)
and ParentId is null
select distinct * from #cities
What can I do to make it faster and better?
Edit:
Id | Name | ParentId
----------------------
1 | ABCD | NULL
----------------------
2 | EFZX | NULL
----------------------
3 | GHIJ | NULL
----------------------
4 | MNOP | 1
----------------------
5 | CDKL | 2
----------------------
6 | QRST | 3
----------------------
this should return:
Id | Name | ParentId
----------------------
1 | ABCD | NULL
----------------------
2 | EFZX | NULL
----------------------
Edit2:
the first select returns the cities with matching names
the second select returns the cities with matching children
then merge the two results.
I can suggest solution with one select.
I have considered that you want result by parents and also by immediate descendants. So you should select all rows where name matches 'CD'
SELECT * FROM #cities
WHERE CHARINDEX(N'CD', Name) > 0
This will give you
1 ABCD NULL
5 CDKL 2
6 CDKP 2
You want select only parents, that's why you need left join on parent to take rows where parent is 2
SELECT * FROM #cities c1
LEFT JOIN #cities c2 ON c1.ParentId = c2.ID
WHERE CHARINDEX(N'CD', c1.Name) > 0
This returns
1 ABCD NULL NULL NULL NULL
5 CDKL 2 2 EFZX NULL
6 CDKP 2 2 EFZX NULL
Then you apply second where and (c1.ParentId is NULL OR (c1.ParentId IS NOT NULL AND c2.ParentId IS NULL)) to take parents and immediate descendants only.
declare #cities table (Id int, Name NVARCHAR(MAX), ParentId INT null)
INSERT INTO #cities (Id, Name, ParentId) VALUES (1, 'ABCD', NULL)
INSERT INTO #cities (Id, Name, ParentId) VALUES (2, 'EFZX', NULL)
INSERT INTO #cities (Id, Name, ParentId) VALUES (3, 'GHIJ', NULL)
INSERT INTO #cities (Id, Name, ParentId) VALUES (4, 'MNOP', 1)
INSERT INTO #cities (Id, Name, ParentId) VALUES (5, 'CDKL', 2)
INSERT INTO #cities (Id, Name, ParentId) VALUES (6, 'CDKP', 2)
SELECT DISTINCT ISNULL(c2.Id, c1.Id), ISNULL(c2.Name, c1.Name) FROM #cities c1
LEFT JOIN #cities c2 ON c1.ParentId = c2.ID
WHERE CHARINDEX(N'CD', c1.Name) > 0 and (c1.ParentId is NULL OR (c1.ParentId IS NOT NULL AND c2.ParentId IS NULL))
SAMPLE CODE
CREATE table #cities (Id INT, Name VARCHAR(30), ParentId INT)
insert into #cities (Id, Name, ParentId) VALUES(1 , 'ABCD',NULL)
insert into #cities (Id, Name, ParentId) VALUES(2 , 'EFZX',NULL)
insert into #cities (Id, Name, ParentId) VALUES(3 , 'GHIJ',NULL)
insert into #cities (Id, Name, ParentId) VALUES(4 , 'MNOP',1)
insert into #cities (Id, Name, ParentId) VALUES(5 , 'CDKL',2)
insert into #cities (Id, Name, ParentId) VALUES(6 , 'QRST',3)
QUERY
;WITH CTE AS
(
-- Select condition for parent
SELECT Id, Name, ParentId,0 AS [LEVEL]
FROM #cities --WHERE ParentId IS NULL --AND ID=1
WHERE CHARINDEX(N'CD', Name) > 0 and ParentId is null
UNION ALL
SELECT C1.*,C2.[LEVEL]+1
FROM #cities C1
JOIN CTE C2 ON C1.ParentId=C2.Id
)
-- Since you get only parent and children, you can filter children here
SELECT *
FROM CTE
WHERE CHARINDEX(N'CD', Name) > 0
OPTION(MAXRECURSION 0)

Oracle joining to get desired results

I have the following tables
Table A Table B Table C
ColumnA ColumnB ColumnA ColumnB ColumnA ColumnB
1 A 2 X X Value1
2 B 3 Y Y Value2
3 C 5 Z Z Value3
4 D
5 E
The result required is
Column1 Column2 Column3
1 A
2 Value1 B
3 Value2 C
4 D
5 Value3 E
I have been playing with the left outer join. But still not getting close to the result I am looking for. Any help is appreciated.
You need to use the LEFT JOIN twice:
CREATE table tablea (
columna NUMBER,
columnb VARCHAR2(1)
);
CREATE table tableb (
columna NUMBER,
columnb VARCHAR2(1)
);
CREATE table tablec (
columna VARCHAR2(1),
columnb VARCHAR2(10)
);
INSERT INTO tablea VALUES (1, 'A');
INSERT INTO tablea VALUES (2, 'B');
INSERT INTO tablea VALUES (3, 'C');
INSERT INTO tablea VALUES (4, 'D');
INSERT INTO tablea VALUES (5, 'E');
INSERT INTO tableb VALUES (2, 'X');
INSERT INTO tableb VALUES (3, 'Y');
INSERT INTO tableb VALUES (5, 'Z');
INSERT INTO tablec VALUES ('X', 'Value1');
INSERT INTO tablec VALUES ('Y', 'Value2');
INSERT INTO tablec VALUES ('Z', 'Value3');
COMMIT;
SELECT ta.columna, tc.columnb, ta.columnb
FROM tablea ta
LEFT JOIN tableb tb ON (ta.columna = tb.columna)
LEFT JOIN tablec tc ON (tc.columna = tb.columnb)
ORDER BY 1
;
Output:
COLUMNA COLUMNB COLUMNB
---------- ---------- -------
1 A
2 Value1 B
3 Value2 C
4 D
5 Value3 E
SQLFiddle demo

Stick two tables together

Let's consider two tables:
First:
Id Data
1 asd
2 buu
And Second:
UPD:
Id Data
10 ffu
11 fffuuu
10001 asd
I want to get a 4-column table looking like this:
Id1 Data1 Id2 Data2
1 asd 10 fuu
2 buu 11 fffuuu
-1 [any text] 10001 asd
(if the numbers of rows are not equal ,let's use "-1" for the id)
How to do this?
I'm using sqlite3-3.7.3.
UPD2:
There is no matching criteria between tables,any random matching between them will be sufficient for me.
Assuming that the id columns are unique and not null, you can "zip" your tables by:
Creating a row number for each row that corresponds to the
position of the row when the table is ordered by the unique id (as
polishchuk mentioned in his comment); and,
Simulating a FULL OUTER JOIN with 2 LEFT OUTER JOINS.
To demonstrate, I used two tables with differing row counts:
CREATE TABLE foo (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT);
INSERT INTO foo VALUES (NULL, 'a');
INSERT INTO foo VALUES (NULL, 'b');
INSERT INTO foo VALUES (NULL, 'c');
INSERT INTO foo VALUES (NULL, 'd');
INSERT INTO foo VALUES (NULL, 'e');
INSERT INTO foo VALUES (NULL, 'f');
INSERT INTO foo VALUES (NULL, 'g');
INSERT INTO foo VALUES (NULL, 'h');
INSERT INTO foo VALUES (NULL, 'i');
INSERT INTO foo VALUES (NULL, 'j');
DELETE FROM foo WHERE data IN ('b', 'd', 'f', 'i');
CREATE TABLE bar (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT);
INSERT INTO bar VALUES (NULL, 'a');
INSERT INTO bar VALUES (NULL, 'b');
INSERT INTO bar VALUES (NULL, 'c');
INSERT INTO bar VALUES (NULL, 'd');
INSERT INTO bar VALUES (NULL, 'e');
INSERT INTO bar VALUES (NULL, 'f');
INSERT INTO bar VALUES (NULL, 'g');
INSERT INTO bar VALUES (NULL, 'h');
INSERT INTO bar VALUES (NULL, 'i');
INSERT INTO bar VALUES (NULL, 'j');
DELETE FROM bar WHERE data IN ('a', 'b');
To obtain a more readable output, I then ran:
.headers on
.mode column
Then you can execute this SQL statement:
SELECT COALESCE(id1, -1) AS id1, data1,
COALESCE(id2, -1) as id2, data2
FROM (
SELECT ltable.rnum AS rnum,
ltable.id AS id1, ltable.data AS data1,
rtable.id AS id2, rtable.data AS data2
FROM
(SElECT (SELECT COUNT(*) FROM foo
WHERE id <= T1.id) rnum, id, data FROM foo T1
) ltable
LEFT OUTER JOIN
(SElECT (SELECT COUNT(*) FROM bar
WHERE id <= T1.id) rnum, id, data FROM bar T1
) rtable
ON ltable.rnum=rtable.rnum
UNION
SELECT rtable.rnum AS rnum,
ltable.id AS id1, ltable.data AS data1,
rtable.id AS id2, rtable.data AS data2
FROM
(SElECT (SELECT COUNT(*) FROM bar
WHERE id <= T1.id) rnum, id, data FROM bar T1
) rtable
LEFT OUTER JOIN
(SElECT (SELECT COUNT(*) FROM foo
WHERE id <= T1.id) rnum, id, data FROM foo T1
) ltable
ON ltable.rnum=rtable.rnum)
ORDER BY rnum
Which gives you:
id1 data1 id2 data2
---------- ---------- ---------- ----------
1 a 3 c
3 c 4 d
5 e 5 e
7 g 6 f
8 h 7 g
10 j 8 h
-1 9 i
-1 10 j
This works "both ways", for example, if you invert the two tables (foo and bar), you get:
id1 data1 id2 data2
---------- ---------- ---------- ----------
3 c 1 a
4 d 3 c
5 e 5 e
6 f 7 g
7 g 8 h
8 h 10 j
9 i -1
10 j -1