Showing the full list IDs when OUTER JOIN two tables - sql

How to display not only the overlapped IDs from two tables (table A and table B) but also the unique IDs from two tables?
Here is the example code:
SELECT A.ID AS ID
FROM A
FULL OUTER JOIN B ON A.ID = B.ID
I think there's something I can do with the SELECT line but I don't know how.

coalesce() returns the first non-null value from a set of parameters. Is that what you are looking for?
rextester demo: http://rextester.com/QYAZV8300
create table a (id int)
insert into a values (1),(3),(5)
create table b (id int)
insert into b values (2),(3),(4)
select
a.id as A_Id
, b.id as B_Id
, coalesce(a.id,b.id) as Id
from a
full join b
on a.id = b.id
returns:
+------+------+----+
| A_Id | B_Id | Id |
+------+------+----+
| 1 | NULL | 1 |
| 3 | 3 | 3 |
| 5 | NULL | 5 |
| NULL | 2 | 2 |
| NULL | 4 | 4 |
+------+------+----+

Related

How to fetch record from Table A which has not any approved status true on Table B

I have three table A , B and C and it structure is shown below
Table A
----------------------------
| id | Text_message_to_show|
----------------------------
| 1 | first demo message |
----------------------------
| 2 | second demo message |
----------------------------
Table B
------------------------------------
| id | request_id | approved_status |
------------------------------------
| 101 | 1 | 2 |
------------------------------------
| 102 | 1 | 1 |
------------------------------------
| 103 | 2 | 2 |
------------------------------------
| 104 | 2 | 2 |
------------------------------------
Table c
------------------------------------
| id | request_id | approved_status |
------------------------------------
| 501 | 1 | 2 |
------------------------------------
| 502 | 2 | 1 |
------------------------------------
Table B and Table C has foreign key request_id column which is reference id column of table A.Table Table A-> Table B has one to many relaionship and Table A->Table C has one to one relationship Now I have question is how to wrie sql query such that to fetch Table A record where no approved_status for request_id should be 2 in Table B And also Table C approved_status should not be 2
You can use not exists like following.
select *
from tablea ta
where not exists (
select 1
from tableb tb
where ta.id = tb.request_id
AND tb.approved_status = 2
)
You can use left join as follows:
Select a.*
From a
Left Join b on a.id = b.request_id and b.approved_status = 2
Left join c on a.id = c.request_id and c.approved_status = 2
Where coalesce(b.id,c.id) is null
select * from tablea ta
where not exists
(
select id from tableb tb where ta.id=tb.request_d and tb.approved_status = 2
)
This may help you out.

How to select multiple rows with only one tag row

