Grouping and subtotalling - sql

I am currently writing a report which I wish to group by the field apar_id and also have a sub total for each of these.
Given my limited knowledged and being bambozled by many google answer I am asking for your kind input.
My code is as follows:
SELECT d.apar_name,a.*,b.rel_value,c.dim_b
FROM acutrans a
LEFT JOIN aglrelvalue b ON a.apar_id=b.att_value
LEFT JOIN acrtrees c ON b.rel_value=c.cat_1
LEFT JOIN acuheader d ON a.apar_id=d.apar_id
WHERE b.rel_attr_id='212'
AND b.attribute_id='A4'
AND a.client='CL'
AND a.client=b.client
AND a.client=c.client
AND c.att_agrid='60'
AND (b.rel_value='X24' OR c.dim_b='PCT')
ORDER BY a.apar_id
The results are similar to
apar_id | ..... | amount.....
x 100
x 300
x -100
Y 400
Y 100
and would like
apar_id | ..... | amount.....
x 100
x 300
x -100
Total X 300
Y 400
Y 100
Total Y 500
Thanks in advance

Many databases support the with rollup clause for group by. If yours does, you can do what you want by making this a group by statement.
SELECT d.apar_name, sum(amount) as amount
FROM acutrans a
LEFT JOIN aglrelvalue b ON a.apar_id=b.att_value
LEFT JOIN acrtrees c ON b.rel_value=c.cat_1
LEFT JOIN acuheader d ON a.apar_id=d.apar_id
WHERE b.rel_attr_id='212'
AND b.attribute_id='A4'
AND a.client='CL'
AND a.client=b.client
AND a.client=c.client
AND c.att_agrid='60'
AND (b.rel_value='X24' OR c.dim_b='PCT')
GROUP BY d.apar_name WITH ROLLUP;
This will not specifically solve this problem, although you can adapt this solution (if your database supports it).

Related

Combining SQL Tables for one source of information

I'm trying to combine 3 different tables into one single row in a query but having some problems. Currently I have four tables; PaintSched, Painted_Log, Paint_Defect, and Paint_Inspection.
PaintSched - Single entry, when scheduler just schedules some parts to be painted
LOT QTY
1 150
2 100
Painted_Log - The paint department then takes the lot and says how many they were able to paint
LOT(FK) QTYPainted
1 145
2 100
Paint_Defect - Master List of defects for paint inspection after parts have been painted. We hand inspect all of our parts that we paint for quality.
DID Defect
1 Scratch
2 Paint Run
Paint_Inspection - Everytime a defect is found the inspector hits a correlating button and the following gets logged. Lot is FK and DID stands for Defect ID from Paint_Defect. QTY is always 1
Lot(FK) DID(FK) QTY
1 1 1
1 1 1
1 2 1
1 1 1
2 2 1
1 2 1
2 1 1
What I'm trying to get is the following output:
Lot Sched Painted Scratch Paint Run
1 150 145 3 2
2 100 100 1 1
I've tried the following to no avail:
SELECT PaintSched.Scheduled, PaintSched.Lot, PaintSched.qty, PaintSched.Is_Painted, Painted_Log.falloff
FROM PaintSched
INNER JOIN Painted_Log ON PaintSched.Lot = Painted_Log.lot
INNER JOIN MPA_Desc ON MPA_Desc.MPAID = PaintSched.MPAID
inner JOIN (
SELECT lot, sum(Paint_Inspection.qty) as seds
FROM Paint_Inspection
WHERE Paint_Inspection.Status = '1'
) AS seeds ON PaintSched.Lot = Paint_Inspection.Lot
SELECT
PS.Lot,
PS.Qty Sched,
Painted,
Scratch,
PaintRun
FROM PaintSched PS
LEFT JOIN (SELECT
Lot,
SUM(QTYPainted) Painted
FROM Painted_Log GROUP BY Lot) PL
ON PS.Lot = PL.Lot
LEFT JOIN (SELECT
Lot,
SUM(CASE WHEN DID = 1 THEN 1 ELSE 0 END) Scratch,
SUM(CASE WHEN DID = 2 THEN 1 ELSE 0 END) PaintRun
FROM Paint_Inspection GROUP BY Lot) PI
ON PS.Lot = PI.Lot
Try that in SQL Fiddle
The code above uses conditional sum to roll up the defect count by type before joining that to the lot id. If you have more than 2 statuses, you will need to update the above code accordingly.
Two things:
You should have a group by in the subquery
When you alias the subquery, you don't join it properly
See the edits to your query below:
SELECT
PaintSched.Scheduled,
PaintSched.Lot,
PaintSched.qty,
PaintSched.Is_Painted,
Painted_Log.falloff
FROM PaintSched
INNER JOIN Painted_Log ON PaintSched.Lot = Painted_Log.lot
INNER JOIN MPA_Desc ON MPA_Desc.MPAID = PaintSched.MPAID
INNER JOIN (
SELECT lot, sum(Paint_Inspection.qty) as seds
FROM Paint_Inspection
WHERE Paint_Inspection.Status = '1'
GROUP BY Paint_Inspection.lot -- Missing GROUP BY
) AS seeds
ON PaintSched.Lot = seeds.Lot

