Postgresql SQL to find revenue from different department on invoice number - sql

I need to find the doctors revenue from various departments like laboratory,radiology,pharmacy and other departments trough patients.
I have only document_number column where the values recorded as 'L1432','R87j7','P652', etc. if doc_no starts with 'L' then it is laboratory, if doc_no starts with 'R' then it is radiology, if doc_no starts with 'P' then it is pharmacy. How can I do this in SQL?
Output should look like this:
doctor_name laboratory radiology pharmacy others
Michel 23098 6763 78732 98838
John 77838 89898 56542 52654
Cranys 98973 78763 5432 65565

This is a conditional aggregation by the first character of the document_number:
select doctor_name,
sum(turnover) filter (where left(document_number,1) = 'L') as laboratory,
sum(turnover) filter (where left(document_number,1) = 'R') as radiology,
sum(turnover) filter (where left(document_number,1) = 'P') as pharmacy,
sum(turnover) filter (where left(document_number,1) not in ('L','R','P')) as others
from the_table
group by doctor_name
order by doctor_name;

Related

I want to count rows of two columns with different values

I have two columns gender(values = 'Male' , 'Female') and grade(values = 'senior officer' , 'Junior Officer') and the table name is employee. I want to count all Males who are senior officers and all Males who are junior officers, vise versa for all females. Below is my code
''' SELECT staff_gender, staff_grade COUNT(*)
FROM permanent_staff
WHERE staff_gender='Female' AND staff_grade='senior officer' '''
Aggregate.
SELECT staff_gender, staff_grade
, COUNT(*) AS total
FROM permanent_staff
GROUP BY staff_gender, staff_grade
ORDER BY staff_gender, staff_grade

Need expert opinion for the scenario defined below in description

SELECT
VP.PERSONNUM,
VP.PAYCODENAME,
VP.PAYCODEID,
VP.TIMEINSECONDS,
TI.ENTEREDONDTM,
VP.APPLYDATE,
VP.LABORLEVELNAME2,
VP.LABORLEVELNAME4,
VP.LABORLEVELNAME5,[enter image description here][1]
CONVERT(VARCHAR(10),VP.ADJUSTEDAPPLYDATE,23) ORIGINALDATE,
CONVERT(VARCHAR(10),VP.PREVPAYPERIODSTART,23)PREVPAYPERIODSTAR,
CONVERT(VARCHAR(10),VP.PREVPAYPERIODEND,112)PREVPAYPERIODEND
FROM VP_TOTALS VP
JOIN TIMESHEETITEM TI
ON TI.EMPLOYEEID = VP.EMPLOYEEID AND TI.TIMESHEETITEMID = VP.TIMESHEETITEMID and TI.DELETEDSW <> '1'
WHERE VP.PAYCODETYPE <> 'G'
and VP.PERSONNUM='100419'
and vp.PAYCODEID in ('145','701')
AND APPLYDATE BETWEEN '2020-06-01' AND '2020-06-30'
Order by VP.PERSONNUM, VP.APPLYDATE
have 2 pay codes Overtime(SWG)Regular(SWG) coming separately in individual rows based on the dates
Example- 1st row personnum =100149 , applydate =6/3/2020, paycode =Overtime(SWG),Timeinseconds =1800
2nd row personnum is 100149 , applydate =6/3/2020, paycode Regular(SWG),Timeinseconds =1500.
2)My main requirement is these two rows should be added together and show only 1 row by adding together.
i.e.personnum =100149 , applydate =6/3/2020, paycode = [Overtime(SWG)+Regular(SWG)] ,Timeinseconds =2300]1
It's hard to tell what all is going on with the WHERE conditions. Based on what's described in the notes I'm thinking something like this.
[Edit] Added PAYCODEID concatenation to the GROUP BY clause
;with
overtime_cte as (select * from VP_TOTALS where PAYCODEID='Overtime(SWG)' and VP.PERSONNUM='100419'),
regular_cte as (select * from VP_TOTALS where PAYCODEID='Regular(SWG)' and VP.PERSONNUM='100419')
select rc.PERSONNUM, rc.APPLYDATE, concat(rc.PAYCODEID, '+', oc.PAYCODEID) PAYCODEID,
sum(rc.TIMEINSECONDS+oc.TIMEINSECONDS)
from regular_cte rc
join
overtime_cte oc on rc.PERSONNUM=oc.PERSONNUM
and rc.APPLYDATE=oc.APPLYDATE
group by rc.PERSONNUM, rc.APPLYDATE, concat(rc.PAYCODEID, '+', oc.PAYCODEID);

Join result of two queries with same column in oracle

