Remove duplicates from inner join with one table - sql

I have following table
id | cId
---------------
1 | 1
2 | 1
3 | 2
4 | 2
I need help with query, that return following result
id1 | id2 | cId
----------------------
1 | 2 | 1
3 | 4 | 2
SELECT s1.id firstC, s2.id secondC
FROM SingleTable s1 inner join SingleTable s2 on s1.cId = s2.cId
But i get duplicates. I want gte result without duplicates.
My result:
id1 | id2 | cId
---------------
1 | 1 | 1
2 | 1 | 1
1 | 2 | 1
2 | 2 | 1
3 | 3 | 2
4 | 3 | 2
3 | 4 | 2
4 | 4 | 2
Please help.

You can just group by the cId and then select the highest and lowest id for every cId
SELECT cId,
min(id) as id1,
max(id) as id2
FROM SingleTable
GROUP BY cId

Remove the duplicates (s1.id = s2.id) with an extra condition (s1.id < s2.id):
SELECT s1.id firstC, s2.id secondC
FROM SingleTable s1 INNER JOIN SingleTable s2
ON (s1.cId = s2.cId AND s1.id < s2.id)

Related

Create column based on multiple possible tables using SQL

We want to add the column doc_val to the Main table such that the value will be the val of the table determined by the doc_type at the row determined by doc_id.
For example, the first value of val will be 57 because in the first row of Main the doc_type is 'doc_a' and the doc_id is 1 and the val of id 1 in table A is 57.
Table Main
id | doc_type | doc_id
----------------------
1 | 'doc_a' | 1
2 | 'doc_a' | 2
3 | 'doc_b' | 3
4 | 'doc_c' | 1
5 | 'doc_c' | 3
Table A Table B Table C
id | val id | val id | val
-------- -------- --------
1 | 57 1 | 33 1 | 55
2 | 63 2 | 26 2 | 22
3 | 72 3 | 19 3 | 54
The table we want is below.
id | doc_type | doc_id | doc_val
--------------------------------
1 | 'doc_a' | 1 | 57
2 | 'doc_a' | 2 | 63
3 | 'doc_b' | 3 | 19
4 | 'doc_c' | 1 | 55
5 | 'doc_c' | 3 | 54
How can we do this with an SQL query?
You can use left join:
select m.*, coalesce(a.val, b.val, c.val) as val
from main m left join
a
on m.doc_id = a.id and m.doc_type = 'doc_a' left join
b
on m.doc_id = b.id and m.doc_type = 'doc_b' left join
c
on m.doc_id = c.id and m.doc_type = 'doc_c';
An alternative method (which is probably less performant) uses union all:
select m.*, abc.val
from main left join
((select id, 'doc_a' as doc_type, val from a
) union all
(select id, 'doc_b' as doc_type, val from b
) union all
(select id, 'doc_c' as doc_type, val from c
)
) abc
on m.id = abc.id and m.doc_type = abc.doc_type;

Postgres SQL query to get the first row of distinct id

channels table
id | name
------------
1 | ABC
2 | XYZ
3 | MNO
4 | ASD
user_channels table
user_id | channel_id
----------------------
555 | 1
666 | 1
777 | 1
555 | 2
888 | 2
999 | 3
555 | 3
user_chats table
id | created_at | channel_id | content
---------------------------------------
2 | time 1 | 1 | Hello
3 | time 2 | 1 | Hi
4 | time 3 | 2 | Good day
5 | time 4 | 2 | Morning
I have these 3 tables in postgres SQL,
I want to write a sql query to get user_channels by user_id and it's latest message only (time 1 is oldest message) from user_chats table. How can I do that?
For example, for user_id = 555, the query should return
channel_id | content | created_at
---------------------------------------
1 | Hi | time 2
2 | Morning | time 4
3 | Null | Null
Use distinct on:
select distinct on (a.channel_id) a.*
from user_chats a
inner join user_channels l on l.channel_id = a.channel_id
where l.user_id = 555
order by a.channel_id, a.createt_at desc
If you want this for all users at once:
select distinct on (l.user_id, a.channel_id) l.user_id, a.*
from user_chats a
inner join user_channels l on l.channel_id = a.channel_id
order by l.user_id, a.channel_id, a.createt_at desc
You can use distinct on:
select distinct on (c.channel_id) c.channel_id, uc.content, uc.created_at
from user_channels c left join
user_chats uc
on uc.channel_id = c.channel_id
where c.user_id = ?
order by c.idchannel_id, uc.created_at desc;

How to get count from one table which is mutually dependent to another table

