Inner join update set postgresql - sql

So I want to make the product between the sum of the number of days that a prisoner has worked and the multiplication coefficient for the specific task.
I tried this code:
UPDATE prisoners
SET nr_days_equaled = (SELECT COALESCE (multiplication_coefficient*SUM(nr_days_worked),0)
FROM prisoners pr
INNER JOIN timesheets_prisoners tp ON pr.idprisoner= tp.idprisoner
INNER JOIN nomenclature_activities_prisoners nap ON pp.idactivity=nap.idactivity)
But I get the following error:
column "nap.multiplication_coefficient" must appear in the GROUP BY clause or be used in an aggregate function
What can I do? Any ideas?

Welcome to StackOverflow.
When using any aggregate function (SUM, COUNT, MIN MAX etc.) together with any other field in your select statement, you must GROUP By the other fields selected. So in your case the compiler wants:
UPDATE prisoners
SET nr_days_equaled =
(SELECT COALESCE (multiplication_coefficient*SUM(nr_days_worked),0)
FROM prisoners pr INNER JOIN timesheets_prisoners tp
ON pr.idprisoner= tp.idprisoner
INNER JOIN nomenclature_activities_prisoners nap
ON pp.idactivity=nap.idactivity GROUP BY multiplication_coefficient)
However, without seeing the inner structure of your tables, I suspect that this is not really what you want. My suspicion is that you really need
SET nr_days_equaled =
(SELECT COALESCE (SUM(multiplication_coefficient*nr_days_worked),0)
FROM prisoners pr INNER JOIN timesheets_prisoners tp
ON pr.idprisoner= tp.idprisoner
INNER JOIN nomenclature_activities_prisoners nap
ON pp.idactivity=nap.idactivity)
The difference is that this version allows for different multiplication_coefficients for different work, but still sums the total. I stress that I am not sure. Please test by converting this to a SELECT statement before issuing the UPDATE.
EDIT
Having seen the structure, what you need is:
UPDATE prisoners
SET nr_days_equaled = SubQ.sumdaysmult
FROM
(SELECT pr.idprisoner, COALESCE (ppnap.sumdaysmult, 0) AS sumdaysmult FROM
FROM prisoners pr LEFT JOIN (SELECT tp.idprisoner, SUM(tp.nr_days_worked
* nap.multiplication_coefficient) as sumdaysmult
FROM timesheets_prisoners tp
INNER JOIN nomenclature_activities_prisoners nap
ON tp.idactivity=nap.idactivity GROUP BY tp.idprisoner) tpnap
ON tpnap.idprisoner = pr.idprisoner) AS SubQ
WHERE SubQ.idprisoner = prisoners.idprisoner

You should use group by using nap.multiplication_coefficient

Related

How to do operations between a column and a subquery

