Fetching data from two tables in oracle - database

I have two result sets :
Set 1:
STUDENT| COUNT
------ | ------
mohit | 4
Rohit | 2
Tanvi | 2
Jhanvi | 1
Set 2:
STUDENT| COUNT_STAR
------ | ------
mohit | 2
Rohit | 3
Tanvi | 1
Arjun | 1
Abhay | 3
Abhi | 1
Expected Result Set :
STUDENT| COUNT | COUNT_STAR
------ | ------ | ----------
mohit | 4 | 2
Rohit | 2 | 3
Tanvi | 2 | 1
Arjun | na | 1
Abhay | na | 3
Abhi | na | 1
Jhanvi | 1 | na
Can someone help me with the SQL Query for this ?

you need a union for get the distinct name from both the table
and left join for get the values for count an count_star
select T.STUDENT , table1.count, table2.count_star
from (
select STUDENT
from table1
UNION
select STUDENT
from table2
) T
left join table1 on table1.student = t.student
left join table2 on table1.student = t.student

Use a FULL OUTER JOIN to join two overlapping result sets:
select coalesce(table1.student, table2.student) as student
, nvl( table1.count, 'na') as count
, nvl( table2.star_count, 'na') as star_count
from table1
full outer join table2
on table1.student = table2.student

you can use FULL OUTER JOIN to get the required result-
SELECT DECODE (a.STUDENT, NULL, b.STUDENT, a.STUDENT) STUDENT,
a.COUNT,
b.count_star
FROM table1 a FULL OUTER JOIN table2 b ON a.STUDENT = b.STUDENT;
Hope this helps.

Following SQL is tested with Oracle 12G:
SELECT COALESCE (T1.STUDENT, T2.STUDENT) AS STUDENT,
DECODE (T1.COUNT, NULL, 'na', T1.COUNT) COUNT,
DECODE (T2.COUNT_STAR, NULL, 'na', T2.COUNT_STAR) COUNT_STAR
FROM TABLE1 T1
FULL OUTER JOIN TABLE2 T2 ON T1.STUDENT = T2.STUDENT;

Related

SQL Server - How to join with max value from second table and apply specific condition

I have two tables:
Weeks
| WeekID | StartDate |
| 1 | 2016-12-25 |
| 2 | 2017-01-01 |
| 3 | 2017-01-08 |
and Settings
| ID | SettingVal | ApplyFrom |
| 1 | 10 | 2016-06-01 |
| 2 | 13 | 2017-01-01 |
| 3 | 5 | 2017-01-02 |
For each WeekID, I need to select SettingVal with MAX(ApplyFrom) existing, but also ApplyFrom <= DATEADD(day, 6, StartDate) from table Weeks, for example:
| WeekID | SettingVal |
| 1 | 10 |
| 2 | 5 |
| 3 | 5 |
When I write the following query:
SELECT t1.WeekID, t2.SettingVal
FROM Weeks t1
LEFT OUTER JOIN Settings t2 ON t2.ApplyFrom <= DATEADD(day, 6, t1.StartDate)
it joins one row from first table with multiple rows from second table. How do I join only with a row having MAX(ApplyFrom), and select the SettingVal column I need?
Option 1 - WITH TIES
Select Top 1 with ties
A.WeekID
,B.SettingVal
From Weeks A
Left Join Settings B
on B.ApplyFrom<=DateAdd(DAY,6,A.StartDate)
Order By Row_Number() over (Partition By A.WeekID Order by B.ApplyFrom Desc)
Option 2 - Cross Apply
Select A.WeekID
,B.SettingVal
From Weeks A
Cross Apply (
Select Top 1 SettingVal
From Settings
Where ApplyFrom<=DateAdd(DAY,6,A.StartDate)
Order By ApplyFrom Desc
) B
Both Return
WeekID SettingVal
1 10
2 5
3 5
You can try using a query like this
SELECT
t1.WeekID,
t2.SettingVal
FROM Weeks t1
LEFT OUTER JOIN
(
SELECT
t3.WeekID,
MAX(t2.ApplyFrom) ApplyFrom
FROM Weeks t3
LEFT OUTER JOIN Settings t2 ON t2.ApplyFrom BETWEEN t3.StartDate AND DATEADD(day, 6, t3.StartDate)
GROUP BY t3.WeekID
)T4
ON T4.WeekID=T1.WeekID
LEFT OUTER JOIN Settings T2 ON T4.ApplyFrom=T2.ApplyFrom

How to join on two fields where one could be null

