How do I write sql query from this result? - sql

I wasn't sure what could be the title for my question so sorry about that.
I'm trying to write a SQL query to achieve the no. of members who should get reimbursed from a pharmacy.
For example : I went to pharmacy, I took a vaccine but by mistake I paid from my pocket. so now Pharmacy needs to reimburse me that amount. Lets say I have the data like:
MemberId Name ServiceDate PresNumber PersonId ClaimId AdminFee(in $)
1 John 1/1/2011 123 345 456 0
1 John 1/21/2011 123 345 987 20
2 Mike 2/3/2011 234 567 342 0
2 Mike 2/25/2011 234 567 564 30
5 Linda 1/4/2011 432 543 575 0
5 Linda 4/6/2011 987 543 890 0
6 Sonia 2/6/2011 656 095 439 0
This data shows all members from that pharmacy who got reimbursed and who haven't.
I need to find out the member having AdminFee 0 but i also need to check another record for the same member having same PresNumber, same PersonId where the ServiceDate falls within 30 Days of the Original Record.
If another record meets this criteria and the AdminFee field contains a value (is NOT 0) then it means that person has already been reimbursed. So from the data you can see John and Mike have already been reimbursed and Linda and Sonia need to be reimbursed.
Can anybody help me how to write an SQL query on this?

You don't mention what SQL engine you're using, so here is some generic SQL. You'll need to adapt the date math and the return of True/False ( in the second option) to whatever engine you're using:
-- Already reimbursed
SELECT * FROM YourTable YT1 WHERE AdminFee = 0 AND EXISTS
(SELECT * FROM YourTable YT2
WHERE YT2.MemberID = YT1.MemberID AND
YT2.PresNumber = YT1.PresNumber AND
YT2.ServiceDate >= YT1.ServiceDate - 30 AND
AdminFee > 0)
-- Need reimbursement
SELECT * FROM YourTable YT1 WHERE AdminFee = 0 AND NOT EXISTS
(SELECT * FROM YourTable YT2
WHERE YT2.MemberID = YT1.MemberID AND
YT2.PresNumber = YT1.PresNumber AND
YT2.ServiceDate >= YT1.ServiceDate - 30 AND
AdminFee > 0)
or
-- Both in one.
SELECT YT1.*,
CASE WHEN YT2.MemberID IS NULL THEN False ELSE True END AS AlreadyReimbursed
FROM YourTable YT1 JOIN YourTable YT2 ON
YT1.MemberID = YT2.MemberID AND
YT1.PresNumber = YT2.PresNumber AND
YT1.ServiceDate <= YT2.ServiceDate + 30
WHERE YT1.AdminFee = 0 AND YT2.AdminFee > 0)

You need to use datediff function in SQL Server and as parameter to pass day and to join the table above by other alias. I do not have SQL Server but I think it should be like this
Select memberid
from PaymentLog p
inner join PaymentLog d on p.serviceid = d.serviceid
and p.memberid = d.memberid
and p.personid = d.personid
Where adminfee = 0
and datediff(day, p.servicedate, d.servicedate) < 30
I called a table paymentlog

Related

SQL to return one row from many

I have the following data
PersonId
City
Type
UpdateDate
123
Boston
P
01/01/2021
123
Boston
M
02/01/2021
130
Detroit
P
01/01/2021
130
Detroit
M
03/01/2021
140
Dallas
M
02/01/2021
140
Dallas
M
03/01/2021
I want a query that returns one row per PersonId. If the Type is "P" return that row otherwise return the row with the minimum UpdateDate. So the query would return:
PersonId
City
Type
UpdateDate
123
Boston
P
01/01/2021
130
Detroit
P
01/01/2021
140
Dallas
M
02/01/2021
In the past I would write a query like
select * from person, address
where person.PersonId = address.PersonId
group by PersonId
having (Type = 'P') or (UpdateDate = min(UpdateDate))
but this is not allowed anymore.
What should my SQL query be in SQL Server?
Presumably you want the most recent address per person. If so, outer apply is very well suited to this problem:
select p.* a.*
from person p outer apply
(select top (1) a.*
from address a
where a.PersonId = p.PersonId
order by (case when a.type = 'P' then 1 else 2 end),
a.updatedate desc
) a;
No aggregation is called for.

Finding records that are only before a given date (SQL)

