Parse 2 records into one and join tables - sql

Reviewed
+----+--------------------- +------+-------+
| id | POS | Review Date| Role |app ID |
+----+----------------------+------+-------+
| 1 | A | 2018-12-03 | E | 170 |
| 2 | A | 2018-12-04 | P | 170 |
| 3 | B | 2018-12-01 | E | 180 |
| 4 | B | 2018-12-05 | P | 180 |
| 5 | B | 2018-12-05 | X | 190 |
| 6 | B | 2018-12-05 | w | 195 |
| 7 | C | 2018-12-06 | w | 170 |
+----+--------+-------------+------+-------+
Call_Center
+----+------+-----+------+
| id | POS | Emp| yrs |
+----+------+-----+------+
| 1 | A | F | 4 |
| 2 | B | F | 3 |
| 3 | C | P | 3 |
+----+------+-----+------+
Need Call Center joined; also, forgot that there can be many roles(x, w, u, t), but just interested in combining reviewed date for Roles E and P.
Need to return one record for each unique POS, including both review_dates for ONLY roles E and P; only app id 170; EMP and yrs from call_center, joining on POS
For example:
POS Review_Date(role E) Review_Date(role P) EMP Yrs app ID
A 2018-12-03 2018-12-04 F 4 170
See updated tables
Oracle syntax please

You could use case when to filter the dates matching the desired role, and combine that with a group by (and max):
select Pos,
max(case Role when 'E' then review_date end) review_E,
max(case Role when 'P' then review_date end) review_P
from reviewed
group by Pos
You can also use the pivot clause available since Oracle 11g:
select *
from (
select Pos, Role, review_date
from reviewed
)
pivot
(
max(review_date)
for Role
in ('E', 'P')
);

I would use two CTEs:
with
e as (
select * from reviewed where role = 'E'
),
p as (
select * from reviewed where role = 'P'
)
select
coalesce(e.pos, p.pos) as pos,
e.review_date as review_date_role_e,
p.review_date as review_date_role_p
from e
full outer join p on e.pos = p.pos
order by coalesce(e.pos, p.pos)

select A.POS, A.review_date as review_date1, a.ROLE as ROLE1, B.review_date as
review_date2, B.ROLE as ROLE2
from reviewed a
left join reviewed b
on a.POS = b.POS
and a.review_date < b.review_date
where B.ROLE is not null
;

Related

Query to show top 3 records per user where the user has submitted a minimum of 3?

I have in a table in MS SQL with multiple entries per user. I am trying to get the top 3 entries by date for each user. I have a query that returns returns the maximum top 3 entries per user but is also returning users which have submitted 2 or 1 entries. I have a join with another table only to get the email address. I would like it to return only the entries by john and dave as they have 3 entries. If they have more than 3 just return the top 3 by submitmonth.
select * from (
select m.Email, q.submitmonth, q.A2, q.A7, q.C7, q.C8, q.C16, q.F9, q.F10, q.G4, q.H1, q.H2, q.J2, q.J13, q.K18, q.N1, q.P6,
row_number() over (partition by q.userid order by q.submitmonth desc) as Submitted
from dbo.submission q
left join dbo.users m
on q.UserId = m.UserId ) ranks
where Submitted < 4
this returns
| Email | submitmonth | A2 | A7 | Submitted
| | | | |
| john#yahoo.com | 01/08/2020 | 2 | 4 | 1
| john#yahoo.com | 01/07/2020 | 8 | 8 | 2
| john#yahoo.com | 01/06/2020 | 2 | 1 | 3
| bob#gmail.com | 01/08/2020 | 1 | 3 | 1
| bob#gmail.com | 01/07/2020 | 9 | 7 | 2
| pete#yahoo.co.uk | 01/08/2020 | 8 | 5 | 1
| dave#gmail.com | 01/06/2020 | 3 | 6 | 1
| dave#gmail.com | 01/04/2020 | 5 | 6 | 2
| dave#gmail.com | 01/02/2020 | 1 | 6 | 3
Thanks for your help.
Add the count window function and then filter on it.
select *
from (
select m.Email, q.submitmonth, q.A2, q.A7, q.C7, q.C8, q.C16, q.F9, q.F10, q.G4, q.H1, q.H2, q.J2, q.J13, q.K18, q.N1, q.P6
, row_number() over (partition by q.userid order by q.submitmonth desc) as Submitted
, count(*) over (partition by q.userid) TotalSubmitted
from dbo.submission q
left join dbo.users m on q.UserId = m.UserId
) ranks
where Submitted < 4 and TotalSubmitted >= 3