Table A
RowID | A | B | C
-------+--------------+----------------+----
1 | google.com | search engine | 1
2 | google.com | |
3 | google.com | |
4 | google.com | |
6 | dropbox.com | consumer | 1
7 | dropbox.com | |
8 | dropbox.com | |
9 | dropbox.com | |
10 | dropbox.com | |
How to select row 1 to 4 where column c = 1?
Query below
select *
from tableA
where C = '1'
Despite there're better ways to collect data, if I understood well what you're trying to achieve, this should work on many situation:
DECLARE #t table (RowID int, A varchar(50), B varchar(50), C int)
DECLARE #MaxId int
INSERT INTO #t(RowID,A,B,C)
VALUES (1,'google.com','search engine',1),
(2,'google.com',NULL,NULL),
(3,'google.com',NULL,NULL),
(4,'google.com',NULL,NULL),
(6,'dropbox.com','consumer',1),
(7,'dropbox.com',NULL,NULL),
(8,'dropbox.com',NULL,NULL),
(9,'dropbox.com',NULL,NULL),
(10,'dropbox.com',NULL,NULL)
SELECT #MaxId = MAX(RowID)
FROM #t
SELECT T.RowID, T.A, I.B
FROM #t AS T
LEFT JOIN (SELECT RowID, B, ISNULL(LEAD(RowId) OVER (ORDER BY RowId) - 1,#MaxId) AS LastId
FROM #t
WHERE C = 1) AS I
ON T.RowID BETWEEN I.RowID AND I.LastId
WHERE I.B = 'search engine'
In this case the search criteria is on column B. I expect that real data has different values on column A for the same set of data (i.e. 'search engine'). For Example this solution works also on this dataset:
RowID | A | B | C
-------+------------------+----------------+----
1 | google.com | search engine | 1
2 | bing.com | |
3 | duckduckgo.com | |
4 | google.co.uk | |
6 | dropbox.com | consumer | 1
7 | facebook.com | |
8 | instagram.com | |
9 | onedrive.com | |
10 | wikipedia.com | |
Of course we're talking about sample, unreal data. Real data should be more complex, and I expect more columns, but it's just matter of adding them to the SELECT.
If column C is an integer then use
select *
from tableA
where C = 1
if is a string then be sure you have not hidden char
select *
from tableA
where trim(C) = '1'
row 1-4 do you want the o/p as of google.com then add one more condition to your where clause as
select *
from tableA
where C = '1' and A like
'%google.com%'
or if you want on basis of B only then
select *
from tableA
where C = '1' and B like
'%search engine%'
first you select row where column C value is 1
SELECT *
FROM tableA a
WHERE a.C = '1'
from there you can JOIN back to your table to get the rest of the rows based on A
SELECT a2.*
FROM tableA a
INNER JOIN tableA a2 ON a.A = a2.A
WHERE a.C = '1'
You can try this:
SELECT *
FROM TABLEA
WHERE A IN
(
SELECT A
FROM TABLEA
WHERE C = 1
)
Regards

Join on different tables depending on column associated with value being joined on?

I am trying to create a view that provides different tables depending on a column associated with the value being joined on.
Example:
SomeTable
+-----+------+
| ID | Type |
+-----+------+
| 123 | 1 |
| 124 | 2 |
| 125 | 1 |
| 126 | 2 |
+-----+------+
TableA
+---------+---------------+-----+------------+
| Item_ID | Serial_Number | ID | LocationID |
+---------+---------------+-----+------------+
| 1 | 19-001 | 124 | 4 |
| 2 | 19-002 | 126 | 17 |
+---------+---------------+-----+------------+
TableB
+-----+------------+----------+
| ID | LocationID | Quantity |
+-----+------------+----------+
| 123 | 7 | 15 |
| 125 | 12 | 10 |
+-----+------------+----------+
SELECT t.ID, v.LocationID
FROM SomeTable t
FULL JOIN NewView v ON t.ID = v.ID
WHERE t.ID = 123
If the ID the view is being joined on is Type 1 then the View selects Table A. If the ID is Type 2, then select Table B.
The expected result for ID 123 would be:
+-----+------------+
| ID | LocationID |
+-----+------------+
| 123 | 7 |
+-----+------------+
And the expected result for ID 124 would be:
+-----+------------+
| ID | LocationID |
+-----+------------+
| 124 | 4 |
+-----+------------+
I know I could do this by using a function and passing a parameter like this:
SELECT t.ID, f.LocationID
FROM SomeTable t
FULL JOIN NewFunction(123) f ON t.ID = f.ID
WHERE t.ID = 123
And here is the function:
CREATE FUNCTION NewFunction (#ID)
RETURNS #ReturnTable TABLE (ID INT, LocationID INT)
BEGIN
DECLARE #Type INT
SET #Type = (SELECT Type FROM SomeTable WHERE ID = #ID)
IF #Type = 1
INSERT INTO #ReturnTable (ID, LocationID)
SELECT t.ID, a.LocationID
FROM SomeTable t
FULL JOIN TableA a
WHERE t.ID = #ID
ELSE
INSERT INTO #ReturnTable (ID, LocationID)
SELECT t.ID, b.LocationID
FROM SomeTable t
FULL JOIN TableB b
WHERE t.ID = #ID
RETURN
END
The problem is that passing a parameter to a function like this will require making changes to the application. I would prefer not to have to implement these changes, so it would be ideal if I could recreate the functionality in the example above either with a view or a function that does not require a parameter. Any ideas?
Why not create a view for all three tables?
select t.id, coalesce(a.locationid, b.locationid) as locationid
from sometable t left join
a
on t.id = a.id and t.type = 1 left join
b
on t.id = b.id and t.type = 2;
You need the type to get the right table, so it seems that all three tables should be used together.
You can't send a parameter into a VIEW, so it isn't possible to make it do different things depending on the content of the select query.
What you could do, is to use a UNION query assuming that Table A and Table B have the same columns, then use the Type column in your WHERE clause

Using CASE for a specific situation - How TO

I'm trying to find the proper SQL for the following situation:
Supposed we have two tables:
TABLE A
ID int,
TEXT varchar(200)
TABLE B
ID int,
A_NO int,
B_NO int
Fields named "ID" on both tables can be join to link tables.
The following SQL:
SELECT
A.ID,
B.A_NO,
B.B_NO
FROM
A
LEFT JOIN
B
ON A.ID = B.ID
ORDER BY A.ID, B.A_NO, B.B_NO
gives the following results:
Now, the problem.
What is asked for is to have in the column B_NO a value = 1 for the MIN value of column A_NO and a value = 0 for all the others row with the same A_NO value.
The results below are expected:
Please note that, in this example, we can find two rows for each B_NO value but it is possible to have more than 2 rows.
I have tried to reproduce these results by using a CASE but with no success.
Thanks for you help in advance,
Bouzouki.
Try this using CTE and ROW_NUMBER(); (DEMO)
Please note: I have considered myT as your joined query of A and B tables for demo purpose. So replace myT with as yours A LEFT JOIN B ON A.ID = B.ID.
;with cte as (
select id, a_no, b_no,
row_number() over(partition by id,b_no order by a_no) rn
from myT
)
select id,a_no, case when rn=1 then b_no else 0 end b_no
from cte
order by a_no
--RESULTS FROM DEMO TABLE
| ID | A_NO | B_NO |
-------------------------
| 1031014 | 1 | 1 |
| 1031014 | 2 | 0 |
| 1031014 | 3 | 2 |
| 1031014 | 4 | 0 |
| 1031014 | 5 | 3 |
| 1031014 | 6 | 0 |
| 1031014 | 7 | 4 |
| 1031014 | 8 | 0 |
| 1031014 | 9 | 5 |
| 1031014 | 10 | 0 |
something like
select ID, a_no, b_no,
case when a_no = min_a_no then b_no else 0 end as new_b_no
from
a left join b on a.id = b.id left join
(Select ID, B_no, min(a_no) as min_a_no
from a left join b on a.id = b.id
group by id, b_no) m on a.id = m.id and b.b_no = m.b_no
ORDER BY A.ID, B.A_NO

Join table 1 to either column 1 or 2 from table 2 without duplicates

[MS SQL 2008]
I have tables (all columns are string names):
A: two columns relating some datafield to an owning entity
B: three columns defining a hierarchy of entities
I need to create a singe table of the whole hierarchy (including all rows not existing in both tables), but the key column in table A (shown as Acol2) can be in either column 1 or 2 of table B...
A: B:
Acol1 | Acol2 Bcol1 | Bcol2 | Bcol3
-------+------ --------+-------+------
A | B B | X | Y
C | D Q | X | Y
E | F H | D | Z
G | H W | V | U
The output should be
Hierarchy:
Acol1 | Bcol1 | Bcol2 | Bcol3
-------+-------+-------+------
A | B | X | Y
Null | Q | X | Y
C | Null | D | Z
G | H | D | Z
E | Null | Null | Null
Null | W | V | U
Logic (also added to original):
If A has no record in B, show A with all Null
If A has record in Bcol1, show A with full row B
If A has record in Bcol2, show A with Null, Bcol2, Bcol3
If B has no record in A, show B with Null for Acol1
I have tried all sorts of UNIONs of two separate JOINs, but can't seem to get rid of extraneous rows...
B LEFT JOIN A ON Acol2=Bcol1 UNION B LEFT JOIN A ON Acol2=Bcol2;
gives duplicate rows, as the second part of the union has to set Bcol1 to NULL
(perhaps one solution is a way to remove this duplicate NULL row?)
B INNER JOIN A ON Acol2=Bcol1 UNION B INNER JOIN A ON Acol2=Bcol2;
Obviously removes all the rows from A and B that have no shared keys
(solution as to easy way to regain just those rows?)
Any idea appreciated!
To play:
[SQL removed - see fiddle in reply comments]
SELECT
Table1.ACol1,
CASE WHEN Table1.ACol1 = Table2.BCol1 THEN Table2.BCol1 ELSE NULL END AS BCol1
Table2.BCol2,
Table2.BCol3
FROM
Table1
FULL OUTER JOIN
Table2
ON Table1.ACol2 IN (Table2.BCol1, Table2.BCol2)
When you say no duplicates, this is only possible if ACol2 only ever appears in one field of one row in Table2. If it appears in multiple places, you'll get duplication.
- If that's possible, how would you want to chose which record from Table2?
Also, in general, however, this is a SQL-Anti-Pattern.
This is because the join would prefer an index on Table2. But, since you never know which field you're joining on, no single index will ever satsify the join condition.
EDIT:
What would make this significantly faster is to create a normalised TableB...
B_ID | B_Col | B_Val
------+-------+-------
1 | 1 | B
1 | 2 | X
1 | 3 | Y
2 | 1 | Q
2 | 2 | X
2 | 3 | Y
3 | 1 | H
3 | 2 | D
3 | 3 | Z
4 | 1 | W
4 | 2 | V
4 | 3 | U
Then index that table with (B_ID) and on (B_Val)...
Then include the B_ID field in the non_normalised table...
ID | Bcol1 | Bcol2 | Bcol3
------+-------+-------+-------
1 | B | X | Y
2 | Q | X | Y
3 | H | D | Z
4 | W | V | U
Then use the following query...
SELECT
Table1.ACol1,
CASE WHEN Table1.ACol1 = Table2.BCol1 THEN Table2.BCol1 ELSE NULL END AS BCol1
Table2.BCol2,
Table2.BCol3
FROM
(
Table1
LEFT JOIN
Table2Normalised
ON Table2Normalised.B_Val = Table1.ACol2
AND Table2Normalised.B_Col IN (1,2)
)
FULL OUTER JOIN
Table2
ON Table2Normalised.B_ID = Table2.ID
EDIT:
Without changing the schema, and instead having one index on BCol1 and a second index on Bcol2...
SELECT ACol1, BCol1, BCol2, BCol3 FROM Table1 a INNER JOIN Table2 b ON a.ACol2 = b.BCol1
UNION ALL
SELECT ACol1, NULL, BCol2, BCol3 FROM Table1 a INNER JOIN Table2 b ON a.ACol2 = b.BCol2
UNION ALL
SELECT ACol1, NULL, NULL, NULL FROM Table1 a WHERE NOT EXISTS (SELECT * FROM Table2 WHERE BCol1 = a.ACol2)
AND NOT EXISTS (SELECT * FROM Table2 WHERE BCol2 = a.ACol2)
UNION ALL
SELECT NULL, BCol1, BCol2, BCol3 FROM Table2 b WHERE NOT EXISTS (SELECT * FROM Table1 WHERE ACol2 = b.BCol1)
AND NOT EXISTS (SELECT * FROM Table1 WHERE ACol2 = b.BCol2)
But that's pretty messy...