How do I do a sum per id? - sql

SELECT distinct
A.PROPOLN, C.LIFCLNTNO, A.PROSASORG, sum (A.PROSASORG) as sum
FROM [FPRODUCTPF] A
join [FNBREQCPF] B on (B.IQCPLN=A.PROPOLN)
join [FLIFERATPF] C on (C.LIFPOLN=A.PROPOLN and C.LIFPRDCNT=A.PROPRDCNT and C.LIFBNFCNT=A.PROBNFCNT)
where C.LIFCLNTNO='2012042830507' and A.PROSASORG>0 and A.PROPRDSTS='10' and
A.PRORECSTS='1' and A.PROBNFLVL='M' and B.IQCODE='B10000' and B.IQAPDAT>20180101
group by C.LIFCLNTNO, A.PROPOLN, A.PROSASORG
This does not sum correctly, it returns two lines instead of one:
PROPOLN LIFCLNTNO PROSASORG sum
1 209814572 2012042830507 3881236 147486968
2 209814572 2012042830507 15461074 463832220

You are seeing two rows because A.PROSASORG has two different values for the "C.LIFCLNTNO, A.PROPOLN" grouping.
i.e.
C.LIFCLNTNO, A.PROPOLN, A.PROSASORG together give you two unique rows.
If you want a single row for C.LIFCLNTNO, A.PROPOLN, then you may want to use an aggregate on A.PROSASORG as well.

Your entire query is being filtered on your "C" table by the one LifClntNo,
so you can leave that out of your group by and just have it as a MAX() value
in your select since it will always be the same value.
As for you summing the PROSASORG column via comment from other answer, just sum it. Hour column names are not evidently clear for purpose, so I dont know if its just a number, a quantity, or whatever. You might want to just pull that column out of your query completely if you want based on a single product id.
For performance, I would suggest the following indexes on
Table Index
FPRODUCTPF ( PROPRDSTS, PRORECSTS, PROBNFLVL, PROPOLN )
FNBREQCPF ( IQCODE, IQCPLN, IQAPDAT )
FLIFERATPF ( LIFPOLN, LIFPRDCNT, LIFBNFCNT, LIFCLNTNO )
I have rewritten your query to put the corresponding JOIN components to the same as the table they are based on vs all in the where clause.
SELECT
P.PROPOLN,
max( L.LIFCLNTNO ) LIFCLNTNO,
sum (P.PROSASORG) as sum
FROM
[FPRODUCTPF] P
join [FNBREQCPF] N
on N.IQCODE = 'B10000'
and P.PROPOLN = N.IQCPLN
and N.IQAPDAT > 20180101
join [FLIFERATPF] L
on L.LIFCLNTNO='2012042830507'
and P.PROPOLN = L.LIFPOLN
and P.PROPRDCNT = L.LIFPRDCNT
and P.PROBNFCNT = L.LIFBNFCNT
where
P.PROPRDSTS = '10'
and P.PRORECSTS = '1'
and P.PROBNFLVL = 'M'
and P.PROSASORG > 0
group by
P.PROPOLN
Now, one additional issue you will PROBABLY be running into. You are doing a query with multiple joins, and it appears that there will be multiple records in EACH of your FNBREQCPF and FLIFERATPF tables for the same FPRODUCTPF entry. If you, you will be getting a Cartesian result as the PROSASORG value will be counted for each instance combination in the two other tables.
Ex: FProductPF has ID = X with a Prosasorg value of 3
FNBreQCPF has matching records of Y1 and Y2
FLIFERATPF has matching records of Z1, Z2 and Z3.
So now your total will be equal to 3 times 6 = 18.
If you look at the combinations, Y1:Z1, Y1:Z2, Y1:Z3 AND Y2:Z1, Y2:Z2, Y2:Z3 giving your 6 entries that qualify, times the original value of 3, thus bloating your numbers -- IF such multiple records may exist in each respective table. Now, imagine if your tables have 30 and 40 matching instances respectively, you have just bloated your totals by 1200 times.