This query may seem basic, but i'm at a fairly basic level.
So here is my data - Sorry about the formatting, i've tried following the help but the table formatting is obviously not working for me (Can someone please advise?):
Table 1
ID |Country
---| -------
1 | UK
1 | IE
1 | US
2 | UK
2 | FR
Table 2
ID |Country
---| -------
1 | UK
1 | IE
2 | UK
The result i want is this
Table 1----- | ----Table 2
ID |Country |-----ID |Country
---| ------- |--------|--------
1 | UK | 1 | UK
1 | IE | 1 | IE
1 | US | 1 | NULL
2 | UK | 2 | UK
2 | FR | 2 | NULL
But more specifically i want to identify the NULL's so that i get this result
Table 1----- | ----Table 2
ID |Country |-----ID |Country
---| ------- |--------|--------
1 | US | 1 | NULL
2 | FR | 2 | NULL
The code i have used so far is:
select *
from table1 t1
left outer join table2 t2 on t1.id = t2.id and t1.country = t2.country
where t1.id is not null
and t2.country is null
Try this
select t1.id, t1.country, isnull(t2.id, t1.id) AS T2_ID, t2.country
from table1 t1
left outer join table2 t2 on t1.id = t2.upc and t1.country = t2.country
if you want to only show the ones where you have nulls in t2, you can add
where t2.id is null
But if you want to show all the records, just leave it without the WHERE condition
You were close, you just need to use isnull() or coalesce().
select
t1.id
, t1.country
, t2_Id = isnull(t2.id,t1.id)
, t2_country = t2.country
from table1 t1
left outer join table2 t2 on t1.id = t2.id and t1.country = t2.country
where t1.id is not null
--and t2.country is null
rextester demo: http://rextester.com/XCNH52338
returns:
+----+---------+-------+------------+
| id | country | t2_Id | t2_country |
+----+---------+-------+------------+
| 1 | UK | 1 | UK |
| 1 | IE | 1 | IE |
| 1 | US | 1 | NULL |
| 2 | UK | 2 | UK |
| 2 | FR | 2 | NULL |
+----+---------+-------+------------+
with the additional filter of t2.country is null
returns:
+----+---------+-------+------------+
| id | country | t2_Id | t2_country |
+----+---------+-------+------------+
| 1 | US | 1 | NULL |
| 2 | FR | 2 | NULL |
+----+---------+-------+------------+
The main difference between the two is that coalesce() can support more than 2 parameters, and it selects the first one that is not null. More differences between the two are answered here.
coalesce() is standard ANSI sql, so it is available in most RDBMS. isnull() is specific to sql server.
Reference:
isnull() - msdn
coalesce() - msdn
coalesce vs isnull - Itzik Ben-Gan

SP to update 3rd table using data in first 2 tables

For e.g. I have below table1 and table3. The 'Counts' field in table2 should be updated based on valuess field in table1 and table3. i.e. 23 appears 4 times in table1 and table3 and 45 appears once. Table2 should be updated with that count.
table1
Id | Data | Valuess
1 | rfsd | 23
2 | fghf | 45
3 | rhhh | 23
table3
Id | Data | Valuess
1 | rfsd | 23
2 | tfgy | 23
table2
Id | Fields | Counts
1 | 23 | 4
2 | 45 | 1
I am using the below stored procedure to achieve this.
WITH t13 AS (
SELECT Id, Data, Valuess FROM Table1 UNION ALL SELECT Id, Data, Valuess FROM Table3),
cte AS (SELECT Valuess,COUNT(*) AS Count2 FROM t13 GROUP BY Valuess)
UPDATE t2
SET t2.Counts = cte.Count2
FROM Table2 t2 JOIN cte ON t2.Fields = cte.Valuess;
QUESTION
Now instead of above table data, i have below table data....
table1
Id | Data | Valuess
1 | rfsd | 004561
2 | fghf | 0045614
3 | rhhh | adcwyx
table3
Id | Data | Valuess
1 | rfsd | 0045614
2 | tfgy | 004561
table2
Id | Fields | Counts
1 | 0045614 | 4
2 | adcwyxv | 1
So here we have alphanumeric data in valuess field of table1 and table3. Also we have data like '004561' and '0045614'
I want to clip off the 7th element of the field and compare it with clipping off 7th element in the table 3. i.e. 004561, 004561 and adcwyx will be taken from table1. 004561 and 004561 will be taken from table3 and compared with 004561 and adcwyx of table2 ( we need to clip off 7th element in table2 first) and then compare.
The final result should be as shown in table2.
SUBSTRING should do it.
WITH t13 AS (
SELECT Id, Data, SUBSTRING(Valuess,1,6) AS [Values]
FROM Table1
UNION ALL
SELECT Id, Data, SUBSTRING(Valuess,1,6) AS [Values]
FROM Table3
)
, cte AS (
SELECT [Values],COUNT(*) AS Count2
FROM t13 GROUP BY [Values]
)
UPDATE t2
SET t2.Counts = cte.Count2
FROM Table2 t2 JOIN cte ON SUBSTRING(t2.Fields,1,6) = cte.[Values];

Split table in two tables plus a link table