I would like to know how I can do operations between a column and a subquery, what I want to do is add to the field Subtotal what was obtained in the subquery Impuestos, the following is the query that I am using for this case.
Select
RC.PURCHID;
LRC.VALUEMST as 'Subtotal',
isnull((
select sum((CONVERT(float, TD1.taxvalue)/100)*LRC1.VALUEMST ) as a
FROM TAXONITEM TOI1
inner join TAXDATA TD1 ON (TD1.TAXCODE = TOI1.TAXCODE and RC.DATAAREAID = TD1.DATAAREAID)
inner join TRANS LRC1 on (LRC1.VEND = RC.RECID)
WHERE TOI1.TAXITEMGROUP = PL.TAXITEMGROUP and RC.DATAAREAID = TOI1.DATAAREAID
), 0) Impuestos
from VEND RC
inner join VENDTABLE VTB on VTB.ACCOUNTNUM = RC.INVOICEACCOUNT
inner join TRANS LRC on (LRC.VEND = RC.RECID)
inner join PURCHLINE PL on (PL.LINENUMBER =LRC.LINENUM and PL.PURCHID =RC.PURCHID)
where year (RC.DELIVERYDATE) =2021 and RC.PURCHASETYPE =3 order by RC.PURCHID;
Hope someone can give me some guidance when doing operations with subqueries.
A few disjointed facts that may help:
When a SELECT statement returns only one row with one column, you can enclose that statement in parenthesis and use it as a plain value. In your case, let's say that select sum(......= TOI1.DATAAREAID returns 500. Then, your outer select's second column is equivalent to isnull(500,0)
You mention in your question "subquery Impuestos". Keep in mind that, although you indeed used a subquery as we mentioned earlier, by the time it was enclosed in parentheses it is not treated as a subquery (more accurately: derived table), but as a value. Thus, the "Impuestos" is only a column alias at this point
I dislike and avoid subqueries before the from, makes things much harder to read. Here is a solution with apply which will keep your code mostly intact:
Select
RC.PURCHID,
LRC.VALUEMST as 'Subtotal',
isnull(subquery1.a, 0) as Impuestos
from VEND RC
inner join VENDTABLE VTB on VTB.ACCOUNTNUM = RC.INVOICEACCOUNT
inner join TRANS LRC on (LRC.VEND = RC.RECID)
inner join PURCHLINE PL on (PL.LINENUMBER =LRC.LINENUM and PL.PURCHID =RC.PURCHID)
outer apply
(
select sum((CONVERT(float, TD1.taxvalue)/100)*LRC1.VALUEMST ) as a
FROM TAXONITEM TOI1
inner join TAXDATA TD1 ON (TD1.TAXCODE = TOI1.TAXCODE and RC.DATAAREAID = TD1.DATAAREAID)
inner join TRANS LRC1 on (LRC1.VEND = RC.RECID)
WHERE TOI1.TAXITEMGROUP = PL.TAXITEMGROUP and RC.DATAAREAID = TOI1.DATAAREAID
) as subquery1
where year (RC.DELIVERYDATE) =2021 and RC.PURCHASETYPE =3 order by RC.PURCHID;

Using summed field in query twice with IIF statement - have I missed some syntax somewhere?