I have two table
Let's name as first table: QC_Meeting_Master
Second table: QC_Project_Master I want to calculate count of problems_ID Which is mutually depend on second table
ID | QC_ID | Problems_ID |
___|_______|_____________|
1 | 1 | 2 |
2 | 1 | 7 |
ID | QC_ID | Problem_ID |
___|_______|_____________|
1 | 1 | 7 |
2 | 1 | 7 |
3 | 1 | 7 |
4 | 1 | 7 |
5 | 1 | 2 |
6 | 1 | 2 |
7 | 1 | 2 |
select COUNT(Problem_ID) from [QC_Project_Master] where Problem_ID in
(select Problems_ID from QC_Meeting_Master QMM join QC_Project_Master QPM on QMM.Problems_ID = QPM.Problem_ID)
I have to calculate Count of QC_Project_Master (problem_ID) on basis of QC_Meeting_Master (Problems_ID)
it means for first table: QC_Meeting_Master(Problems_ID) = 2,
then count should be 3
And for Second table: QC_Project_Master (Problems_ID) = 7,
then count should be 4
use conditional aggregation
select sum(case when t2.Problem_ID=2 then 1 else 0 end),
sum(case when t2.Problem_ID=7 then 1 else 0 end) from
table1 t1 join table2 t2 on t1.QC_ID=t2.QC_ID and t1.Problems_ID=t2.Problems_ID
if you need all the group count then use below
select t2.QC_ID,t2.Problems_ID, count(*) from
table1 t1 join table2 t2
on t1.QC_ID=t2.QC_ID and t1.Problems_ID=t2.Problems_ID
group by t2.QC_ID,t2.Problems_ID
As far as I understood your problem this is simple aggregation and JOIN as below:
SELECT mm.QC_ID, mm.Problem_ID, pm.cnt
FROM QC_Meeting_Master mm
INNER JOIN
(
SELECT QC_ID, Problem_ID, COUNT(*) cnt
FROM QC_Project_Master
GROUP BY QC_ID, Problem_ID
) pm
ON pm.QC_ID = mm.QC_ID AND pm.Problem_ID = mm.Problem_ID;

select records where condition is true in one record

I need to select cid, project, and owner from rows in the table below where one or more rows for a cid/project combination has an owner of 1.
cid | project | phase | task | owner
-----------------------------------
1 | 1 | 1 | 1 | 1
1 | 1 | 1 | 2 | 2
1 | 1 | 1 | 3 | 2
2 | 1 | 1 | 1 | 1
2 | 1 | 1 | 2 | 1
3 | 1 | 1 | 3 | 2
My output table should look like the this:
cid | project | phase | task | owner
-----------------------------------
1 | 1 | 1 | 1 | 1
1 | 1 | 1 | 2 | 2
1 | 1 | 1 | 3 | 2
2 | 1 | 1 | 1 | 1
2 | 1 | 1 | 2 | 1
The below query is what I came up with. It does seem to test okay, but my confidence is low. Is the query an effective way to solve the problem?
select task1.cid, task1.project, task1.owner
from
(select cid, project, owner from table) task1
right join
(select distinct cid, project, owner from table where owner = 1) task2
on task1.cid = task2.cid and task1.project = task2.project
(I did not remove the phase and task columns from the sample output so that it would be easier to compare.)
You can simply use a IN clause
select cid, project, owner
from table
where cid in (select distinct id from table where owner = 1)
or a inner join with a subquery
select a.cid, a.project, a.owner
from table a
INNER JOIN ( select distinct cid , project
from table where owner = 1
) t on t.cid = a.cid and t.project = a.project

Join two or more tables that have no common fields

I have 3 tables in a database
Project Material Used Document
------------ ------------------- ------------------------
PID | Name MID | PID | Name DocID | PID | Date
------------ ------------------- ------------------------
1 | A 1 | 1 | A1 1 | 1 | 1/1/2016
2 | B 2 | 1 | A1 2 | 1 | 1/2/2016
3 | C 3 | 1 | A1 3 | 2 | 1/3/2016
4 | 2 | A1 4 | 2 | 1/4/2016
5 | 2 | A1 5 | 2 | 1/5/2016
6 | 3 | A1 6 | 2 | 1/6/2016
7 | 3 | A1 7 | 2 | 1/7/2016
8 | 3 | A1 8 | 1 | 1/8/2016
9 | 3 | A1 9 | 1 | 1/9/2016
How to query with the results like below ?
------------------------------------------------------------------------
PID Project Name MID Material Name DocID Date
------------------------------------------------------------------------
1 A 1 A1 1 1/1/2016
1 A 2 A2 2 1/2/2016
1 A 3 A3 NULL NULL
2 B 4 B1 3 1/3/2016
2 B 5 B2 4 1/4/2016
2 B NULL NULL 5 1/5/2016
2 B NULL NULL 6 1/6/2016
2 B NULL NULL 7 1/7/2016
3 C 6 C1 8 1/8/2016
3 C 7 C2 9 1/9/2016
3 C 8 C3 NULL NULL
3 C 9 C4 NULL NULL
PID in Material and Document table is Foreign Key.
I am using Microsoft SQL 2008.
Is it possible ?
You seem to want lists in the columns. You can get this using full outer join and row_number():
select p.*, m.mid, m.name, d.docid, d.date
from project p left join
(select m.*, row_number() over (partition by pid order by mid) as seqnum
from materials
) m
on p.pid = m.pid full outer join
(select d.*, row_number() over (partition by pid order by docid) as seqnum
from documents
) d
on p.pid = d.pid and m.seqnum = d.seqnum;
Hmmm, try this version:
select p.*, md.mid, md.name, md.docid, md.date
from project p left join
(select m.id, m.name, d.docid, d.date
from (select m.*, row_number() over (partition by pid order by mid) as seqnum
from materials
) m full outer join
(select d.*, row_number() over (partition by pid order by docid) as seqnum
from documents
) d
on p.pid = d.pid and m.seqnum = d.seqnum
) md
on p.pid = md.pid;