SQL Query Not Working Properly With Multiple Join Clauses

I have been working on this Query for quite a while. I just got a resolution for part of it and now trying to add that query to my big one, I am having some problems with the output of the query.
SELECT T1.[miles],
T2.[name],
T2.[code],
T2.[routesid],
T2.[id],
T2.[company],
T2.[contract],
T2.[supplier],
T3.[tons],
CASE
WHEN T4.miles IS NULL THEN T5.miles
ELSE T4.miles
END MILES2,
CASE
WHEN T4.miles = T1.miles
AND T4.miles != 9999 THEN T4.flatrate
ELSE T5.rate
END AS RATE,
T3.[change]
FROM ((table1 AS T1
JOIN table2 AS T2
ON T1.[company] = T2.[company]
AND T1.[id] = T2.[routesid])
JOIN table3 AS T3
ON T1.[company] = T3.[code])
LEFT JOIN table4 AS T4
ON T1.[company] = T4.[code]
AND ( T1.[miles] = T4.[miles] )
INNER JOIN (SELECT TOP 1 code,
miles,
rate,
flatrate
FROM table4
WHERE miles = 9999
AND active = 1) AS T5
ON T1.[company] = T5.[code]
WHERE T2.[active] = 1
AND T2.[expiration] < '02/10/2015'
AND T1.[miles] > 0
AND T1.[company] = 'COMPANY'
AND T3.[active] = 1;
I know its a big query. I am trying to figure out why it leaves out the numbers that would pair with the miles on table 4 where it pair with 9999. It has no problem printing out these.
MILES NAME CODE ROUTESID ID COMPANY CONTACT SUPPLIER TONS MILES2 CHANGE
140 N/A N/A 3425 185 ILLINI TARIFF 1 N/A 24 140 Weekly
144 N/A N/A 4532 198 ILLINI TARIFF 3 N/A 24 144 Weekly
9999 N/A N/A 2134 150 ILLINI TARIFF 2 N/A 24 9999 Weekly
Its not printing out right now if it matches this case below. Which I got the SQL statement from my previous stack overflow, I got the SQL statement to print if Miles and Miles2 don't match but since I added the SQLs together it stopped working.
MILES NAME CODE ROUTESID ID COMPANY CONTACT SUPPLIER TONS MILES2 CHANGE
140 N/A N/A 3420 170 ILLINI TARIFF 4 N/A 24 9999 Weekly
Previous Stack Overflow
Here is a demo of the issue
As you can see the 250, 300, 350, 400, 450, and 500 out of TABLE1 isn't displaying.
Here is the resolution
The answer given by Giorgos in your previous Stack Overflow thread worked partially because you only had one company in your example. See this portion of the query?:
INNER JOIN (SELECT TOP 1 code,
miles,
rate,
flatrate
FROM table4
WHERE miles = 9999
AND active = 1) AS T5
ON T1.[company] = T5.[code]
This literally takes only the top row from the table (where miles = 9999 and active = 1) and then tries to join it to the T1 table. Not the top row for each company, just the top row. So whatever company happens to be on the top row is the only one available when you join the T5 table to the T1 table on the company field. You could get around this perhaps by using distinct instead of top 1, if the table doesn't have multiple rows for a single code where miles = 9999 and active = 1 (which I'm guessing you shouldn't, as that would mean there are multiple rates for the same code and miles):
INNER JOIN (SELECT distinct code, miles, rate, flatrate
FROM table4
WHERE miles = 9999 AND active = 1
GROUP BY code) AS T5 ON T1.[company] = T5.[code]
But as others have noted, it is very difficult to understand what you are trying to accomplish, partially because the formatting of your query is odd. And it would help perhaps to re-explain the nature of your tables and the solution you are seeking, as well as defining the problem better.