I am using Oracle. I am currently working on one table with two different query output. I want to combine two output in single output, I have tried Union all and union but no luck.
with D as
(
Select
VP.HOMELABORLEVELNM4 as DEPT,
SUM(X.DURATIONSECSQTY/3600.0) as ACTL_HR,
SUM(X.WAGEAMT) as ACTL_DLR,
to_char(X.APPLYDTM,'YYYY-MM') AS MONTHLY,
VP.HOMELABORLEVELDSC4 as DESCRIPTION,
NULL as DAILY,
NULL as DEPT1,
NULL as ACTL_HR1,
NULL as ACTL_DLR1
from VP_EMPLOYEEV42 VP,
WFCTOTAL X
where
VP.PERSONID = X.EMPLOYEEID and
X.APPLYDTM between '01-DEC-18' and '31-DEC-18' and
X.EMPLOYEEID in (select personid from PERSONCSTMDATA where CUSTOMDATADEFID ='154' and PERSONCSTMDATATXT = 'USKEANE')
group by VP.HOMELABORLEVELNM4, VP.HOMELABORLEVELDSC4, to_char(X.APPLYDTM,'YYYY-MM')
union all
Select
NULL as DEPT,
NULL as ACTL_HR,
NULL as ACTL_DLR,
NULL as MONTHLY,
VP.HOMELABORLEVELDSC4 as DESCRIPTION,
to_char(X.APPLYDTM) as DAILY,
VP.HOMELABORLEVELNM4 as DEPT1,
SUM(X.DURATIONSECSQTY/3600.0) as ACTL_HR1,
SUM(X.WAGEAMT) as ACTL_DLR1
from VP_EMPLOYEEV42 VP,
WFCTOTAL X
where
VP.PERSONID = X.EMPLOYEEID and
X.APPLYDTM = '31-DEC-18' and
X.EMPLOYEEID in (select personid from PERSONCSTMDATA where CUSTOMDATADEFID ='154' and PERSONCSTMDATATXT = 'USKEANE')
group by VP.HOMELABORLEVELNM4, VP.HOMELABORLEVELDSC4, to_char(X.APPLYDTM)
)
select D.DEPT DEPT,
SUM(D.ACTL_HR) ACTL_HR,
SUM(D.ACTL_DLR) ACTL_DLR,
D.MONTHLY MONTHLY,
D.DESCRIPTION DESCRIPTION,
D.DAILY DAILY,
D.DEPT1 DEPT1,
SUM(D.ACTL_HR1) ACTL_HR1,
SUM(D.ACTL_DLR1) ACTL_DLR1
from D
group by D.DEPT, D.MONTHLY, D.DAILY, D.DESCRIPTION, D.DEPT1
order by DESCRIPTION
it is giving me output like this
-DEPT-HR-DLR-MONTHLY-DESC-DAILY-DEPT-HR-DLR-
-1-12-12-11/1-Manu-NULL-NULL-NULL-NULL-
-NULL-NULL-NULL-NULL-Manu-17-1-12-12-
As long as you have null value in any of the fields you want to group on, you will receive it as a separate row. I think you'd want to review your needed output, then we can try to paraphrase it with code to you.
Hint: you may want to look into JOIN, and group only on D.MONTHLY, D.DAILY, D.DESCRIPTION, D.DEPT1, because your DEPT column is missing in one of the tables.
I think your goal (which is not quite clear to me) might be easier to achieve following this pattern:
with Query1 as (select fields from table where conditions are met),
Query2 as (select fields from table where conditions are met)
select fields
from Query1
outer join Query2
on Query1.identifier_for_match=Query2.identifier_for_match
where optional conditions are true
Note - the 'identifier_for_match' might be employeeid in your case (which would make it a required part of the Query1/Query2 resultset) - you have to look at the model and figure out how the query should combine the rows.
Also - an answer fitting your tables is easier to provide if the DDL for the tables is provided and some data for the same (including the desired output)

Need a count of one column if i am having another column values multiple