List only repeating names

| personid | first | last | section |
| 1 | Jon | A | y3 |
| 2 | Bob | Z | t6 |
| 3 | Pat | G | h4 |
| 4 | Ron | Z | u3 |
| 5 | Sam | D | y3 |
| 6 | Sam | D | u3 |
| 7 | Pam | F | h4 |
I want to isolate all the repeat names, despite the other columns, like this:
| personid | first | last | section |
| 5 | Sam | D | y3 |
| 6 | Sam | D | u3 |
This is what I came up with but I cannot get it to work:
SELECT personid, last, first, section FROM d 01 WHERE EXISTS
(SELECT * FROM d 02 WHERE 02.last = 01.last AND 02.first = 01.first )
You could just do a window count and filter by that:
select personid, first, last, section
from (
select t.*, count(*) over(partition by first, last) cnt
from mytable t
) t
where cnt > 1
You must check that the 2 rows have different ids:
SELECT d1.personid, d1.last, d1.first, d1.section
FROM d d1 WHERE EXISTS (
SELECT *
FROM d d2
WHERE d1.personid <> d2.personid AND d2.last = d1.last AND d2.first = d1.first
)
Always qualify the column names with the table's name/alias and don't use numbers as aliases unless they are enclosed in backticks or square brackets.
See the demo.
Results:
| personid | last | first | section |
| -------- | ---- | ----- | ------- |
| 5 | D | Sam | y3 |
| 6 | D | Sam | u3 |
Another way to yield the same results as the other accepted answer:
SELECT personid,
A.firstName,
A.lastName,
section
FROM personTable as A
INNER JOIN (
SELECT
firstName,
lastName,
CASE
WHEN COUNT(*)>1 THEN 'Yes'
ELSE 'Null' , AS UseName
FROM
personTable
WHERE UseName='Yes') as B
ON A.firstName=B.firstName AND A.lastName=B.lastName
This solution subqueries itself. Since it is an inner join, it will only pull the values that join onto the subquery. Since I filtered anything with a count less than 2 out, only the duplicates will match.

SQL server 2008: join 3 tables and select last entered record from child table against each parent record

I have following 3 tables and last entered reasoncode from Reasons table against each claimno in claims table.
Reasons:
Rid |chargeid| enterydate user reasoncode
-----|--------|-------------|--------|----------
1 | 210 | 04/03/2018 | john | 99
2 | 212 | 05/03/2018 | juliet | 24
5 | 212 | 26/12/2018 | umar | 55
3 | 212 | 07/03/2018 | borat | 30
4 | 211 | 03/03/2018 | Juliet | 20
6 | 213 | 03/03/2018 | borat | 50
7 | 213 | 24/12/2018 | umer | 60
8 | 214 | 01/01/2019 | john | 70
Charges:
chargeid |claim# | amount
---------|-------|---------
210 | 1 | 10
211 | 1 | 24.2
212 | 2 | 5.45
213 | 2 | 76.30
214 | 1 | 2.10
Claims:
claimno | Code | Code
--------|-------|------
1 | AH22 | AH22
2 | BB32 | BB32
Expected result would be like this:
claimno | enterydate | user | reasoncode
--------|-------------|--------|-----------
1 | 01/01/2019 | john | 70
2 | 26/12/2018 | umer | 55
I have applied many solutions but no luck. Following is the latest solution I was trying using SQL Server 2008 but still got incorrect result.
With x As
(
select r.chargeid,r.enterydate,ch.claimno from charges ch
join (select chargeid,max(enterydate) enterydate,user from Reasons group by chargeid) r on r.chargeid = ch.chargeid
)
select x.*,r1.user, r1.reasoncode from x
left outer join Reasons r1 on r1.chargeid = x.chargeid and r1.enterydate = x.enterydate
--group by x.claimno
Is this what you want?
select claimno, enterydate, user, reasoncode
from (select c.claimno, r.*,
row_number() over (partition by c.claimno order by r.entrydate desc) as seqnum
from charges c join
reasons r
on c.chargeid = r.chargeid
) cr
where seqnum = 1;
You can try using row_number()
select * from
(
select r.chargeid,r.enterydate,ch.claimno,user,reasoncode,
row_number() over(partition by ch.claimno order by r1.enterydate desc) as rn
from charges ch left outer join Reasons r1 on r1.chargeid = ch.chargeid
)A where rn=1

Select if data has two instances with different values sql