How to SUM an AS column in SQL

I have the following code...
SELECT WF.Word, WF.Frequency, WW.Weight, (WF.Frequency * WW.Weight) AS Product
FROM WF
INNER JOIN WW ON WW.Word = WF.word
Which outputs the following...
WORD | FREQUENCY | WEIGHT | PRODUCT
Fat 3 2 6
Ugly 2 4 8
Stupid 1 7 7
I also want to sum the product column at the same time. I understand how to sum an existing column but unsure how to sum a column i'm creating.
SELECT SUM(WF.Frequency * WW.Weight) AS Product
FROM WF
INNER JOIN WW ON WW.Word = WF.word
SELECT WF.Word, SUM(WF.Frequency) Frequency, SUM(WW.Weight) Weight, SUM(WF.Frequency * WW.Weight) AS Product
FROM WF
INNER JOIN WW ON WW.Word = WF.word
GROUP BY WF.Word
;
SELECT SUM(WF.Frequency * WW.Weight) Product
FROM WF
INNER JOIN
WW ON WW.Word = WF.word

Sum Values within 3 tables

Table 1
jh."job-hdr"
job-date job-disp job-dept job-route job-id job-no
01/04/2013 6467 abc 123 22 81088
01/04/2013 6468 abc 987 36 82568
Table 2
rh."rec-charge"
charge-type rec-id base-sales-value
XYZ 22 700
Table 3
rc."rec-cost"
charge-type rec-id base-cost-value
XYZ 22 300
I need to be able to get the profit from this jobid of
700 - 300 = 400
This is where I have gotten up to
SELECT jh."job-date", jh."job-disp", jh."job-dept", jh."job-route", rc."charge-type",rh."charge-type",
SUM(rc."base-cost-value") as COSTS,
SUM(rh."base-sales-value") as SALES,
SUM(rh."base-sales-value") - SUM(rc."base-cost-value") as PROFIT
FROM MSN.PUB."rec-chg" rh, PUB."job-hdr" jh, pub."rec-cost" rc
WHERE jh."job-date" between '2013-04-01' and '2013-04-30'
and jh."job-id" = rc."rec-id"
and rc."rec-id" = rh."rec-id"
and jh."grp-id" = '0'
and jh."job-status"<>'D'
and jh."job-no" = '81088'
and rc."charge-type" = rh."charge-type"
Group by jh."job-date", jh."job-disp", jh."job-dept", jh."job-route",rc."charge- type",rh."charge-type"
This is not giving me great results at all and I know I am way off. I just need to be put in the right direction.
Update profit to:
SUM(rh."base-sales-value" - rc."base-cost-value") as PROFIT
And update your group by to:
group by jh."job-id", rc."rec-id", rh."rec-id"
This should give your the desired result (hopefully). Sorry didnt not have time to test it myself. The main focus is on group by, which should be applied on a field that would return multiple results for other fields you want to run the sum on.
Your question appears is a little ambiguous, as to whether you want the results by job or by charge type. In either case, you need to aggregate the results before doing the join. The following query does this at the job level:
SELECT jh."job-date", jh."job-disp", jh."job-dept", jh."job-route",
COSTS, SALES, SALES - COSTS as PROFIT
FROM PUB."job-hdr" jh left outer join
(select rh."rec-id", SUM(rh."base-sales-value") as SALES
from MSN.PUB."rec-chg" rh
group by rh."rec-id"
) rh
on jh."job-id" = rh."rec-id" left outer join
(select rc."rec-id", SUM(rc."base-cost-value") as COSTS
from pub."rec-cost" rc
group by rc."rec-id"
) rc
on jh."job-id" = rc."rec-id"
WHERE jh."grp-id" = '0' and
jh."job-status" <> 'D' and
jh."job-no" = '81088';
Notice that I replaced your implicit join syntax with explicit join syntax. The explicit version is much better, so you should learn to use it.