Related

Two Tables/Databases error: Only one expression can be specified in the select list when the subquery is not introduced with EXISTS

Using SQL Server I'm trying to multiply two columns of a distinct part number using 2 tables and 2 databases but it gives this error:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
This SQL joins two tables in different databases and show the Final Part Number (FinalPartNo) for a bumper and the ancillary parts that it needs to put it together (bolts, brackets etc.)
Query:
SELECT
tb_1.FinalPartNo,
tb_1.SubPartType,
tb_1.SubPart,
tb_1.FinalItemSubPartQuantity,
tb_2.PurchasedOrMfg,
tb_2.SalesWeek1,
tb_2.SalesWeek2
FROM [009Reports].[dbo].[ANC Parts] tb_1
JOIN [555].[cache].[PurchasingSupplyChainNeeds] tb_2 ON tb_1.FinalPartNo = tb_2.ItemNo
So it displays this:
If you look at the table and to siplify things, I highlighted 3 part numbers that all use the same SubPart. Two of them use 4 of the FinalSubPartQuantity and one uses 2 in the "install" step. For SalesWeek1 of the highlighted in the image, they sold two of the FinalPartNo which requires 4 FinalSubPartQuantity and had two sales so that totals 8 needed for that week. I don't need the FinalPartNo but added that to show that it's multiple FinalPartNo with the same subpart.
Trying to figure to sum them up with a totals column for each SubPart for that week (for 52 weeks, just showing 2).
In this example, 03CSFY-0500350 for SalesWeek1 could total 150 having it on
multiple FinalPartNo and multiple steps (Fabricate, Assembly, Install).
So, I tried a subquery to make the SubPart distinct and multiply the FinalSubPartQuantity x SalesWeek1 for TotalSalesWeek1 but getting error. Trying to figure out syntax.
SELECT
tb_1.SubPart,
tb_1.FinalItemSubPartQuantity,
TotalSalesWeek1 = (SELECT DISTINCT(tb_1.SubPart),
tb_1.FinalItemSubPartQuantity * tb_2.SalesWeek1),
TotalSalesWeek2 = (SELECT DISTINCT(tb_1.SubPart),
tb_1.FinalItemSubPartQuantity * tb_2.SalesWeek2)
FROM [009Reports].[dbo].[ANC Parts] tb_1
JOIN [555].[cache].[PurchasingSupplyChainNeeds] tb_2 ON tb_1.FinalPartNo = tb_2.ItemNo
I'm just trying to display:
SubPart/FinalSubPartQuantity/TotalSalesWk1/TotalSalesWk2/TotalSalesWk3/ to week 52. So it just shows the sub part, sum of all the FinalSubPartQuantity amounts for that part for all the different FinalPartNo's and the total sales FinalItemPartQuantity * SalesWeek1, 2, 3...
summarize: subpart and how many sold of that part that week.
You can't set the TotalSalesWeek1 to two columns (DISTINCT(tb_1.SubPart) and tb_1.FinalItemSubPartQuantity * tb_2.SalesWeek1).
I would suggest something like the following
SELECT
tb_1.SubPart,
SUM(tb_1.FinalItemSubPartQuantity) FinalItemSubPartQuantity,
SUM(tb_1.FinalItemSubPartQuantity * tb_2.SalesWeek1) TotalSalesWeek1
SUM(tb_1.FinalItemSubPartQuantity * tb_2.SalesWeek2) TotalSalesWeek2
FROM [009Reports].[dbo].[ANC Parts] tb_1
JOIN [555].[cache].[PurchasingSupplyChainNeeds] tb_2 ON tb_1.FinalPartNo = tb_2.ItemNo
GROUP BY tb_1.SubPart
The GROUP BY tb_1.SubPart at the end says you want each unique SubPart on a row, the SUMs in the SELECT explain that you want those values summed for each group.