I am having this query:
select qos.orgname, qos.org, qos.suborg, qos.Archive, qos.location, count(c.coe) AS DEPT, c.coe AS DEP,
qos.siteid, qos.admin as sitelead,
CASE When qos.Archive = 0 THEN 'Active'
when qos.Archive is null THEN '-'
ELSE 'Archived'
END AS STATUS
from qryOrgsite qos WITH (NOLOCK)
LEFT JOIN ltbcoe c WITH (NOLOCK) on qos.orgname = c.orgname and qos.location= c.location
group by qos.orgname, qos.location, qos.org, qos.suborg, qos.Archive, c.coe,
qos.siteid, qos.ADMIN
This gives me some records as follows:
So i want the count of "Dept" column which are active. I mean it should return only one row with Organization B and Dept as 7....e.g here the Dept column should be 7.
that means I want count of c.coe column.
The problem here is your GROUP BY is too inclusive. What the query is asking for is a count, but the results have to be unique by all of the columns in your GROUP BY. If you only want a count per orgname, you will need to do
SELECT qos.orgname, COUNT(*)
FROM qryOrgsite qos
GROUP BY qos.orgname
This essentially says that you want to count all rows by the orgname. Each column you add to the group by creates unique combinations for your COUNT. For example, if you grouped by orgname and location it would give you a roll up count for each combination of those two columns. Based on the data you show above this would result in
OrganizationB Demo-Fixe 1
OrganizationB GE CapitalP 3
OrganizationB Hadasa Plant 1
OrganizationB Mostoles Plant 1
You can wrap your query in another:
select orgname, count(*)
from (
select qos.orgname, qos.org, qos.suborg, qos.Archive, qos.location, count(c.coe) AS DEPT, c.coe AS DEP,
qos.siteid, qos.admin as sitelead,
CASE When qos.Archive = 0 THEN 'Active'
when qos.Archive is null THEN '-'
ELSE 'Archived'
END AS STATUS
from qryOrgsite qos WITH (NOLOCK)
LEFT JOIN ltbcoe c WITH (NOLOCK) on qos.orgname = c.orgname and qos.location= c.location
group by qos.orgname, qos.location, qos.org, qos.suborg, qos.Archive, c.coe,
qos.siteid, qos.ADMIN) t1
where t1.orgname = 'Organization B' and t1.STATUS = 'Active'
group by t1.orgname
guys i have got the answer.
I had to remove the department name from the group by and the select
because the count(c.coe) didnt had any effect.
Thanks for all you help

how to write SQL query in this situation

I have table named "Attendance" which looks like this:
Sno SecurityGroup SecurityName Designation AttendanceStatus
----------------------------------------------------------------
1 JJ Ram officer present
2 JJ Raja Guards Present
3 JJ Rani LadyGuards Present
4 JJ Ramu officer present
I need the Output as count of number of securities present in each Designation as follows:
SecutityGroup Officer Guards LadyGuards
-----------------------------------------
JJ 2 1 1
Can someone please help me write a query to get this Output?
select SecurityGroup,
sum(case when Designation = 'officer' then 1 end) as Officer,
sum(case when Designation = 'Guards' then 1 end) as Guards,
sum(case when Designation = 'LadyGuards' then 1 end) as LadyGuards
from Attendance
group by SecurityGroup
Alternately, if you are OK with having the information in rows instead, you can do:
select SecurityGroup, Designation, count(*) as Count
from Attendance
group by SecurityGroup, Designation
Obviously the second approach is preferred as it is less brittle, and will function if more Designations get added without any modification.
This can also be done with a PIVOT, depending on your database:
SELECT SecurityGroup, SUM([officer]) AS Officers, SUM([Guards]) AS Guards, SUM([LadyGuards]) AS LadyGuards
FROM Attendance
PIVOT
(
COUNT(Sno)
FOR Designation IN ([officer], [Guards], [LadyGuards])
) as pvt
WHERE AttendanceStatus = 'Present'
GROUP BY SecurityGroup
If you want to have the column list generated dynamically based on whatever is in the table, it gets harder, but this avoids the needs for lots of subqueries.
I Tried out using PIVOT in SQL, But i could not Get count value..
Following is Code i tried:
select SecurityGroup,Officer,Guards,LadyGuards from
(select SecurityGroup,rDesignation from Attendance
where SecurityGroup='jj') up
PIVOT (count(Designation) for Designation IN
(Officer,Guards,LadyGuards)) as pvt
When i Execute this Query, I get
SecurityGroup,Officer,Guards,LadyGuards
JJ,0,0,0
Instead of,
SecurityGroup,Officer,Guards,LadyGuards
JJ,2,1,1
select distinct SecurityGroup,
select sum(*) from Attendance where designation = 'officer') as Officer,
select sum(*) from Attendance where designation = 'Guards') as Guards,
select sum(*) from Attendance where designation = 'LadyGuards') as LadyGuards
from Attendance
You can use sub queries to get this accomplished:
SELECT
SecurityGroup,
(SELECT COUNT(*) FROM `Attendance` WHERE `Designation` = "officer") AS `Officer`,
(SELECT COUNT(*) FROM `Attendance` WHERE `Designation` = "Guards") AS `Guards`,
(SELECT COUNT(*) FROM `Attendance` WHERE `Designation` = "LadyGuards") AS `LadyGuards`
FROM `Attendance`
WHERE `SecurityGroup` = "JJ"
I haven't actually tested this query, as I just wanted to share the concept with you.
Also please do note that is not the fastest way of accomplishing what you need done, but I believe it's the simplest way possible.
I hope this works for you.