Crosstab/cross over query

Given data looks like
PLI_ID OWN_ID DCSF_ID SCH_NAME PREMIUM1 PREMIUM2 DESCRIPTION
901 2 1000 Dfe-School 1 86.40 7.20 Heads, Deps
902 2 1000 Dfe-School 2 403.30 8.40 Relief Bursar
903 2 1000 Dfe-School 3 327.00 8.40 £10.00
904 2 1000 Dfe-School 4 381.50 8.40 £11.00
905 2 1000 Dfe-School 5 152.60 8.40 Teaching staff
Expected data to look like
School £10.00 £11.00 Heads, Deps Relief Bursar Teaching staff Total
Dfe-School 1
Dfe-School 2
Dfe-School 3
Dfe-School 4
Total [Pre-Total]
I am not sure whether to write a Cross Tab or Cross Over query, as suggested. Let me know, if need more explanation.
My query uses around 6 tables and it looks like this:
SELECT PolicyLine.PLI_POS_Id, Policy.POL_OWN_Id, Policy.POL_DCSF, School.SCH_Name, PolicyLine.PLI_Premium, CoverPremium.CPR_Premium, StaffCategory.SCA_Description FROM
School
INNER JOIN Policy ON School.SCH_OWN_Id = Policy.POL_OWN_Id AND School.SCH_DCSF = Policy.POL_DCSF
INNER JOIN PolicyLine ON Policy.POL_Id = PolicyLine.PLI_POL_Id
INNER JOIN CoverOption ON PolicyLine.PLI_COP_Id = CoverOption.COP_Id
INNER JOIN CoverPremium ON CoverOption.COP_Id = CoverPremium.CPR_COP_Id AND Policy.POL_OWN_Id = CoverPremium.CPR_OWN_Id
RIGHT OUTER JOIN StaffCategory ON CoverOption.COP_SCA_Id = StaffCategory.SCA_
Based on your existing query you would use something like this:
SELECT School.SCH_Name school,
[£10.00], [£11.00],
[Heads, Deps], [Relief Bursar], [Teaching staff]
FROM
(
SELECT PolicyLine.PLI_POS_Id,
Policy.POL_OWN_Id,
Policy.POL_DCSF,
School.SCH_Name,
PolicyLine.PLI_Premium,
CoverPremium.CPR_Premium,
StaffCategory.SCA_Description
FROM School
INNER JOIN Policy
ON School.SCH_OWN_Id = Policy.POL_OWN_Id
AND School.SCH_DCSF = Policy.POL_DCSF
INNER JOIN PolicyLine
ON Policy.POL_Id = PolicyLine.PLI_POL_Id
INNER JOIN CoverOption
ON PolicyLine.PLI_COP_Id = CoverOption.COP_Id
INNER JOIN CoverPremium
ON CoverOption.COP_Id = CoverPremium.CPR_COP_Id
AND Policy.POL_OWN_Id = CoverPremium.CPR_OWN_Id
RIGHT OUTER JOIN StaffCategory
ON CoverOption.COP_SCA_Id = StaffCategory.SCA_
) x
PIVOT
(
sum(PLI_Premium)
for SCA_Description in([£10.00], [£11.00],
[Heads, Deps], [Relief Bursar], [Teaching staff])
) p
See SQL Fiddle with Demo
You probably want a PIVOT query, but from your example it's hard to tell what that should look like.
SELECT *
FROM yourtable
PIVOT
(SUM(Premium) FOR sch_name in ([£10.00],[£11.00],[Heads, Deps],[Relief Bursar],[Teaching staff]))