SQL Calculations over tables

There are 2 tables, there is an expected result, the result is to have the total cost of each engagement calculated, there are multiple tests taken during each engagement, each test ranges in cost (all set values), the expected result must be in terms of EngagementId, EngagementCost
The 2 tables, with there respective fields
- EngagementTest (EngagementId, TestId)
- Test (TestId, TestCost)
How would one go calculating the cost of each engagement.
This is as far as i managed to get
SELECT EngagementId, COUNT(TESTId)
FROM EngagementTest
GROUP BY EngagementId;
Try a SUM of the TestCost column rather than a COUNT. COUNT just tells you the number of rows. SUM adds up the values within the rows and gives you a total. Also your existing query doesn't actually use the table that contains the cost data. You can INNER JOIN the two tables via TestId and then GROUP BY the EngagementId so you get the sum of each engagement.
Something like this:
SELECT
ET.EngagementId,
SUM(T.TestCost)
FROM
EngagementTest ET
INNER JOIN Test T
ON T.TestId = ET.TestId
GROUP BY
ET.EngagementId
It can be achieved using below query.
SELECT i.EngagementId, SUM(TestCost)
FROM EngagementTest i
INNER JOIN Test t
ON e.TestId = t.TestId
GROUP BY i.EngagementId

Count items in SQL Server

