I have an oracle sql query
select
distinct
tab1.col1,
tab2.col1
from
table1 tab1
join table2 tab2 on tab1.col1 = tab2.col1
Here i get the as expected in terms of distinct values.
For Example : The result rows are
1 2
3 4
5 6
Now I want to add one more join for table3. so my sql is
select
distinct
tab1.col1,
tab2.col1,
tab3.col1
from
table1 tab1
join table2 tab2 on tab1.col1 = tab2.col1
join table3 tab3 on tab1.col1 = tab3.col1
Here what the problem is is that table 3 is returning more than one value.
which is resulting in duplicate rows based on table3.
For Example : The result rows are
1 2 4
1 2 5
3 4 1
3 4 2
5 6 3
(Here if you notice row 1 & 2 are duplicate and 3 & 4 are duplicate)
What I am trying to do is for the join of table3 i want to fetch the
first occurrence of row.
This shud work for you !
select
distinct
tab1.col1,
tab2.col1,
MIN(tab3.col1)
from
table1 tab1
join table2 tab2 on tab1.col1 = tab2.col1
join table3 tab3 on tab1.col1 = tab3.col1
GROUP BY tab1.col1, tab2.col1
Edit: Thoughts,
I am assuming column 3 to be a integer which ever increasing, in that case this works. You can use the date column to define your aggregate accurately to get the "first occurance of your row".
select
distinct
tab1.col1,
tab2.col1,
t3.col1
from
table1 tab1
join table2 tab2 on tab1.col1 = tab2.col1
join (select distinct col1 from table3) t3 on tab1.col1 = t3.col1
Related
I need to create a table keyed by an ID where the values of one of the columns in the new table are the earliest values entered into the column of another table where the rows share the same ID and have a specific type label.
For example, say I want the Name and first Value entered for each fruit with an entry type A:
These are the tables I have:
TABLE1
Key
ID
Name
1
1
Cherry
2
2
Grape
TABLE2
Key
ID
Value
EntryNum
EntryType
1
1
21
1
A
2
1
32
2
B
3
1
4
3
B
4
1
15
4
A
5
2
3
1
B
6
2
8
2
A
7
2
16
3
B
And this is the result that I want:
TABLE3
ID
Name
EarliestEntry
1
Cherry
21
2
Grape
8
I've attempted the following query but it just returns the same value for all EarliestEntry:
SELECT TABLE1.ID, TABLE2.Name,
(SELECT Value FROM (SELECT ROW_NUMBER() OVER (ORDER BY TABLE2.EntryNum)
as row_num, Value FROM TABLE2
WHERE TABLE2.ID = TABLE1.ID AND TABLE2.EntryType = 'A')
AS sub
WHERE row_num = 1) AS EarliestEntry
INTO TABLE3
FROM TABLE2
INNER JOIN TABLE1 ON TABLE1.ID = TABLE2.ID
GROUP BY TABLE1.ID, TABLE2.Type, TABLE2.EntryNum
I would greatly appreciate help on this. Thank you
If you wanted to use the ROW_NUMBER function then you would need to put that on TABLE1 and add a partition by like so:
WITH rn AS(
SELECT a.Key, ROW_NUMBER() OVER(PARTITION BY a.ID ORDER BY a.EntryNum) AS rn
FROM TABLE2 AS a
)
SELECT b.Name, a.Value AS EarliestValue
FROM TABLE2 AS a
INNER JOIN TABLE1 AS b ON b.ID = a.ID
INNER JOIN rn AS rn ON rn.key = a.key
WHERE rn.rn = 1
In your example you skipped the PARTITION BY clause so you just get a number for all values in TABLE2. Instead of a number per ID in ascending order for Value.
Based on your description of the three tables TABLE1, TABLE2 and TABLE3.
I modified a little bit your script. Thank of Dale K remark, I explain in some words the solution : the field TABLE2.Name shown in the first select was wrong, because [name] belongs to TABLE1, so the right syntax for this is TABLE1.name. And in the GROUP BY clause the field TABLE2.Type might be replaced by TABLE1.name to repect aggregation criteria. So the script becomes :
SELECT DISTINCT table1.id, table1.name,
(SELECT Value FROM (SELECT ROW_NUMBER() OVER (ORDER BY table2.EntryNum)
as row_num, Value FROM table2
WHERE table2.id = table1.id AND table2.EntryType = 'A')
AS sub
WHERE row_num = 1) AS EarliestEntry
INTO table3
FROM table2
INNER JOIN table1 ON table1.id = table2.id
GROUP BY table1.id, table1.name, table2.entrynum;
Here, you can verify the output with fiddle
You are hugely over-complicating this.
Just partition Table2 and take a row-number, then join that to Table1 and filter on only row-number 1
SELECT
t1.Id,
t1.Name,
EarliestEntry = t2.Value
FROM Table1 t1
JOIN (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY t2.ID ORDER BY t2.EntryNum)
FROM Table2 t2
WHERE t2.EntryType = 'A'
) t2 ON t2.ID = t1.ID AND t2.rn = 1;
db<>fiddle
I have 4 tables as shown below
I basically want to get how many users from table1 are in tables 2, 3 and 4. Similarly for table2 I want to get how many users are present in table 1, 3 and 4. and same for tables 3 and 4
Basically all the possible combinations. The final result I want is something as below
One of the way I am trying to solve is by doing a left-join of table1 with other tables to followed by count to get first row of my output. But doing it for all the possible combinations is not optimized. I was looking for any other alternative that is possible
My code for the same
SELECT
COUNT(DISTINCT A.id) table1,
COUNT(DISTINCT B.id) table2,
COUNT(DISTINCT C.id) table3,
COUNT(DISTINCT D.id) table4
FROM table1 A
LEFT JOIN table2 B
ON A.id = B.id
LEFT JOIN table3 C
ON A.id = C.id
LEFT JOIN table4 D
ON A.id = D.id
db-fiddle (This fiddle is for mysql, I am looking for a generic SQL based approach than any db specific approach)
I would recommend:
with t as (
select 'table1' as which, id from table1 union all
select 'table2' as which, id from table2 union all
select 'table3' as which, id from table3 union all
select 'table4' as which, id from table4
)
select ta.which,
sum(case when tb.which = 'table1' then 1 else 0 end) as cnt_table1,
sum(case when tb.which = 'table2' then 1 else 0 end) as cnt_table2,
sum(case when tb.which = 'table3' then 1 else 0 end) as cnt_table3,
sum(case when tb.which = 'table4' then 1 else 0 end) as cnt_table4
from t ta left join
t tb
on ta.id = tb.id
group by ta.which;
Note: This assumes that id is unique in each of the tables. That is a reasonable assumption given the name of the column and the sample data. However, if there are duplicates, you can change the union all in the CTE to union.
This structure also readily generalizes to additional tables.
Use UNION ALL
DEMO
select 'table1' as col1,count(table1.id),count(table2.id),count(table3.id),count(table4.id)
from table1
left join table2 on table1.id=table2.id
left join table3 on table1.id=table3.id
left join table4 on table1.id=table4.id
union all
select 'table2' ,count(table1.id),count(table2.id),count(table3.id),count(table4.id)
from table2
left join table1 on table2.id=table1.id
left join table3 on table2.id=table3.id
left join table4 on table2.id=table4.id
union all
select 'table3' ,count(table1.id),count(table2.id),count(table3.id),count(table4.id)
from table3
left join table1 on table3.id=table1.id
left join table2 on table3.id=table2.id
left join table4 on table3.id=table4.id
union all
select 'table4' ,count(table1.id),count(table2.id),count(table3.id),count(table4.id)
from table4
left join table1 on table4.id=table1.id
left join table2 on table4.id=table2.id
left join table3 on table4.id=table3.id
OUTPUT:
col1 tbl1 tbl2 tbl3 tbl4
table1 8 3 2 2
table2 3 6 1 0
table3 2 1 5 0
table4 2 0 0 4
Let s say my two tables keys are comprised of column A and B:
Table 1
Column A Column B
1 1
1 X
2 2
3 3
Table 2
Column A Column B
1 1
2 2
3 3
How do I select only the rows in Table1 where the key only matches partially. My intended result would pulling out row:
Column A Column B
1 X
Basically finding all rows where Column A and B match but where following records were ´left out' in Table 2
select *
from tabl1
join tabl2
on (tabl1.cola == tabl1.cola and tabl1.colb <> tabl1.colb)
or (tabl1.cola <> tabl1.cola and tabl1.colb == tabl1.colb)
join the tables on "partial" match
select t1.*
from table1 t1
join table2 t2 on ((t1.a = t2.a and t1.b <> t2.b) or (t1.a <> t2.a and t1.b = t2.b))
You can solve this problem using NOT-EXISTS subquery:
SELECT
input1.ColumnA,input1.ColumnB
FROM
t1
WHERE
NOT EXIST (
SELECT *
FROM t2
WHERE t1.ColumnB = t2.ColumnB AND t1.ColumnA = t2.ColumnA)
Explanation: you select rows in table1 whose values are not contained in table2.
The have the following 2 table2:
Table1(col1 integer, col2)
1 "This is a string"
2 "This is another string"
5 "This is yet another string"
3 "a"
4 "b"
6 "Some other string"
Table2(col3 integer, col4 integer, col5 integer)
1 2 5
3 4 6
Now I want to find all the values from Table2 where col4=2. This gives me col3=1 and col5=5. Now I want to join this result with Table1 such that I obtain the string values(col2) corresponding to these integers.
That is, I want the result as: "This is a string", "This is yet another string"
The SQL query which I wrote in postgresql is given below:
select d1.col2, d2.col2
from Table1 d1, Table1 d2
where (select col3, col5 from Table2 where col4=0);
However, the above query is giving me error. Can someone please help me write an efficient query for the same.
You could use an INNER JOIN with two conditions on the ON clause:
SELECT Table1.*
FROM
Table1 INNER JOIN Table2
ON Table1.col1 = Table2.col3 OR Table1.col1 = Table2.col5
WHERE
Table2.col4=2
Please see fiddle here.
Try
SELECT t2.col2, t3.col2
FROM Table1 AS t1
INNER JOIN Table2 AS t2 ON t1.col1 = t2.col3
INNER JOIN Table2 AS t3 ON t1.col1 = t2.col5
WHERE t1.col4 = 2
if you want your result as two rows with one column:
select t1.col2
from Table2 as t2
inner join Table1 as t1 on t1.col1 in (t2.col3, t2.col5)
where t2.col4 = 2;
-- output
-- 'This is a string'
-- 'This is yet another string'
if you want your result as one row with two columns:
select t13.col2, t15.col2
from Table2 as t2
inner join Table1 as t13 on t13.col1 = t2.col3
inner join Table1 as t15 on t15.col1 = t2.col5
where t2.col4 = 2
-- output
-- 'This is a string', 'This is yet another string'
sql fiddle demo
try it as a union
select col2 from table1 where col1 in (
select col3 from table2 where col4 = 2
union
select col5 from table2 where col4 = 2
)
I have three tables Tab1, Tab2 and Tab3 with almost same structre (in MS Access). But Tab2 and Tab3 have a few more columns than Tab1.
Tab2 and Tab3 are exactly same structure. Following are the joining keys
col1
col2
col3
Basically Tab1 records should tally with Tab2 and Tab3 together.
If I need to get the missing records in Tab2 and Tab3 when compare to Tab1 what could be the efficient way
Appreciate your response
If you only care about the keys, here is a good approach:
select col1, sum(isTab1) as numTab1, sum(isTab2) as numTab2, sum(isTab3) as numTab3
from ((select col1 as col, 1 as isTab1, 0 as isTab2, 0 as isTab3 from tab1
) union all
(select col2, 0 as isTab1, 1 as isTab2, 0 as isTab3 from tab2
) union all
(select col3, 0 as isTab1, 0 as isTab2, 1 as isTab3 from tab3
)
) t
group by col
having sum(isTab1)*sum(isTab2)*sum(isTab3) <> 1
This returns each of the key values and tells you which tables they are in and not in, for keys that are not in all three tables. As a bonus, this will also tell you if any of the tables have duplicate keys.
usually you would SELECT FROM tab1 LEFT JOINing the tab2 and tab3 LEFT JOINed together. That way you will get ALL records from tab1. When there are some missing records in tab2 and tab3 there will be nulls. You can check for nulls in the WHERE clause
So, the query would look similar to this one (please note the brackets - it is a requirement for ms-access):
SELECT * FROM
tab1 LEFT JOIN (tab2 LEFT JOIN tab3 ON tab2.col1 = tab3.col1 AND tab2.col2 = tab3.col2)
ON tab1.col1 = tab2.col1 AND tab1.col2 = tab2.col2
WHERE tab2.col1 Is Null;