I have following senario
table1 - having 1 record with 1001(primary key)
table2 - having 3 record with same id (1001) - not as primary key
table3 - having 3 record with same id (1001) - not as primary key
The join of the first 2 tables is returning 3 rows (it is fine). But, if I join table3 then it is returning 9 rows. I know how join work and result is expected.
I need only 3 rows in result. something like shown below
id name age sex city
1001 Jhon 20 A Z
1001 Jhon 20 B Y
1001 Jhon 20 C X
Here is fiddle example
This query may do what you ask for. To change the combination between Table2 and Table3 you can work on the two ORDER BY clauses. Really strange requierement anyway! Are you sure you're doing it right?
with ord_t2 as (
select idt1 as id, sex, row_number() over(partition by idt1 order by sex) as ord_no
from table2 t2
), ord_t3 as (
select idt3 as id, city, row_number() over(partition by idt3 order by city) as ord_no
from table3 t3
), t2_x_t3 as (
select id, sex, city
from ord_t2
natural full outer join ord_t3
)
select *
from Table1
natural left join t2_x_t3
Related
I am trying to get all id, std_name from table1, and all id, score from table2 where std_id of table2 matches the id of table1 and deleted_at should be null for all entries of table1 and table2. But table2 can have duplicate std_ids, in that case, I only want the entries with the maximum id number from table2.
Sample table1:
id
std_name
deleted_at
1
jhon
null
2
sam
null
3
joe
null
Sample table2:
id
std_id
score
deleted_at
1
1
10
null
2
2
20
null
3
1
30
null
So far I have tried using this query:
const query = knex.select([
't1.id as t1id',
't1.std_name as name',
't2.score as score'
])
.from('table1 as t1')
.leftJoin('table2 as t2', function () {
this.on('t2.std_id', '=', 't1.id')
})
.joinRaw('left join (select MAX(id) as id, std_id from table2 group by std_id) as kst on kst.std_id = t2.std_id');
query.where({'t1.deleted_at': null}).orderBy('t1.id')
Results generated for the above query:
id
name
score
1
jhon
30
2
sam
20
But this only returns the maximum id entry of the duplicate entries from table2 and omits the entries of table1, but I also want the ids from table1 which are not included in the std_id of table2.
My desired output:
id
name
score
1
jhon
30
2
sam
20
3
joe
null
You can use window functions. In SQL this looks like:
select t1.*, t2.score
from table1 t1 left join
(select t2.*,
row_number() over (partition by t2.std_id order by t2.id desc) as seqnum
from table2 t2
) t2
on t2.std_id = t1.id and t2.seqnum = 1;
I have a oracle table called table1 that has a foreign key from table2.
table2 has 2 columns: id, name
table2.name has a lot of duplicates that need to be sorted out, so I grouped table2 by name and kept only 1 id for each name.
However, table1.table2_id uses a lot of the duplicated fields.
How can I change all the table1.table2_id fields so that there are no duplicate names?
Currently:
table1:
id
blabla
table2_id
1
row
1001
2
row
1002
3
row
1003
4
row
1004
5
row
1004
6
row
1005
table2:
id
name
1001
Bob
1002
Bob
1003
Bob
1004
Jack
1005
Jack
Desired Result:
table1:
id
blabla
table2_id
1
row
1001
2
row
1001
3
row
1001
4
row
1004
5
row
1004
6
row
1004
table2:
id
name
1001
Bob
1004
Jack
So imo, I would need to:
update all table1.table2_id to top 1 table2.id grouped by name
delete duplicate rows from table2
And as there are thousands of duplicate fields in table2, I cannot use case for this..
The solution I am trying returns 1 id for each name, but I am failing at the part where I can update the table.
update table1 d
set d.table2_id =
(select
b.id
from table2 b
where b.name in (select min(id) keep(dense_rank first order by id) id
, name
from table2
group by name)
order by b.id ASC
)
where d.table2_id in ( SELECT b.id FROM table2 b WHERE b.name in (select min(id) keep(dense_rank first order by id) id
, name
from table2
group by name));
Please help :)
Here are syntactically correct Oracle statements
update table1 t1
set t1.table2_id = (
select new_id
from (
select id, min(id) over (partition by name) new_id
from table2
) d
where d.id = t1.table2_id
);
delete from table2
where id not in (
select min(id) from table2 group by name
);
The analytic function min(id) over (partition by name) is used here so that you can have all original ids together with their new ids (the min ids from the set where the name is the same).
here is one way:
update table1 d
set d.table2_id = x.id_tokeep
from
(
select name , id , min(id) over (partition by name ) as id_tokeep
from table2
) x
where x.id = d.table2_id
delete from table2
where id not in ( select min(id) from table2 group by name)
These are my sample tables, columns and records...
Table: tbl1
-----------------------
Columns: ID | DEPT | WK | MANHRS
Records: 01 A 1 8
02 A 2 2
Table: tbl2
--------------------------------
Columns: ID | DEPT | WK | WAGES
Records: 01 A 1 3
02 A 2 5
Scenario:
I want to have a result where two tables are joined and MANHRS and WAGES columns are both together in the result set.
Expected output of the result table:
Columns: ID | DEPT | WK | MANHRS | WAGES
01 A 1 8 3
02 A 2 2 5
I tried UNION but didn't get my expected result. :(
How to do this?
The proper way to write the query is:
SELECT t1.*, t2.WAGES
FROM tbl1 t1 JOIN
tbl2 t2
ON t1.DEPT = t2.DEPT and t1.WK = t2.WK;
Notes:
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
I'm not sure if ID should be in the JOIN conditions.
If you want all rows in both tables, but some might be missing, then use FULL JOIN.
You can write the query with the USING clause:
SELECT ID, DEPT, WK, t1.MANHRS, t2.WAGES
FROM tbl1 t1 JOIN
tbl2 t2
USING (ID, DEPT, WK);
This is particularly useful if you are using a FULL JOIN.
Assuming that you should join by DEPT and WK:
SELECT t1.*, t2.WAGES
FROM tbl1 t1, tbl2 t2
where t1.DEPT = t2.DEPT and t1.WK = t2.WK
Here is my sqlfiddle http://sqlfiddle.com/#!3/671c8/1.
Here are my tables:
Person
PID LNAME FNAME
1 Bob Joe
2 Smith John
3 Johnson Jake
4 Doe Jane
Table1
PID VALUE
1 3
1 5
1 35
2 10
2 15
3 8
Table2
PID VALUE
1 X1
1 X2
1 X3
2 Z1
3 X3
I am trying to join several tables on a person's ID. These tables contain events with dates, but the dates may or may not match across table. So what I really want it to regardless of date join the tables in a way such that when I get results the table with the largest rows will be the amount of rows in my result and all other tables will "fit" within. For example
Instead of this which is a cartesian product:
PID LNAME FNAME THINGONE THINGTWO
1 Bob Joe 3 X1
1 Bob Joe 3 X2
1 Bob Joe 3 X3
1 Bob Joe 5 X1
1 Bob Joe 5 X2
1 Bob Joe 5 X3
1 Bob Joe 35 X1
1 Bob Joe 35 X2
1 Bob Joe 35 X3
I would like something like this:
PID LNAME FNAME THINGONE THINGTWO
1 Bob Joe 3 X1
1 Bob Joe 5 X2
1 Bob Joe 35 X3
My sql statement:
SELECT
p.*,
t1.value as thingone,
t2.value as thingtwo
FROM
person p
left outer join table1 t1 on p.pid=t1.pid
left outer join table2 t2 on p.pid=t2.pid
;
I can't fathom why you want to do this, but...
You need to create an artificial join between table1 and table2, and then link that to the master table. One way of doing that is by ranking the rows in order. eg:
SELECT
p.pid, p.lname,p.fname, thingone, thingtwo
FROM
person p
left outer join
(
select ISNULL(t1.pid, t2.pid) as pid, t1.value as thingone, t2.value as thingtwo
from
(select *, ROW_NUMBER() over (partition by pid order by value) rn
from table1) t1
full outer join
(select *, ROW_NUMBER() over (partition by pid order by value) rn
from table2) t2
on t1.pid=t2.pid and t1.rn=t2.rn
) v
on p.pid = v.pid
This is a trickier problem than I thought. The challenge is being sure that all the records appear, regardless of the lengths of the two lists. The following works by enumerating each of the lists and using that for the join conditions:
SELECT p.*,
t1.value as thingone,
t2.value as thingtwo
FROM person p left outer join
(select t1.*,
row_number() over (partition by pid order by pid) as seqnum,
count(*) over (partition by pid) as cnt
from table1 t1
) t1
on p.pid = t1.pid left outer join
(select t2.*, row_number() over (partition by pid order by pid) as seqnum,
count(*) over (partition by pid) as cnt
from table2 t2
) t2
on p.pid = t2.pid
WHERE t1.seqnum = t2.seqnum or
(t2.seqnum > t1.cnt) or
(t1.seqnum > t2.cnt) or
t1.seqnum is null or
t2.seqnum is null;
Here is a slight modification to your SQL Fiddle that has better test data.
EDIT:
The logic in the where clause handles these cases (in order by the clauses):
Where the two lists have sequence numbers, these must match.
Where list2 is longer and list1 has at least one element.
Where list1 is longer and list2 has at least one element.
Where list1 is empty
Where list 2 is empty
These were arrived at by trial and error, because the original condition did not work:
on p.pid = t2.pid and t1.seqnum = t2.seqnum
This returns NULL values for p.id for the extra elements on the list. Podliuska's approach may also work; I had just started down this path and the where conditions do the trick.
I am attempting to do something using MSSQL that I believe is possible (easily) but I do not know how to vocalize the correct search string. I have the situation below.
Table A
UID | Value....
1 | a
2 | b
3 | c
Table B
PartTypes_uid_fk | Value....
1 | a
1 | b
1 | c
1 | d
1 | e
3 | 67
3 | 1354
I am attempting to get the following result, query Table A for all results {TableA.*} and on the same row result show the number of table b references {count TableB.tableA_fk}
What I have so far is the following.
SELECT DISTINCT t1.uid, CONVERT(varchar(MAX), t1.Name) AS Name, CONVERT(varchar(MAX), t1.Description) AS Description,
Count(t2.Items_uid_fk) OVER (Partition By t2.PartTypes_uid_fk) as Count
FROM [Table1] as t1 left outer join Table2 as t2 on t2.PartTypes_uid_fk=t1.uid;
This works for all of Table A records with an associated record in Table B but if there are 0 entries in Table B it won't work. The conversion of the varchars was required due to the fact they are ntext format and it was distinct.
Thank you for all your help in advance.
Stephen
Instead of running into problems with the GROUP BY on N/TEXT columns, and to run faster, you would want to pre-aggregate the B table and LEFT JOIN that against A.
select t1.*, ISNULL(t2.c, 0) AS CountOfB
from table1 t1
left join
(
select parttypes_uid_fk, count(*) c
from table2
group by parttypes_uid_fk
) t2 on t2.PartTypes_uid_fk=t1.uid
It's easier than that:
SELECT t1.uid, t1.Name, COUNT(*)
FROM [Table1] t1
LEFT JOIN [Table2] t2 ON t2.PartTypes_uid_fk = t1.uid
GROUP BY t1.uid, t1.Name
Your query should be
SELECT t1.uid,
CONVERT(varchar(MAX), t1.Name) AS Name,
CONVERT(varchar(MAX), t1.Description) AS Description,
Count(t2.Items_uid_fk) CountItems
FROM [Table1] as t1 left outer join Table2 as t2 on t1.uid = t2.PartTypes_uid_fk
GROUP BY uid, t1.name, t1.Description;