I have a table with multiple instances of title some hardcover (h) and some paperback (p)
title | type
-----------------------------+------
Franklin in the Dark | p
Little Women | p
The Cat in the Hat | p
Dune | p
The Shining | p
Programming Python | p
Goodnight Moon | p
2001: A Space Odyssey | h
Dynamic Anatomy | p
Bartholomew and the Oobleck | p
The Cat in the Hat | h
Dune | h
The Velveteen Rabbit | p
The Shining | h
The Tell-Tale Heart | p
2001: A Space Odyssey | p
I'm trying to return instances that have both paper back and hardcover copies.
The table should ideally return only 4 titles.
*edit these are part of two different tables.
7808 | The Shining | 4156 | 9
4513 | Dune | 1866 | 15
4267 | 2001: A Space Odyssey | 2001 | 15
1608 | The Cat in the Hat | 1809 | 2
1590 | Bartholomew and the Oobleck | 1809 | 2
25908 | Franklin in the Dark | 15990 | 2
0385121679 | 7808 | 2 | 75 | 1993-10-01 | h
1885418035 | 156 | 1 | 163 | 1995-03-28 | p
0929605942 | 156 | 2 | 171 | 1998-12-01 | p
0441172717 | 4513 | 2 | 99 | 1998-09-01 | p
044100590X | 4513 | 3 | 99 | 1999-10-01 | h
0451457994 | 4267 | 3 | 101 | 2000-09-12 | p
0451198492 | 4267 | 3 | 101 | 1999-10-01 | h
0823015505 | 2038 | 1 | 62 | 1958-01-01 | p
0596000855 | 41473 | 2 | 113 | 2001-03-01 | p
This could also work.
SELECT TITLE
FROM BOOKS
GROUP BY TITLE
HAVING COUNT(DISTINCT TYPE) > 1
there are a couple ways of doing this. If you just want the title of the book that has both a hard cover and a paperback (I'm assuming those are the only two options). Then you can do a query like this:
select title, count(*) from book group by title having count(*) > 1
You also could join to the table.
select t0.title from
(
select title from book where btype = 'h'
) t0
inner join
(
select title from book where btype = 'p'
) t1 on t0.title = t1.title
Edited for the two tables
select * from table_one where bookid in (
select t0.bookid
from
(
select bookid from table_two where type = 'h'
) t0
inner join
(
select bookid from table_two where type = 'p'
) t1
on t0.bookid = t1.bookid
) t2
Does this work for you?
SELECT title
FROM table a
WHERE type = 'h' AND
EXISTS (SELECT 1
FROM table
WHERE title = a.title AND
type = 'p')

how to sql query 2 tables and group by?

i have 2 tables: activities and users.
users has columns: name, active
activities: name, type, time, user_id.
for example i have these tables:
users
-----
id | name | active
1 | marc | true
2 | john | true
3 | mary | true
4 | nico | true
activities
-----
id | name | type | time | user_id
1 | morn | walk | 90 | 2
2 | morn | walk | 22 | 2
3 | morn | run | 12 | 2
4 | sat | walk | 22 | 1
5 | morn | run | 13 | 1
6 | mond | walk | 22 | 3
7 | morn | walk | 22 | 2
8 | even | run | 42 | 1
9 | morn | walk | 22 | 3
10 | morn | walk | 62 | 1
11 | morn | run | 22 | 3
now i would like to get table that would sum time spent on each type of activity and would group it by user name. so:
result
------
user name | type | time
marc | walk | 84
marc | run | 55
john | walk | 134
john | run | 12
mary | walk | 44
mary | run | 2
nico | walk | 0
nico | run | 0
how should i write this query to get this result?
thanks in advance
gerard
you can use coalesce to get 0 for empty activities and distinct to get all type of possible activities
select
u.name, c.type,
coalesce(sum(a.time), 0) as time
from (select distinct type from activities) as c
cross join users as u
left outer join activities as a on a.user_id = u.id and a.type = c.type
group by u.name, c.type
order by u.name, c.type
sql fiddle demo
Select u.name, a.type, SUM(a.time) FROM
activities a
LEFT JOIN users u
ON a.user_id = u.id
GROUP BY u.name, a.type
FIDDLE
Use this to get zero count as well
SELECT c.name,c.type,aa.time FROM
(Select u.id,u.name, b.type FROM
users u
CROSS JOIN (SELECT DISTINCT type FROM activities) b) c
LEFT JOIN (SELECT a.user_id, a.type, SUM(a.time) as time FROM
activities a
GROUP BY a.user_id, a.type) aa ON
aa.user_id = c.id and c.type = aa.type
Fiddle2
this might work :
select users.name,activities.type,sum(activities.time)
from users left join activities on users.id = activities.user_id
where users.active group by users.name,activities.type