I've tried multiple queries but none of them work.
It's probably really simple.
Here's an example table :
ordernr debnaam debnr orddat
1 Coca-Cola 123 2019-02-07
12 Altec 456 2019-02-07
123 Coca-Cola 123 2016-01-01
1234 Brady 789 2015-03-18
So the point is to find the clients (debnaam) that haven't ordered since the last 2 years.
In my example the only record should be Brady.
I've tried following query :
SELECT a.ordernr, a.debnaam, a.debnr, a.orddat
FROM orkrg as a
WHERE NOT EXISTS(SELECT b.debnr
FROM orkrg as b
WHERE a.ordernr = b.ordernr
AND b.orddat > CONVERT(date, dateadd(year,-2,getdate())))
Or with a Left outer join :
SELECT *
FROM (
SELECT orkrg.ordernr, orkrg.debnaam, orkrg.debnr, orkrg.orddat
FROM orkrg
WHERE orkrg.orddat < CONVERT(date, dateadd(year,-2,getdate()))
) AS a
LEFT OUTER JOIN
(
SELECT orkrg.ordernr, orkrg.debnaam, orkrg.debnr, orkrg.orddat
FROM orkrg
WHERE orkrg.orddat > CONVERT(date, dateadd(year,-2,getdate()))
) as b
ON a.ordernr = b.ordernr
But I always get following result :
ordernr debnaam debnr orddat
123 Coca-Cola 123 2016-01-01
1234 Brady 789 2015-03-18
Could someone please help me?
Thanks!
select a.*
from orkrg as a
where a.orddat < dateadd(year,-2,getdate()) -- this is kinda not needed
and not exists (select 1 -- NOT EXISTS is a safer option than NOT IN, where a null result can cause issues
from orkrg as b
where a.debnaam = b.debnaam and
b.orddat > dateadd(year,-2,getdate()))
I use not exists over not in as default, see here for why
You need to use DATEDIFF() to filter out the older dates:
SELECT a.ordernr, a.debnaam, a.debnr, a.orddat
FROM orkrg as a
WHERE DATEDIFF(year, a.orddat, GETDATE()) > 2
AND A.debnr NOT IN (SELECT b.debnr FROM orkrg as b WHERE
DATEDIFF(year, b.orddat, GETDATE()) <= 2)
select *
from orders as o
where o.debnr not in (select debnr
from orders as u
where orddat > CONVERT(date, dateadd(year,-2,getdate())))

Fetching same rows that has multiple columns along with other rows

I have a view which results the following rows.
comp Sub-comp Lognum id Firname LAstname
AK AK-G 0 3897 ABC DEF
AK AK-G 0 5432 mark ray
MC MC-A 0 1234 john steve
MC MC-A 0 5678 dan pitcher
MC MC-A 0 9843 james robin
MC MC-A 84 1234 john steve
MC MC-A 84 5678 dan pitcher
MC MC-A 84 9843 james robin
I want to fetch the only the rows that has a lognum (if the same row has 0 also as lognum) along with the other rows that has just 0 as lognum.
The result table should be like this
comp Sub-comp Lognum id Firname LAstname
AK AK-G 0 3897 ABC DEF
AK AK-G 0 5432 mark ray
MC MC-A 84 1234 john steve
MC MC-A 84 5678 dan pitcher
MC MC-A 84 9843 james robin
And the outline of the query is as follows
create view view1 as
select
comp, Sub-comp, "00" as Lognum, id ,Firname ,LAstname
from
table A
inner joins---
UNION
select
select
comp, Sub-comp, Lognum, id ,Firname ,LAstname from
table B
inner joins----
;
Can anyone help?
Thanks!
Try this:
select * from(
select comp,
Sub-comp,
Lognum,
id,
Firname,
LAstname,
row_number() over(partition by id order by lognum desc) rn
from table_name)
where rn = 1;
This will show the line with the biggest lognum grouped by the ID.
This query should work, even in cases where, for a given id value, you have multiple "non-zero" lognum rows.
If you look at the where clause, rows with non-zero lognum values are always returned (t.Lognum != 0). But rows with zero lognum values will also return, but only if the t.rn = 1 condition is true, which will only happen if there aren't any other non-zero lognums for that same id (see the order by clause of the row_number() window function).
select t.comp,
t.Sub-comp,
t.Lognum,
t.id,
t.Firname,
t.LAstname
from (select t.*,
row_number() over (
partition by t.id
order by case when t.lognum = 0 then 1 else 0 end) as rn
from your_view t) t
where t.Lognum != 0 or t.rn = 1

Find count from specific table by specific filter sql server

