How do I find the SUM of the following rows in SQL? - sql

I have the following query in SQL :
SELECT LOCATION_CODE AS "Location",
AUTHORIZATION_STATUS AS "Authorization Status",
COUNT(authorization_status) AS "Requisition Lines Count",
imcb.SEGMENT1 AS "CATEGORY"
FROM apps.po_requisition_headers_all prha
JOIN apps.po_requisition_lines_all prla
ON prla.REQUISITION_HEADER_ID = prha.REQUISITION_HEADER_ID
AND (prha.CANCEL_FLAG = 'N' OR prha.CANCEL_FLAG IS NULL )
JOIN INV.MTL_CATEGORIES_B imcb
ON prla.category_id = imcb.category_id
JOIN HR.PER_ALL_PEOPLE_F P
ON P.person_id = prha.preparer_id
JOIN apps.HR_LOCATIONS ahl
ON prla.deliver_to_location_id = ahl.location_id
JOIN apps.FND_USER afu
ON p.person_id = afu.employee_id
WHERE prla.CREATION_DATE >= '13-JUN-14'
AND P.effective_start_date >=
ALL (SELECT p_temp.EFFECTIVE_START_DATE
FROM HR.PER_ALL_PEOPLE_F p_temp
WHERE P.PERSON_ID = p_temp.PERSON_ID)
AND P.current_employee_flag = 'Y'
/* AND AUTHORIZATION_STATUS = 'APPROVED' */
AND ahl.country IN ( 'US', 'CA', 'MX' ) /* countries in NA */
AND imcb.SEGMENT1 = 'NONBOM'
GROUP BY imcb.SEGMENT1 , authorization_status, LOCATION_CODE
ORDER BY Location_code ASC
And it yields the following output :
However, I would like it to have the total Count for a single location, regardless of Authorization Status. So , it should look like so :
Liberty Lake 826
Rather than
Liberty Lake 767
Liberty Lake 29
Liberty Lake 29
etc
How do I generate this result? I tried adding in a SUM like so:
sum(authorization_status),
but this gives me the following error:
ORA-01722: invalid number

Use a group by rollup instead of just group by
You'll get the current summaaries you have now plus rolled up summaries:
GROUP BY imcb.SEGMENT1, LOCATION_CODE, ROLLUP (authorization_status)
If you don't want any of the more detailed summaries, then remove authorization_status from both your select and group by lists.

You're trying to call the aggregate function SUM on a text field, which is why you are getting that error. SUM is for adding numeric values together. COUNT is used to count the occurrences of rows in that grouping scope. What I think you actually want to do is remove Authorization status from your query, so it would actually be:
SELECT LOCATION_CODE AS "Location",
COUNT(authorization_status) AS "Requisition Lines Count",
imcb.SEGMENT1 AS "CATEGORY"
FROM apps.po_requisition_headers_all prha
JOIN apps.po_requisition_lines_all prla
ON prla.REQUISITION_HEADER_ID = prha.REQUISITION_HEADER_ID
AND (prha.CANCEL_FLAG = 'N' OR prha.CANCEL_FLAG IS NULL )
JOIN INV.MTL_CATEGORIES_B imcb
ON prla.category_id = imcb.category_id
JOIN HR.PER_ALL_PEOPLE_F P
ON P.person_id = prha.preparer_id
JOIN apps.HR_LOCATIONS ahl
ON prla.deliver_to_location_id = ahl.location_id
JOIN apps.FND_USER afu
ON p.person_id = afu.employee_id
WHERE prla.CREATION_DATE >= '13-JUN-14'
AND P.effective_start_date >=
ALL (SELECT p_temp.EFFECTIVE_START_DATE
FROM HR.PER_ALL_PEOPLE_F p_temp
WHERE P.PERSON_ID = p_temp.PERSON_ID)
AND P.current_employee_flag = 'Y'
/* AND AUTHORIZATION_STATUS = 'APPROVED' */
AND ahl.country IN ( 'US', 'CA', 'MX' ) /* countries in NA */
AND imcb.SEGMENT1 = 'NONBOM'
GROUP BY imcb.SEGMENT1 , LOCATION_CODE
ORDER BY Location_code ASC
Note that I removed it from both my SELECT list and my GROUP BY clause.

Related

Combine two queries to get the data in two columns