I have a table with three columns with double values, but no double rows. Now I want to split this table in two table with unique values and a link table. I think the Problem gets clearer when I Show you example tables:
Original:
| ID | Column_1 | Column_2 | Column_3 |
|----|----------|----------|----------|
| 1 | A | 123 | A1 |
| 2 | A | 123 | A2 |
| 3 | B | 234 | A2 |
| 4 | C | 456 | A1 |
Table_1
| ID | Column_1 | Column_2 |
|----|----------|----------|
| 1 | A | 123 |
| 2 | B | 234 |
| 3 | C | 456 |
Table_2
| ID | Column_3 |
|----|----------|
| 1 | A1 |
| 2 | A2 |
Link-Table
| ID | fk1 | fk2 |
|----|-----|-----|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
| 4 | 3 | 1 |
Table_1 I created like this:
INSERT INTO Table_1(Column_1, Column_2)
SELECT DISTINCT Column_1, Column_2 FROM Original
WHERE Original.Column_1 NOT IN (SELECT Column_1 FROM Table_1)
Table_2 I created in the same way.
The question now is, how to create the Link-Table?
The original table does grow continuesly, so only new entries should be added.
Do I have to use a Cursor, or is there a better way?
SOLUTION:
MERGE Link_Table AS LT
USING (SELECT DISTINCT T1.ID AS T1ID, T2.ID AS T2ID FROM Original AS O
INNER JOIN Table_1 AS T1 ON T1.Column_1 = O.Column_1
INNER JOIN Table_2 AS T2 ON T2.Column_3 = O.Column_3) AS U
ON LT.fk1 = U.T1ID
WHEN NOT MATCHED THEN
INSERT (fk1, fk2)
VALUES (U.T1ID, U.T2ID);
You can JOIN all 3 tables to get proper data for link table:
--INSERT INTO [Link-Table]
SELECT t1.ID,
t2.ID
FROM Original o
INNER JOIN Table_1 t1
ON t1.Column_1 = o.Column_1
INNER JOIN Table_2 t2
ON t2.Column_3 = o.Column_3
If your original table will grow, then you need to use MERGE to update/insert new data.
You have to inner join your Original,Table_1 and Table_2 to get the desired result.
Try like this, Its similar to gofr1 post.
DECLARE #orginal TABLE (
ID INT
,Column_1 VARCHAR(10)
,Column_2 INT
,Column_3 VARCHAR(10)
)
DECLARE #Table_1 TABLE (
ID INT
,Column_1 VARCHAR(10)
,Column_2 INT
)
DECLARE #Table_2 TABLE (
ID INT
,Column_3 VARCHAR(10)
)
Insert into #orginal values
(1,'A',123,'A1')
,(2,'A',123,'A2')
,(3,'B',234,'A2')
,(4,'C',456,'A1')
Insert into #Table_1 values
(1,'A',123)
,(2,'B',234)
,(3,'C',456)
Insert into #Table_2 values
(1,'A1')
,(2,'A2')
SELECT O.ID
,T1.ID
,T2.ID
FROM #orginal O
INNER JOIN #Table_1 T1 ON T1.Column_1 = O.Column_1
INNER JOIN #Table_2 T2 ON T2.Column_3 = O.Column_3

SELECT rows from Table1 having identical values on columns and Table2 Column > N

This is simple. I have two tables. I need to select rows from Table1 which have same 'Customer' and in Table2 'yearmm' is bigger than 2015001.
Table1
id | Customer | yearmmm |
----------------------------
10 | 123456 | 2015001 |
11 | 456789 | 2015001 |
20 | 111111 | 2015001 |
21 | 222222 | 2015001 |
44 | 4444 | 2015001 |
Table2
id | Customer | yearmmm |
----------------------------
10 | 123456 | 2015001 |
11 | 456789 | 2015002 |
20 | 111111 | 2015003 |
21 | 222222 | 2010001 |
333 | 333 | 2015004 |
Wonder if this works:
SELECT * FROM Table1 WHERE Customer IN
(SELECT Customer FROM Table2 WHERE yearmmm > '2015001')
Desired result:
11 | 456789 | 2015002 |
20 | 111111 | 2015003 |
You can use EXISTS:
SELECT t1.*
FROM Table1 t1
WHERE EXISTS
(
SELECT 1 FROM Table2 t2
WHERE t1.Customer = t2.Customer
AND t2.yearmmm > '20150101'
)
You have other options like INNER JOIN or IN.
Well, no, that will not work. You're ultimately selecting the Customer and yearmmm from Table1 based on values in Table2. Yet your desired results show yearmmm values that exist in Table2.
Based on your desired results it seems like you just want this:
SELECT * FROM Table2 WHERE yearmmm > '2015001'
EDIT: If you do in fact need more data from Table1, consider:
SELECT t1.id, t1.Customer, t2.yearmmm, another_other_fields
FROM Table1 t1 INNER JOIN Table2 t2 ON t1.id = t2.id
WHERE t2.yearmmm > '2015001'
You can use:
SELECT
t1.*
FROM
Table1 t1
INNER JOIN Table2 t2 ON
(t1.Customer = t2.Customer)
AND (t2.yearmmm > '2015001');
Or
SELECT
t1.*
FROM
Table1 t1
INNER JOIN Table2 t2 ON
(t1.Customer = t2.Customer)
WHERE
(t2.yearmmm > '2015001');

Resources