I am Having table like this:
id candid candname status date time location jobcode
1 12 hhhhhhhhhh Introduce 2014-05-21 14:0 NewYork 10JN
3 12 hhhhhhhhhh Reject 2014-05-21 15:0 AM London 10JN
4 12 hhhhhhhhhh Interview 2014-05-21 15:0 PM Chicago 10JN
5 11 Pinky Bare Introduce 2014-05-21 65:6 India 10JN
6 11 Pinky Bare Interview 2014-05-21 4:56 AM 10JN
7 13 chetan Tae Introduce 2014-05-21 4:54 AM Nagpur faOl
8 13 chetan Tae Interview 2014-05-21 3:45 Pune faOl
9 14 manisha mane Introduce 2014-05-21 3:33 PM Pune faOl
10 18 ranju gondane Introduce 2014-05-28 3:44 Nagpur AQW-06
12 18 ranju gondane Interview 2014-05-28 5:45 45454 AQW-06
13 18 ranju gondane Reject 2014-05-28 43:43 rsds AQW-06
14 19 vandanna rai Introduce 2014-05-28 7:7 yyyr AQW-06
if i use query
SELECT COUNT(*) FROM [tablename]
WHERE
(jobcode='AQW-06')
AND
([status] <> 'Interview' AND [status] <> 'Reject'
AND
[status] <> 'ON-Hold' AND [status] <> 'Hire')
I get count 2 for introduce candidates..
if the candidate is interviewd after introduce, it will not counted as Introduce
I want the count of Introduce, interviewd, rejected candidates of specofic jobcode
Please help me for this.
You can try
select status, count(*)
from [tablename]
where jobcode = 'AQW-06'
group by status
Edit: You can try use something like this
select count(x.candid) numofcandidates, x.statusnum
from
(select candid, max(case when status = 'Reject' then 3
when status = 'Interview' then 2
when status = 'Introduce' then 1 end) statusnum
from [tablename] t
where jobcode = 'AQW-06'
group by candid) x
group by x.statusnum;
What I actually did is to "translate" the status to a number, so I can use the highest status first. All you need to do then it to "translate" back the statusnum to the values of your table. In my opinion I would use a statusnum in my table directly
Try this:
;with reftable as
(select 1 'key', 'Introduce' 'val'
union
select 2 'key', 'Interview' 'val'
union
select 3 'key', 'Rejected' 'val'
),
cte as
(select e.candid, e.[status], row_number() over (partition by e.candid order by r.[key] desc) rn
from yourtable e
inner join reftable r on e.[status] = r.val
where e.[status] in ('Introduce','Interview','Rejected')
and e,jobcode = 'AQW-06')
select [status], count([status])
from cte
where rn = 1
group by [status]
Basically, we assign a numeric value to your text status to allow sorting. In the over clause, we sort by this numeric value in descending order to get the highest status of a candidate as you describe. Then, we just count the number of occurrences of each status.
Note that you can extend this to include values for status like 'Hire'. To do this, you will need to add it to the list in reftable with appropriate numeric value, and also add it to the filter in cte.
I want the count of Introduce, interviewed, rejected candidates of specific jobcode
The query below will return the results you need:
SELECT SUM(t.IsIntroduction) AS CountOfIntroductions,
SUM(t.IsInterview) AS CountOfInterviews,
SUM(t.IsRejected) AS CountOfRejections
FROM (
SELECT id,
CASE WHEN Status = 'Introduce' THEN 1 ELSE 0 END AS IsIntroduction,
CASE WHEN Status = 'Interview' THEN 1 ELSE 0 END AS IsInterview,
CASE WHEN Status = 'Reject' THEN 1 ELSE 0 END AS IsRejected
FROM [Tablename]
WHERE JobCode = 'AQW-06'
) AS t
Sample at this SQL Fiddle.

Oracle 11G R2 SQL rows to columns

I have a table of bank staff information that looks like this:
branchNumber Position firstName lastName staffNumber
------------ -------- --------- -------- -----------
25 Manager john doe 11111
25 Secretary robert paulson 11112
25 Secretary cindy lu 11113
66 Manager tim timson 22223
66 Manager jacob jacobson 22224
66 Secretary henry henryson 22225
66 Supervisor paul paulerton 22226
I am actually done with this, but I completed the assignment using SQL common table expressions, and I can't use them in this project, I need them in this format.
branchNumber numOfManagers numOfSecretaries numOfSupervisors totalEmployees
------------ ------------- ---------------- ---------------- --------------
25 1 2 0 3
66 2 1 1 4
My issue is getting multiple columns with information from a row, I have this so far,
SELECT branchNumber, COUNT(*) AS numOfManagers
FROM Staff
WHERE position = 'Manager'
GROUP BY branchNumber, Position;
This outputs the correct information for numOfManagers, but making the next three columns eludes me without using CTE's. I tried sub selects too, with no luck. Anybody have any ideas?
You can use something like this:
select branchnumber,
sum(case when Position ='Manager' then 1 else 0 end) numofManagers,
sum(case when Position ='Secretary' then 1 else 0 end) numofSecretaries,
sum(case when Position ='Supervisor' then 1 else 0 end) numofSupervisors,
count(*) totalEmployees
from yourtable
group by branchnumber
See SQL Fiddle with Demo
Or you can use the PIVOT function:
select branchnumber,
'Manager', 'Secretary', 'Supervisor',
TotalEmployees
from
(
select t1.branchnumber,
t1.position,
t2.TotalEmployees
from yourtable t1
inner join
(
select branchnumber, count(*) TotalEmployees
from yourtable
group by branchnumber
) t2
on t1.branchnumber = t2.branchnumber
) x
pivot
(
count(position)
for position in ('Manager', 'Secretary', 'Supervisor')
) p;
See SQL Fiddle with Demo