SELECT
tblEmployeeMaster.TeamName, SUM(tblData.Quantity) AS 'TotalQuantity'
FROM
tblData
INNER JOIN
tblEmployeeMaster ON tblData.EntryByHQCode = tblEmployeeMaster.E_HQCode
INNER JOIN
tblPhotos ON tblEmployeeMaster.TeamNo = tblPhotos.TeamNo
WHERE
IsPSR = 'Y'
GROUP BY
tblPhotos.TeamSort, tblPhotos.TeamNo, tblPhotos.Data,
tblEmployeeMaster.TeamName
ORDER BY
tblPhotos.TeamSort DESC, TotalQuantity DESC
This returns
Using this statement
select TeamName, count(TeamName) AS 'Head Count'
from dbo.tblEmployeeMaster
where IsPSR = 'Y'
group by teamname
Which returns
I would like to combine these 2 queries in 1 to get the below result.
Tried union / union all but no success :(
Any help will be very much helpful.
You can simply use the sub-query as follows:
SELECT tblEmployeeMaster.TeamName, SUM(tblData.Quantity) AS 'TotalQuantity',
MAX(HEAD_COUNT) AS HEAD_COUNT, -- USE THIS VALUE FROM SUB-QUERY
CASE WHEN MAX(HEAD_COUNT) <> 0
THEN SUM(tblData.Quantity)/MAX(HEAD_COUNT)
END AS PER_MAN_CONTRIBUTION -- column asked in comment
FROM tblData INNER JOIN
tblEmployeeMaster ON tblData.EntryByHQCode = tblEmployeeMaster.E_HQCode INNER JOIN
tblPhotos ON tblEmployeeMaster.TeamNo = tblPhotos.TeamNo
-- FOLLOWING SUB-QUERY CAN BE USED
LEFT JOIN (select TeamName, count(TeamName) AS HEAD_COUNT
from dbo.tblEmployeeMaster
where IsPSR = 'Y' group by teamname) AS HC
ON HC.TeamName = tblEmployeeMaster.TeamName
where IsPSR = 'Y'
GROUP BY tblPhotos.TeamSort, tblPhotos.TeamNo, tblPhotos.Data,tblEmployeeMaster.TeamName
order by tblPhotos.TeamSort desc, TotalQuantity desc

Filter between dates grouping 3 tables in SQL Server

I have this SQL in SQL Server:
SELECT
Itens.Mercadoria, Mercadoria.Nome, Cabecalho.Data,
SUM(ValorUnitario) AS Total,
SUM(Quantidade) AS Quantidade
FROM
Itens
INNER JOIN
Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN
Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE
Cabecalho.Data >= '2016-01-01'
AND Cabecalho.Data <= '2018-12-31'
GROUP BY
Itens.Mercadoria, Mercadoria.Nome, Cabecalho.Data
ORDER BY
4 DESC
It is returning the following result.
The highlighted values are repeating, I do not want to be repeated, I want to show only once each item and that the Quantidade and Total fields are SUM.
For example:
`Camisa Polo` -> **Quantidade = 23**
`Calça Jeans` -> **Quantidade = 15**
`Camiseta Estampada` -> **Quantidade = 21**
Assuming thate the relation between Sales and SaleItems is based on SalesId
you can use between assign to your_start_date and your_end_date a proper value
select Products.ProductName
, sum(SaleItems.Price)
, sum(SaleItems.Quantity)
from Products
inner join SaleItems on SaleItems.IdProduct = Products.IdProduct
inner join Sales on Sales.IdSale = SaleItems.IdSale
where SaleDate between your_start_date and your_end_date
group by Products.ProductName
In you case remove or aggregated the Cabecalho.Data column eg:
SELECT Itens.Mercadoria
, Mercadoria.Nome
, SUM(ValorUnitario) AS Total
, SUM(Quantidade) AS Quantidade
FROM Itens INNER JOIN Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE Cabecalho.Data between '2016-01-01' AND '2018-12-31'
GROUP BY Itens.Mercadoria, Mercadoria.Nome
ORDER BY 4 DESC
or
SELECT Itens.Mercadoria
, Mercadoria.Nome
, max(Cabecalho.Data)
, SUM(ValorUnitario) AS Total
, SUM(Quantidade) AS Quantidade
FROM Itens INNER JOIN Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE Cabecalho.Data between '2016-01-01' AND '2018-12-31'
GROUP BY Itens.Mercadoria, Mercadoria.Nome
ORDER BY 4 DESC

SQL Logic for Latest record from results obtained

I have a query that I build that pulls back data from multiple tables for a particular location, particular appointment types in a schedule for a particular date range. In the data that is returned, I am pulling the provider of the service, the member who is getting the service and a number of fields that describe things about the member or service appointment. The information will be grouped by the provider. So you will have multiple members/client records per provider for that period.
What I am now being asked to do is to take those results and pull only the latest appointment for those results.
My code is as follows:
SELECT SCSERVICES.servicecode, SCSERVICES.servicename, SCSESSIONS.scheduleid, SCSERVICES.servicetype, SCSERVICECATEGORIES.servicecategory,
SCSCHEDULES.scheduledatefrom, MEMBERS.lname, MEMBERS.fname, SCSCHEDULES.timestart, SCSCHEDULES.schedulestatus,
CASE WHEN MEMBERS.phone1label = '4' THEN MEMBERS.phone1 WHEN MEMBERS.phone2label = '4' THEN MEMBERS.phone2 WHEN MEMBERS.phone3label = '4'
THEN MEMBERS.phone3 WHEN MEMBERS.phone4label = '4' THEN MEMBERS.phone4 END AS MobilePhone, MEMBERS.scancode,
EMPLOYEES.fname AS trainfname, EMPLOYEES.lname AS trainlname, MEMBERS.lastvisit
FROM SCSESSIONS INNER JOIN
SCSERVICES ON SCSESSIONS.serviceid = SCSERVICES.serviceid INNER JOIN
SCSERVICECATEGORIES ON SCSERVICES.servicecategoryid = SCSERVICECATEGORIES.servicecategoryid INNER JOIN
SCSCHEDULES ON SCSESSIONS.scheduleid = SCSCHEDULES.scheduleid INNER JOIN
MEMBERS ON SCSCHEDULES.memid = MEMBERS.memid INNER JOIN
SCSESSION_PROVIDERS ON SCSESSIONS.sessionid = SCSESSION_PROVIDERS.sessionid INNER JOIN
EMPLOYEES ON SCSESSION_PROVIDERS.employeeid = EMPLOYEES.employeeid
WHERE (SCSERVICECATEGORIES.servicecategory = 'Trainers' OR
SCSERVICECATEGORIES.servicecategory = 'Pilates' OR
SCSERVICECATEGORIES.servicecategory = 'Specialty') AND (SCSERVICES.siteid = #rvSite) AND (CAST(SCSCHEDULES.scheduledatefrom AS DATE) BETWEEN
#rvSessionDate AND #rvSessionDateEnd) AND (SCSCHEDULES.schedulestatus = '1') AND (SCSERVICES.servicecode <> 'BREAK')
Results look something like this:
you can use row_number function for that
( for latest scheduledatefrom for a member)
select * from (
SELECT SCSERVICES.servicecode
, SCSERVICES.servicename
, SCSESSIONS.scheduleid
, SCSERVICES.servicetype
, SCSERVICECATEGORIES.servicecategory
, SCSCHEDULES.scheduledatefrom
, MEMBERS.lname
, MEMBERS.fname
, SCSCHEDULES.timestart
, SCSCHEDULES.schedulestatus
, CASE
WHEN MEMBERS.phone1label = '4'
THEN MEMBERS.phone1
WHEN MEMBERS.phone2label = '4'
THEN MEMBERS.phone2
WHEN MEMBERS.phone3label = '4'
THEN MEMBERS.phone3
WHEN MEMBERS.phone4label = '4'
THEN MEMBERS.phone4
END AS MobilePhone
, MEMBERS.scancode
, EMPLOYEES.fname AS trainfname
, EMPLOYEES.lname AS trainlname
, MEMBERS.lastvisit
, row_number() over ( partition by MEMBERS.memid order by SCSCHEDULES.scheduledatefrom desc) rowid
FROM SCSESSIONS
INNER JOIN SCSERVICES
ON SCSESSIONS.serviceid = SCSERVICES.serviceid
INNER JOIN SCSERVICECATEGORIES
ON SCSERVICES.servicecategoryid = SCSERVICECATEGORIES.servicecategoryid
INNER JOIN SCSCHEDULES
ON SCSESSIONS.scheduleid = SCSCHEDULES.scheduleid
INNER JOIN MEMBERS
ON SCSCHEDULES.memid = MEMBERS.memid
INNER JOIN SCSESSION_PROVIDERS
ON SCSESSIONS.sessionid = SCSESSION_PROVIDERS.sessionid
INNER JOIN EMPLOYEES
ON SCSESSION_PROVIDERS.employeeid = EMPLOYEES.employeeid
WHERE (
SCSERVICECATEGORIES.servicecategory = 'Trainers'
OR SCSERVICECATEGORIES.servicecategory = 'Pilates'
OR SCSERVICECATEGORIES.servicecategory = 'Specialty'
)
AND (SCSERVICES.siteid = #rvSite)
AND (
CAST(SCSCHEDULES.scheduledatefrom AS DATE) BETWEEN #rvSessionDate
AND #rvSessionDateEnd
)
AND (SCSCHEDULES.schedulestatus = '1')
AND (SCSERVICES.servicecode <> 'BREAK')
) x
where rowid = 1

Sum of resulting set of rows in SQL

I've got the following query:
SELECT DISTINCT CU.permit_id, CU.month, /*CU.year,*/ M.material_id, M.material_name, /*MC.chemical_id, C.chemical_name,
C.precursor_organic_compound, C.non_precursor_organic_compound,*/
/*MC.chemical_percentage,*/
POC_emissions =
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END,
NON_POC_emissions =
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
AND M.material_id = 52
--AND CU.permit_id = 2118
--GROUP BY CU.permit_id, M.material_id, M.material_name, CU.month, MC.chemical_id, MC.chemical_id, C.chemical_name, C.precursor_organic_compound, C.non_precursor_organic_compound
--ORDER BY C.chemical_name ASC
Which returns:
But what I need is to return one row per month per material adding up the values of POC per month and NON_POC per month.
So, I should end up with something like:
Month material_id material_name POC NON_POC
1 52 Krylon... 0.107581 0.074108687
2 52 Krylon... 0.143437 0.0988125
I tried using SUM but it sums up the same result multiple times:
SELECT /*DISTINCT*/ CU.permit_id, CU.month, /*CU.year,*/ M.material_id, M.material_name, /*MC.chemical_id, C.chemical_name,
C.precursor_organic_compound, C.non_precursor_organic_compound,*/
--MC.chemical_percentage,
POC_emissions = SUM(
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END),
NON_POC_emissions = SUM(
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END)
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE M.material_id = 52
--AND CU.permit_id = 187
AND (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
GROUP BY CU.permit_id, M.material_id, M.material_name, CU.month/*, CU.year, MC.chemical_id, C.chemical_name, C.precursor_organic_compound, C.non_precursor_organic_compound*/
--ORDER BY C.chemical_name ASC
The first query has a DISTINCT clause. What is the output without the DISTINCT clause. I suspect you have more rows than shows in your screenshot.
Regardless, you could try something like this to get the desired result.
select permit_id, month, material_id, material_name,
sum(poc_emissions), sum(non_poc_emissions)
from (
SELECT DISTINCT CU.permit_id, CU.month, M.material_id, M.material_name,
POC_emissions =
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END,
NON_POC_emissions =
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
AND M.material_id = 52
) main
group by permit_id, month, material_id, material_name
Explanation
Since the results you retrieved by doing a DISTINCT was consider source-of-truth, I created an in-memory table by making it a sub-query. However, this subquery must have a name of some kind...whatever name. I gave it a name main. Subqueries look like this:
select ... from (sub-query) <give-it-a-table-name>
Simple Example:
select * from (select userid, username from user) user_temp
Advanced Example:
select * from (select userid, username from user) user_temp
inner join (select userid, sum(debits) as totaldebits from debittable) debit
on debit.userid = user_temp.userid
Notice how user_temp alias for the subquery can be used as if the sub-query was a real table.
Use above query in subquery and group by (month) and select sum(POC_emissions) and sum(NON_POC_emissions )

In SQL , how do I create a query that will display this type of chart?

I'm looking for general pointers about how to do the following :
I have a chart that looks like this :
The following is my SQL so far , where I am using a WITH clause:
WITH WithSubquery1 AS (
SELECT AUTHORIZATION_STATUS AS "TOTAL AUTHO", COUNT(authorization_status) AS "Requisition Lines Count", LOCATION_CODE AS "Location",
imcb.SEGMENT1 AS "CATEGORY"
FROM
apps.po_requisition_headers_all prha
JOIN apps.po_requisition_lines_all prla ON prla.REQUISITION_HEADER_ID = prha.REQUISITION_HEADER_ID
AND (prha.CANCEL_FLAG = 'N' OR prha.CANCEL_FLAG IS NULL )
JOIN INV.MTL_CATEGORIES_B imcb ON prla.category_id = imcb.category_id
JOIN HR.PER_ALL_PEOPLE_F P ON P.person_id = prha.preparer_id
JOIN apps.HR_LOCATIONS ahl ON prla.deliver_to_location_id = ahl.location_id
JOIN apps.FND_USER afu ON p.person_id = afu.employee_id
WHERE prla.CREATION_DATE >= '13-JUN-14'
AND P.effective_start_date >=
ALL (SELECT p_temp.EFFECTIVE_START_DATE
FROM HR.PER_ALL_PEOPLE_F p_temp
WHERE P.PERSON_ID = p_temp.PERSON_ID)
AND P.current_employee_flag = 'Y'
AND ahl.country IN ( 'US', 'CA', 'MX' ) /* countries in NA */
AND imcb.SEGMENT1 = 'NONBOM'
GROUP BY
imcb.SEGMENT1 , authorization_status, LOCATION_CODE
ORDER BY Location_code Asc
) ,
WithSubquery2 AS
(
SELECT AUTHORIZATION_STATUS AS "APPROVED AUTHO", COUNT(authorization_status) AS "Requisition Lines Apprvd Count", LOCATION_CODE AS "Location",
imcb.SEGMENT1 AS "CATEGORY"
FROM
apps.po_requisition_headers_all prha
JOIN apps.po_requisition_lines_all prla ON prla.REQUISITION_HEADER_ID = prha.REQUISITION_HEADER_ID
AND (prha.CANCEL_FLAG = 'N' OR prha.CANCEL_FLAG IS NULL )
JOIN INV.MTL_CATEGORIES_B imcb ON prla.category_id = imcb.category_id
JOIN HR.PER_ALL_PEOPLE_F P ON P.person_id = prha.preparer_id
JOIN apps.HR_LOCATIONS ahl ON prla.deliver_to_location_id = ahl.location_id
JOIN apps.FND_USER afu ON p.person_id = afu.employee_id
WHERE prla.CREATION_DATE >= '13-JUN-14'
AND P.effective_start_date >=
ALL (SELECT p_temp.EFFECTIVE_START_DATE
FROM HR.PER_ALL_PEOPLE_F p_temp
WHERE P.PERSON_ID = p_temp.PERSON_ID)
AND P.current_employee_flag = 'Y'
and AUTHORIZATION_STATUS = 'APPROVED'
AND ahl.country IN ( 'US', 'CA', 'MX' ) /* countries in NA */
AND imcb.SEGMENT1 = 'NONBOM'
GROUP BY
imcb.SEGMENT1 , authorization_status, LOCATION_CODE
ORDER BY Location_code Asc
)
SELECT WithSubquery1."TOTAL AUTHO", WithSubquery1."Requisition Lines Count", WithSubquery2."APPROVED AUTHO", WithSubquery2."Requisition Lines Apprvd Count"
FROM
WithSubquery1 JOIN WithSubquery2
ON
WithSubquery1."Location" = WithSubquery2."Location"
The problem I'm having is that I'm not sure how to generate SQL so that it has the indentation shown, with the "Ship to" location having spaces underneath it for each of the 5 subcategories ("#Requisition Lines", "#Requisition Lines Approved" etc) . The results I get so far look like this :
This is confusing to read , and doesn't have the hanging -indent.
any tips appreciated, thanks !
Usually, I'd say you should worry about display issues in your front end and not in your SQL. However, you can employ this technique if you want to:
WITH d AS (
SELECT 'Canada' loc, 'APPROVED' status, 5 this_week FROM DUAL UNION ALL
SELECT 'Canada' loc, 'NOT APPROVED' status, 6 this_week FROM DUAL UNION ALL
SELECT 'New York' loc, 'APPROVED' status, 15 this_week FROM DUAL UNION ALL
SELECT 'Philadelphia' loc, 'APPROVED' status, 8 this_week FROM DUAL UNION ALL
SELECT 'Philadelphia' loc, 'NOT APPROVED' status, 2 this_week FROM DUAL )
SELECT case when row_number() over ( partition by loc order by status ) = 1 THEN loc else null end loc_display, status, this_week From d
-- make sure your order by matches your partition and order by
order by loc, status;