This is my database
I want to count Bikes which are currently available in a RouteCode in a SAME EXPIRY WEEK. So if EXPIRY WEEKs are different, the RouteCode can reappear, otherwise the RouteCode has to display with the BikeQuantity it has.
This is my problem. The RouteCode = G shows up 2 times with 1 bikes each even though they are expired in a same week. How can I say it has 2 bikes in BikeQuantity column?
The first problem is that you are GROUPing by 'FoundDate'. You need to group by 'ExpiryWeek' if you want to aggregate (i.e. sum) the number of bikes on a per-ExpiryWeek basis.
The second problem is that you are SELECTing 'FoundDate' and 'ExpiryDate'. You cannot select these columns if you're grouping on 'ExpiryWeek' because there's no way to aggregate the data (dates) in those columns*. It follows that you should not order by 'ExpiryDate' (since this column won't appear in the output table).
( * ...because if you have two entries for a given expiry week but with different a 'FoundDate' for each, what would you expect to see in the result table in the 'FoundDate' column for that row?)
Change your SELECT clause to this:
SELECT li.RouteCode,
DATEPART(WK,DATEADD(WEEK, 4, FoundDate)) as ExpiryWeek,
COUNT(b.BikeId) As BikeQuantity
and change your GROUP BY clause to this:
GROUP BY li.RouteCode, DATEPART(WK,DATEADD(WEEK, 4, FoundDate))
ORDER BY DATEPART(WK,DATEADD(WEEK, 4, FoundDate));
and your query should work.
(Because 'ExpiryWeek' is a calculated column, you have to supply the same calculation in the GROUP BY and ORDER BY clauses - just specifying 'ExpiryWeek' won't work, at least for some variants of SQL. There are ways around this: for example, you could use a 'With' clause. See this answer for examples which avoid duplication: How to group by a Calculated Field)
Based on the latest code you have posted, the correct query should be:
select li.RouteCode,
DATEPART(WK,DATEADD(WEEK, 4, b.FoundDate)) as ExpiryWeek,
COUNT(b.BikeId) as BikeQuantity
FROM dbo.Bike b
LEFT OUTER JOIN dbo.Contact ct ON b.ContactId = ct.ContactId
INNER JOIN dbo.LocationInfo li ON li.PostCode = ct.PostCode
WHERE DATEADD(day, 30, FoundDate) >= GETDATE()
Group by li.RouteCode, DATEPART(WK,DATEADD(WEEK, 4, FoundDate))
ORDER BY DATEPART(WK,DATEADD(WEEK, 4, FoundDate));

Remove duplicate column after SQL query

I have this query but I'm getting two columns of houseid:
How do I only get one?
SELECT vehv2pub.houseid, vehv2pub.vehid, vehv2pub.epatmpg,
dayv2pub.houseid, dayv2pub.trpmiles
FROM vehv2pub, dayv2pub
WHERE vehv2pub.vehid >= 1
AND dayv2pub.trpmiles < 15
AND dayv2pub.houseid = vehv2pub.houseid;
And also, how do I get the average of the epatmpg? So the query would just return the value?
The most elegant way would be to use the USING clause in an explicit join condition:
SELECT houseid, v.vehid, v.epatmpg, d.houseid, d.trpmiles
FROM vehv2pub v
JOIN dayv2pub d USING (houseid)
WHERE v.vehid >= 1
AND d.trpmiles < 15;
This way, the column houseid is in the result only once, even if you use SELECT *.
Per documentation:
USING is a shorthand notation: it takes a comma-separated list of
column names, which the joined tables must have in common, and forms a
join condition specifying equality of each of these pairs of columns.
Furthermore, the output of JOIN USING has one column for each of the
equated pairs of input columns, followed by the remaining columns from each table.
To get the average epatmpg for the selected rows:
SELECT avg(v.epatmpg) AS avg_epatmpg
FROM vehv2pub v
JOIN dayv2pub d USING (houseid)
WHERE v.vehid >= 1
AND d.trpmiles < 15;
If there are multiple matches in dayv2pub, the derived table can hold multiple instances of each row in vehv2pub after the join. avg() is based on the derived table.
not 100% sure this works in postgres sql, but something like this gets the average in SQL server:
SELECT vehv2pub.houseid, avg(vehv2pub.epatmpg)
FROM vehv2pub, dayv2pub
WHERE vehv2pub.vehid >= 1
AND dayv2pub.trpmiles < 15
AND dayv2pub.houseid = vehv2pub.houseid
GROUP BY vehv2pub.houseid

How do I return a value of an entity in a table that is less than but closest to the value in another table for each element in the last table in SQL?

I have two tables in MS Access and I am trying to add a field for one of those tables that tells which record from another table has a value that is less than the first field's value, but comes the closest? I have this query so far (just a select statement to test output and not alter existing tables), but it lists all values that are less than the querying value:
SELECT JavaClassFileList.ClassFile, ModuleList.Module
FROM JavaClassFileList, ModuleList
WHERE ModuleList.Order<JavaClassFileList.Order;`
I tried using things likeSELECT JavaClassFileList.Classfile, MAX(ModuleList.Module), which will only display the maximum module but combined it with the select statement above, but it would say that it would only return one record.
Output desired: I have some records, a, b, and c, I shall call them, each storing various information, while a is storing a value of 732 in a column, and b is storing a value of 731 in the same column. c is storing a value of 720. In another table, d is storing a value of 730 and e is storing a value of 718. I want the output like this (they are ordered largest to smallest):
a 732 d 730
b 731 d 730
c 720 e 718
There can be duplicates on the right, but no duplicates on the left. How can I get this result?
I would approach this type of query using a correlated subquery. I think the following words in Access:
SELECT jc.ClassFile,
(select top 1 ml.Module
from ModuleList as ml
where ml.[Order] < jc.[Order]
)
FROM JavaClassFileList as jc;
I'm assuming Order is unique for Module. If it isn't, JavaClassFileRecords may show up multiple times in the resultset.
If no module can be found for a JavaClassFile then it will not show up in the results. If you do want it to show up in cases like that (with a null module), replace INNER JOIN with LEFT OUTER JOIN.
SELECT j.ClassFile, m.Module
FROM JavaClassFileList j
INNER JOIN ModuleList m
ON m.Order =
(SELECT MAX(Order)
FROM ModuleList
WHERE Order < j.Order)