Having a bit of a problem with my code and can't figure out where I'm going wrong.
Essentially this query will return all employees for a given employer for a given year, along with the amount of their allowances, tax withheld, and gross payments they've received, and their Reportable Employer Superannuation Contributions (RESC).
RESC is any amounts (tblSuperPayments.PaymentAmount) paid over and above the superannuation guarantee, which is gross payments (sum of tblPayment.GrossPayment) * super rate (tblSuperRate.SuperRate). Otherwise, RESC is 0.
The data that I currently have in my tables is as follows
SUM(tblPayment.GrossPayment) = 1730
SUM(tblEmployee.TaxPayable) = 80
SUM(tblSuperPayments.PaymentAmount) = 500
tblSuperRate.SuperRate = 9.5%
Therefore my query should be returning an amount of RESC of 500-(1730*9.5%)= 335.65.
However, my query is currently returning $835.65 - meaning that (1730*9.5%) is returning -335.65.
I can't figure out where my logic is going wrong - it's probably something simple but I can't see it. I suspect that it might be summing tblPayment.GrossPayment twice (edited on request)
SELECT
tblEmployee.EmployeeID AS Id
SUM(tblPayment.Allowances) AS TotAllow,
SUM(tblPayment.TaxPayable) AS TotTax,
SUM(tblPayment.GrossPayment) AS TotGross,
(IIF
((SUM(tblSuperPayments.PaymentAmount)) <= (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate),
0,
(SUM(tblSuperPayments.PaymentAmount) - (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate))
)) As TotRESC
FROM
((tblEmployee
LEFT JOIN tblPayment // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblPayment.fk_EmployeeID)
LEFT JOIN tblSuperPayments // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblSuperPayments.fk_EmployeeID)
LEFT JOIN tblSuperRate // any reason for using left join over inner join
ON (tblPayment.PaymentDate <= tblSuperRate.TaxYearEnd) // these two conditions might be returning
AND (tblPayment.PaymentDate >= tblSuperRate.TaxYearStart) //two SuperRate rows because of using equals in both
WHERE
tblEmployee.fk_EmployerID = 1
GROUP BY
tblEmployee.EmployeeID,
tblSuperRate.SuperRate;
Looking at your query I recommend you to just group by primary key (EmployeeID) of tblEmployee and the use the result as a sub query and do a join later tham using many columns of tblEmployeein group by which might cause duplicate rows. I rewrote the query as I have mentioned above and added comments at places which might cause the error.
SELECT
tblEmployee.TFN,
tblEmployee.FirstName,
tblEmployee.MiddleName,
tblEmployee.LastName,
tblEmployee.DOB,
tblEmployee.MailingAddress,
tblEmployee.AddressLine2,
tblEmployee.City,
tblEmployee.fk_StateProvinceID,
tblEmployee.PostalCode,
temp.TotAllow,
temp.TotTax,
temp.TotGross,
temp.TotRESC
FROM
(SELECT
tblEmployee.EmployeeID AS Id
SUM(tblPayment.Allowances) AS TotAllow,
SUM(tblPayment.TaxPayable) AS TotTax,
SUM(tblPayment.GrossPayment) AS TotGross,
(IIF
((SUM(tblSuperPayments.PaymentAmount)) <= (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate),
0,
(SUM(tblSuperPayments.PaymentAmount) - (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate))
)) As TotRESC
FROM
((tblEmployee
LEFT JOIN tblPayment // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblPayment.fk_EmployeeID)
LEFT JOIN tblSuperPayments // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblSuperPayments.fk_EmployeeID)
LEFT JOIN tblSuperRate // any reason for using left join over inner join
ON (tblPayment.PaymentDate <= tblSuperRate.TaxYearEnd) // these two conditions might be returning
AND (tblPayment.PaymentDate >= tblSuperRate.TaxYearStart) //two SuperRate rows because of using equals in both
WHERE
tblEmployee.fk_EmployerID = 1
GROUP BY
tblEmployee.EmployeeID,
tblSuperRate.SuperRate) temp // Does a single employee have more than one superrate why grouping by it?
JOIN tblEmployee ON tblEmployee.EmployeeID=temp.Id;

Query to return SINGLE DISTINCT row

I have the query below working, the thing is I need to only list each unique "VolumeSerialNumber0" once. There's no shortage of questions and approaches to this problem on SO but they suggest using subqueries and group by clause, but when I try to do that I get an error "columnname is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I feel like it has to be close I'm just not getting the magical syntax perfectly correct.
SELECT
dbo.v_R_System.Netbios_Name0,
dbo.v_GS_LOGICAL_DISK.TimeStamp,
dbo.v_GS_LOGICAL_DISK.Description0,
dbo.v_GS_LOGICAL_DISK.DeviceID0,
dbo.v_GS_LOGICAL_DISK.DriveType0,
dbo.v_GS_LOGICAL_DISK.Name0,
dbo.v_GS_LOGICAL_DISK.SystemName0,
dbo.v_GS_LOGICAL_DISK.VolumeName0,
dbo.v_GS_LOGICAL_DISK.VolumeSerialNumber0,
dbo.v_GS_PARTITION.Size0,
dbo.v_GS_LOGICAL_DISK.FileSystem0
FROM
dbo.v_R_System
INNER JOIN dbo.v_GS_LOGICAL_DISK
ON dbo.v_R_System.ResourceID = dbo.v_GS_LOGICAL_DISK.ResourceID
INNER JOIN dbo.v_GS_PARTITION
ON dbo.v_GS_LOGICAL_DISK.ResourceID = dbo.v_GS_PARTITION.ResourceID
SELECT
MAX(S.Netbios_Name0),
MAX(L.TimeStamp),
MAX(L.Description0),
MAX(L.DeviceID0),
MAX(L.DriveType0),
MAX(L.Name0),
MAX(L.SystemName0),
MAX(L.VolumeName0),
L.VolumeSerialNumber0,
MAX(P.Size0),
MAX(L.FileSystem0)
FROM
dbo.v_R_System S
INNER JOIN dbo.v_GS_LOGICAL_DISK L
ON S.ResourceID = L.ResourceID
INNER JOIN dbo.v_GS_PARTITION P
ON L.ResourceID = P.ResourceID
GROUP BY
L.VolumeSerialNumber0

Add values of one column

I am trying to get a record by adding values of one column based on key value. Here is the query I have:
SELECT
PM_ProductPayment.ProjectId, SalesDetail.SalesPerson,
PM_ProductCost.ProductCost, dbo.PM_ProductPayment.ProductPayment,
dbo.PM_ProductPayment.PaymentDate
FROM
dbo.PM_ProductPayment
INNER JOIN
dbo.PM_Product ON dbo.PM_ProductPayment.ProjectId = dbo.PM_Product.ProductId
INNER JOIN
dbo.PM_ProductCost ON dbo.PM_ProductPayment.ProductId = dbo.PM_ProductCost.ProductId
INNER JOIN
dbo.SalesDetail ON dbo.PM_Product.SalesPersonId = dbo.SalesDetail.ID
The result I am getting is:
Now, here I want to get single row by adding "Payment" for each product and last payment date.
Please optimize my query or suggest any other better way to do that..
Thanks,
SELECT pay.ProjectId,
sum(pay.ProductPayment),
max(pay.PaymentDate)
FROM dbo.PM_ProductPayment pay
INNER JOIN dbo.PM_Product pro ON pay.ProjectId = pro.ProductId
INNER JOIN dbo.PM_ProductCost cos ON pay.ProductId =cos.ProductId
INNER JOIN dbo.SalesDetail sal ON pro.SalesPersonId = sal.ID
GROUP BY pay.ProjectId

MAX not working as expected in Oracle

I have an SQL query
SELECT spt.paymenttype,
MAX(nest.paytypetotal) total
FROM sportpaymenttype spt
INNER JOIN (SELECT spt.paymenttype,
SUM(sod.detailunitprice * sod.detailquantity) paytypetotal
FROM sportorderdetail sod
INNER JOIN sportorder so ON so.orderid = sod.orderid
INNER JOIN sportpaymenttype spt ON spt.paymenttype = so.paymenttype
GROUP BY spt.paymenttype) nest ON nest.paymenttype = spt.paymenttype
GROUP BY spt.paymenttype;
I expect it to return one row (because of the MAX function) however, it returns 4 rows. I came up with a painful way to do it properly but I'm wondering, why the max function is behaving this way?
Also, these are the results, where I only expect the first one
PAYMENTTYPE TOTAL
Loan 8640.95
Check 147.34
Credit Card 479.93
Cash 25.95
What I was wondering is if there was a better way to do this...
SELECT spt.paymenttype,
nest.paytypetotal total
FROM sportpaymenttype spt
INNER JOIN (SELECT spt.paymenttype,
SUM(sod.detailunitprice * sod.detailquantity) paytypetotal
FROM sportorderdetail sod
INNER JOIN sportorder so ON so.orderid = sod.orderid
INNER JOIN sportpaymenttype spt ON spt.paymenttype = so.paymenttype
GROUP BY spt.paymenttype) nest ON nest.paymenttype = spt.paymenttype
WHERE nest.paytypetotal = (SELECT MAX(nest.paytypetotal)
FROM (SELECT spt.paymenttype,
SUM(sod.detailunitprice * sod.detailquantity) paytypetotal
FROM sportorderdetail sod
INNER JOIN sportorder so ON so.orderid = sod.orderid
INNER JOIN sportpaymenttype spt ON spt.paymenttype = so.paymenttype
GROUP BY spt.paymenttype) nest);
Thanks.
It is behaving that way because you're telling Oracle to group by the paymenttype
If you do a MAX(spt.paymenttype) and remove the GROUP BY than it will work as you want it.
The MAX function is an aggregate. When you use a GROUP BY (in your case, the "GROUP BY spt.paymenttype" at the end), the aggregate applies to each group produced by the GROUP BY, not to the result set as a whole. You did get one result row per payment type, as GROUP BY is supposed to do in the absence of filters.
To get one row, pick the single payment type you want, and add a
HAVING spt.paymenttype = 'FOO'
at the very end of the query. If you want the max value across all paytypetotal values, probably easiest (not necessarily best) to make this whole thing into a subquery and then select from it the largest payment value.