Not a GROUP BY Expression & aggregate functions - sql

I was wondering why, for this query that I have right here, why I have to use the MAX() aggregate function for the case statements, and not just jump directly into the case statement:
select
bank_id,
tran_branch_code,
acct_sol_id,
acct_sol_name,
transaction_date,
gl_date,
transaction_id,
account_number,
max(case
when cast(substr(GLSH_Code,0,1) as int) >= 1
and cast(substr(GLSH_Code,0,1) as int) <= 5
and trans_type = 'D'
then (trans_amount)
--else 0
end ) Ind_Part_Tran_Dr_RBU,
max(case
when cast(substr(GLSH_Code,0,1) as int) >= 1
and cast(substr(GLSH_Code,0,1) as int) <= 5
and trans_type = 'C'
then (trans_amount)
--else 0
end) Ind_Part_Tran_Cr_RBU,
max(case
when cast(substr(GLSH_Code,0,1) as int) = 0
or (cast(substr(GLSH_Code,0,1) as int) >= 6
and cast(substr(GLSH_Code,0,1) as int) <= 9)
and trans_type = 'D'
then (trans_amount)
--else 0
end)Ind_Part_Tran_Dr_FCDU,
max(case
when cast(substr(GLSH_Code,0,1) as int) = 0
or (cast(substr(GLSH_Code,0,1) as int) >= 6
and cast(substr(GLSH_Code,0,1) as int) <= 9)
and trans_type = 'C'
then (trans_amount)
--else 0
end) Ind_Part_Tran_Cr_FCDU,
ccy_alias,
ccy_name,
acct_currency,
tran_currency
from
(
SELECT
DTD.BANK_ID,
DTD.SOL_ID Acct_Sol_ID, --Account Sol ID
dtd.br_code Tran_branch_code, -- branch code of the transacting branch
sol.sol_desc Acct_sol_name, -- name/description of SOL
DTD.TRAN_DATE Transaction_Date, --TransactionDate
DTD.GL_DATE GL_Date, --GL Date
TRIM(DTD.TRAN_ID) Transaction_ID, --Transaction ID
DTD.GL_SUB_HEAD_CODE GLSH_Code, --GLSH Code
dtd.tran_amt trans_amount,
GAM.ACCT_CRNCY_CODE Acct_Currency, --Account Currency
DTD.TRAN_CRNCY_CODE Tran_Currency, --Transaction Currency
cnc.crncy_alias_num ccy_alias,
cnc.crncy_name ccy_name,
GAM.FORACID Account_Number, --Account Number
DTD.TRAN_PARTICULAR Transaction_Particulars, --Transaction Particulars
DTD.CRNCY_CODE DTD_CCY,
--GSH.CRNCY_CODE GSH_CCY,
DTD.PART_TRAN_TYPE Transaction_Code,
--'Closing_Balance',
DTD.PSTD_USER_ID PostedBy,
CASE WHEN DTD.REVERSAL_DATE IS NOT NULL
THEN 'Y' ELSE 'N' END Reversal,
TRIM(DTD.TRAN_ID) REV_ORIG_TRAN_ID,
--OTT.REF_NUM OAP_REF_NUM,
'OAP_SETTLEMENT',
'RATE_CODE',
EAB.EOD_DATE
FROM TBAADM.DTD
LEFT OUTER JOIN TBAADM.GAM ON DTD.ACID = GAM.ACID AND DTD.BANK_ID = GAM.BANK_ID
LEFT OUTER JOIN TBAADM.EAB ON DTD.ACID = EAB.ACID AND DTD.BANK_ID = EAB.BANK_ID AND EAB.EOD_DATE = '24-MAR-2014'
left outer join tbaadm.sol on dtd.sol_id = sol.sol_id and dtd.bank_id = sol.bank_id
left outer join tbaadm.cnc on dtd.tran_crncy_code = cnc.crncy_code
WHERE DTD.BANK_ID = 'CBC01'
AND GAM.ACCT_OWNERSHIP = 'O'
AND GAM.DEL_FLG != 'Y'
--AND DTD.TRAN_DATE = '14-APR-2014'
AND DTD.TRAN_DATE between '01-APR-2014' and '21-APR-2014'
--and foracid in ('50010112441109','50010161635051')
--and DTD.SOL_ID = '5001'
and GAM.ACCT_CRNCY_CODE = 'USD'
)
group by
bank_id,
tran_branch_code,
acct_sol_id,
acct_sol_name,
transaction_date,
gl_date,
transaction_id,
account_number,
ccy_alias,
ccy_name,
Acct_Currency,
Tran_Currency
Because If I would remove the MAX(), I'd get the "Not a GROUP BY Expression", and Toad points me to the first occurrence of the GLSH_Code. Based from other websites, the cure for this is really adding the MAX() function. I would just like to understand why should I use that particular function, what it exactly does in the query, stuff like that.
EDIT: inserted the rest of the code.
I know for sure what MAX() does, it returns the largest value in an expression. But in this case, I can't seem to figure out exactly what that largest value is that the function is attempting to return.

The GROUP BY statement declares that all columns returned in the SELECT should be aggregated, but that you want to separate the results by those listed in the GROUP BY.
This means we have to use aggregate functions like MIN, MAX, AVG, SUM, etc. on any column that is NOT listed in the GROUP BY.
It's about telling the SQL engine what the expected results should be when there is more than one option.
In a simple example, we have a table with three columns:
PrimaryId SubId RowValue
1 1 1
2 1 2
3 2 4
4 2 8
And an SQL like the following (which is invalid):
SELECT SubId, RowValue
FROM SampleTable
GROUP BY SubId
We know we want the distinct SubId's (because of the GROUP BY), but we don't know what RowValue should be when we aggregate the results.
SubId RowValue
1 ?
2 ?
We have to be explicit in our query, and indicate what RowValue should be as the results can vary.
If we choose MIN(RowValue) we see:
SubId RowValue
1 1
2 4
If we choose MAX(RowValue) we see:
SubId RowValue
1 2
2 8
If we choose SUM(RowValue) we see:
SubId RowValue
1 3
2 12
Without being explicit there's a high likelihood that the results will be wrong, so our SQL engine of choice protects us from ourselves by enforcing the need for aggregate functions.

You have group by clause at the end on all the columns except for Ind_Part_Tran_Dr_RBU, Ind_Part_Tran_Cr_RBU, Ind_Part_Tran_Dr_FCDU, Ind_Part_Tran_Cr_FCDU. In this case oracle wants you to tell what to do with these columns, i.e. based on which function it has to aggregate them for every group it finds.

Related

How to Count Distinct on Case When?

I have been building up a query today and I have got stuck. I have two unique Ids that identify if and order is Internal or Web. I have been able to split this out so it does the count of how many times they appear but unfortunately it is not providing me with the intended result. From research I have tried creating a Count Distinct Case When statement to provide me with the results.
Please see below where I have broken down what it is doing and how I expect it to be.
Original data looks like:
Company Name Order Date Order Items Orders Value REF
-------------------------------------------------------------------------------
CompanyA 03/01/2019 Item1 Order1 170 INT1
CompanyA 03/01/2019 Item2 Order1 0 INT1
CompanyA 03/01/2019 Item3 Order2 160 WEB2
CompanyA 03/01/2019 Item4 Order2 0 WEB2
How I expect it to be:
Company Name Order Date Order Items Orders Value WEB INT
-----------------------------------------------------------------------------------------
CompanyA 03/01/2019 4 2 330 1 1
What currently comes out
Company Name Order Date Order Items Orders Value WEB INT
-----------------------------------------------------------------------------------------
CompanyA 03/01/2019 4 2 330 2 2
As you can see from my current result it is counting every line even though it is the same reference. Now it is not a hard and fast rule that it is always doubled up. This is why I think I need a Count Distinct Case When. Below is my query I am currently using. This pull from a Progress V10 ODBC that I connect through Excel. Unfortunately I do not have SSMS and Microsoft Query is just useless.
My Current SQL:
SELECT
Company_0.CoaCompanyName
, SopOrder_0.SooOrderDate
, Count(DISTINCT SopOrder_0.SooOrderNumber) AS 'Orders'
, SUM(CASE WHEN SopOrder_0.SooOrderNumber IS NOT NULL THEN 1 ELSE 0 END) AS 'Order Items'
, SUM(SopOrderItem_0.SoiValue) AS 'Order Value'
, SUM(CASE WHEN SopOrder_0.SooParentOrderReference LIKE 'INT%' THEN 1 ELSE 0 END) AS 'INT'
, SUM(CASE WHEN SopOrder_0.SooParentOrderReference LIKE 'WEB%' THEN 1 ELSE 0 END) AS 'WEB'
FROM
SBS.PUB.Company Company_0
, SBS.PUB.SopOrder SopOrder_0
, SBS.PUB.SopOrderItem SopOrderItem_0
WHERE
SopOrder_0.SopOrderID = SopOrderItem_0.SopOrderID
AND Company_0.CompanyID = SopOrder_0.CompanyID
AND SopOrder_0.SooOrderDate > '2019-01-01'
GROUP BY
Company_0.CoaCompanyName
, SopOrder_0.SooOrderDate
I have tried using the following line but it errors on me when importing:
, Count(DISTINCT CASE WHEN SopOrder_0.SooParentOrderReference LIKE 'INT%' THEN SopOrder_0.SooParentOrderReference ELSE 0 END) AS 'INT'
Just so know the error I get when importing at the moment is syntax error at or about "CASE WHEN sopOrder_0.SooParentOrderRefer" (10713)
Try removing the ELSE:
COUNT(DISTINCT CASE WHEN SopOrder_0.SooParentOrderReference LIKE 'INT%' THEN SopOrder_0.SooParentOrderReference END) AS num_int
You don't specify the error, but the problem is probably that the THEN is returning a string and the ELSE a number -- so there is an attempt to convert the string values to a number.
Also, learn to use proper, explicit, standard JOIN syntax. Simple rule: Never use commas in the FROM clause.
count distinct on the SooOrderNumber or the SooParentOrderReference, whichever makes more sense for you.
If you are COUNTing, you need to make NULL the thing that your are not counting. I prefer to include an else in the case because it is more consistent and complete.
, Count(DISTINCT CASE WHEN SopOrder_0.SooParentOrderReference LIKE 'INT%' THEN SopOrder_0.SooParentOrderReference ELSE null END) AS 'INT'
Gordon Linoff is correct regarding the source of your error, i.e. datatype mismatch between the case then value else value end. null removes (should remove) this ambiguity - I'd need to double check.
Editing my earlier answer...
Even though it looks, as you say, like count distinct is not supported in Pervasive PSQL, CTEs are supported. So you can do something like...
This is what you are trying to do but it is not supported...
with
dups as
(
select 1 as id, 'A' as col1 union all select 1, 'A' union all select 1, 'B' union all select 2, 'B'
)
select id
,count(distinct col1) as col_count
from dups
group by id;
Stick another CTE in the query to de-duplicate the data first. Then count as normal. That should work...
with
dups as
(
select 1 as id, 'A' as col1 union all select 1, 'A' union all select 1, 'B' union all select 2, 'B'
)
,de_dup as
(
select id
,col1
from dups
group by id
,col1
)
select id
,count(col1) as col_count
from de_dup
group by id;
These 2 versions should give the same result set.
There is always a way!!
I cannot explain the error you are getting. You are mistakenly using single quotes for alias names, but I don't actually think this is causing the error.
Anyway, I suggest you aggregate your order items per order first and only join then:
SELECT
c.coacompanyname
, so.sooorderdate
, COUNT(*) AS orders
, SUM(soi.itemcount) AS order_items
, SUM(soi.ordervalue) AS order_value
, COUNT(CASE WHEN so.sooparentorderreference LIKE 'INT%' THEN 1 END) AS int
, COUNT(CASE WHEN so.sooparentorderreference LIKE 'WEB%' THEN 1 END) AS web
FROM sbs.pub.company c
JOIN sbs.pub.soporder so ON so.companyid = c.companyid
JOIN
(
SELECT soporderid, COUNT(*) AS itemcount, SUM(soivalue) AS ordervalue
FROM sbs.pub.soporderitem
GROUP BY soporderid
) soi ON soi.soporderid = so.soporderid
GROUP BY c.coacompanyname, so.sooorderdate
ORDER BY c.coacompanyname, so.sooorderdate;

Check whether an employee is present on three consecutive days

I have a table called tbl_A with the following schema:
After insert, I have the following data in tbl_A:
Now the question is how to write a query for the following scenario:
Put (1) in front of any employee who was present three days consecutively
Put (0) in front of employee who was not present three days consecutively
The output screen shoot:
I think we should use case statement, but I am not able to check three consecutive days from date. I hope I am helped in this
Thank you
select name, case when max(cons_days) >= 3 then 1 else 0 end as presence
from (
select name, count(*) as cons_days
from tbl_A, (values (0),(1),(2)) as a(dd)
group by name, adate + dd
)x
group by name
With a self-join on name and available = 'Y', we create an inner table with different combinations of dates for a given name and take a count of those entries in which the dates of the two instances of the table are less than 2 units apart i.e. for each value of a date adate, it will check for entries with its own value adate as well as adate + 1 and adate + 2. If all 3 entries are present, the count will be 3 and you will have a flag with value 1 for such names(this is done in the outer query). Try the below query:
SELECT Z.NAME,
CASE WHEN Z.CONSEQ_AVAIL >= 3 THEN 1 ELSE 0 END AS YOUR_FLAG
FROM
(
SELECT A.NAME,
SUM(CASE WHEN B.ADATE >= A.ADATE AND B.ADATE <= A.ADATE + 2 THEN 1 ELSE 0 END) AS CONSEQ_AVAIL
FROM
TABL_A A INNER JOIN TABL_A B
ON A.NAME = B.NAME AND A.AVAILABLE = 'Y' AND B.AVAILABLE = 'Y'
GROUP BY A.NAME
) Z;
Due to the complexity of the problem, I have not been able to test it out. If something is really wrong, please let me know and I will be happy to take down my answer.
--Below is My Approch
select Name,
Case WHen Max_Count>=3 Then 1 else 0 end as Presence
from
(
Select Name,MAx(Coun) as Max_Count
from
(
select Name, (count(*) over (partition by Name,Ref_Date)) as Coun from
(
select Name,adate + row_number() over (partition by Name order by Adate desc) as Ref_Date
from temp
where available='Y'
)
) group by Name
);
select name as employee , case when sum(diff) > =3 then 1 else 0 end as presence
from
(select id, name, Available,Adate, lead(Adate,1) over(order by name) as lead,
case when datediff(day, Adate,lead(Adate,1) over(order by name)) = 1 then 1 else 0 end as diff
from table_A
where Available = 'Y') A
group by name;

How to take the total sum of all objects within an object?

I am trying to get the total sum of all parts in a container. The way I am doing now, sum(weight), will only grab the first weight of the first part in the container. I want to grab all part weights where the container number is the same. There are many different container numbers in the table. I want the statement to work with different container numbers, and only insert the value in the row of the first occurrence of the container number.
http://s33.postimg.org/3t63t83hr/sumweight.png
Each part has a weight in the above. I want to tally those weights for each container number and sum it up on the first row like shown.
,(case when mu.master_unit_no is null
then c.Gross_weight
when mu.master_unit_no is not null
then sum(c.Gross_weight)+mut.tare_weight
end)
as 'Weight in LBS'
Right now I have this query but it returns just the first part weight + the tare weight. I want to grab the sum of all the parts for the container.
/* I-Dashboards Shipping Report */
/* ROTW 11-21-2015 */
select
p.part_no AS 'Part_Number'
,p.name AS 'Description'
,c.serial_no as 'S#'
,c.quantity AS 'Qty'
,cp.customer_part_No as 'F_NUMBER'
--,cast(mut.length AS varchar) + 'X' + Cast(mut.width as varchar) + 'X' + Cast(mut.Height as varchar) as 'dim MU'
,(CASE when mut.length is null
then 0
else cast(mut.length as int) end) as 'M_LEN'
,(CASE when mut.width is null
then 0
else cast(mut.width as int) end) As 'M_WD'
,(CASE when mut.height is null
then 0
else cast(mut.Height as int) end) AS 'M_HT'
,cast(pct.cube_length AS INT) as 'S_LEN'
,cast(pct.cube_width AS INT) AS 'S_WD'
,cast(pct.cube_height AS INT) AS 'S_HT'
,mut.tare_Weight as 'M_Tare_lbs'
,c.Gross_weight as 'Net_Wt_lbs'
,mu.master_unit_no as 'M Number'
,g.Booking_No as 'Booking_HAWB_Num'
,concat(g.cargo_container_no, '-', g.dock_code) as 'Container_ID'
,g.outbound_scac_code AS 'Carrier'
,concat(cast(pct.cube_length as int), 'x', cast(pct.cube_width as int), 'x', cast(pct.cube_height as int)) as 'BOX_DIMS_INCHES'
,(case when row_number() over (partition by mu.master_unit_no order by mu.master_unit_no) = 1
then concat(cast(mut.length as int), 'x', cast(mut.width as int), 'x', cast(mut.Height as int))
when mu.master_unit_no is null
then ''
end)
as 'PALLET_DIMS_INCHES'
,(case when g.booking_container_type_key = 6 THEN
'DIRECT'
when g.booking_container_type_key = 5 THEN
'AIR'
else 'CEVA-Ocean'
end) as 'Shipment Type'
,CASE
--WHEN(ROW_NUMBER() OVER (PARTITION BY mu.master_unit_no ORDER BY mu.master_unit_no)) = 1
--then (select sum((pct.cube_length*0.0254)*(pct.cube_width*0.0254)* (pct.cube_height*0.0254))
--from part_v_container c where c.master_unit_key = mu.master_unit_key)
when mu.master_unit_no is null
then (pct.cube_length*0.0254)*(pct.cube_width*0.0254)* (pct.cube_height*0.0254)
end as 'CBM'
,select c.*, CASE
WHEN(ROW_NUMBER() OVER (PARTITION BY mu.master_unit_no ORDER BY mu.master_unit_no)) = 1
THEN **(**select SUM(c.Gross_weight)+mut.tare_weight
from part_v_container c where c.master_unit_no = mu.master_unit_no**)** END AS 'Total Weight'
from part_v_container c
I'm trying to take the total sum of all the parts gross weight in a m number + the tare weight for that m number and store is as total weight.
Like Siyual said, add tables to help better our understanding. Until then I believe I have most of what you want.
Your table probably looks something like...
part_id container_ id Weight
------- ------------- ------
1 a 5
2 a 5
3 b 99
4 a 3
5 c 99
And you probably want a result like (example using container_id = a)...
Weight
------
13
Try this...
SELECT SUM(Weight) FROM someTable WHERE container_id = someContainer
In the case of the result example I gave I would do...
SELECT SUM(Weight) FROM someTable WHERE container_id = 'a'
I am not fully sure on what you mean by your last part "only insert the value in the row of the first occurrence of the container number". Why would you want this specifically?
EDIT 1
The final result should not have multiple container_id though. I did the following...
My table...
SELECT t1.container_id, SUM(t1.weight) FROM table_1 t1 JOIN table_1 t2 ON t1.part_id = t2.part_id GROUP BY t1.container_id
Result was...
EDIT 2
It took me a while but I think I got it :)
Table:
Query:
SELECT t.*, CASE
WHEN(ROW_NUMBER() OVER (PARTITION BY t.Container ORDER BY t.Container)) = 1
THEN (SELECT SUM(t2.Weight) FROM table1 t2 WHERE t2.Container = t.Container)
ELSE 0 END AS 'Total Weight'
FROM table1 t GROUP BY t.Container, t.Part, t.Weight
Results:
EDIT 3
This was your original...
select c.*, CASE
WHEN(ROW_NUMBER() OVER (PARTITION BY mu.master_unit_no ORDER BY mu.master_unit_no)) = 1
THEN select SUM(c.Gross_weight)+mut.tare_weight
from part_v_container c where c.master_unit_no = mu.master_unit_no END AS 'Total Weight'
This is what I would change (surrounded by two asterix on both sides EX: ** A **)...
select c.*, CASE
WHEN(ROW_NUMBER() OVER (PARTITION BY mu.master_unit_no ORDER BY mu.master_unit_no)) = 1
THEN **(**select SUM(c.Gross_weight)+mut.tare_weight
from part_v_container c where c.master_unit_no = mu.master_unit_no**)** END AS 'Total Weight'
You need the parenthesis because the code doesn't know where the end belongs to otherwise. The parenthesis allows SQL to know that the end belongs to the case statement. I also am not sure where the mu. and mut. come from. It seems like they belong to a different table that you never reference here?
I am not sure if you added it but after 'Total Weight' you are missing
from someTable group by (all things that are in your select aka things that will be output need to be here...see my previous example for a better understanding)
If you want, on your original question you can post screen shots of exactly what your tables look like (or manually create it) so I can use the names you use accurately and make it more easily understandable by you :)
EDIT 4
/* I-Dashboards Shipping Report */
/* ROTW 11-21-2015 */
select
p.part_no AS 'Part_Number'
,p.name AS 'Description'
,c.serial_no as 'S#'
,c.quantity AS 'Qty'
,cp.customer_part_No as 'F_NUMBER'
--,cast(mut.length AS varchar) + 'X' + Cast(mut.width as varchar) + 'X' + Cast(mut.Height as varchar) as 'dim MU'
,(CASE when mut.length is null
then 0
else cast(mut.length as int) end) as 'M_LEN'
,(CASE when mut.width is null
then 0
else cast(mut.width as int) end) As 'M_WD'
,(CASE when mut.height is null
then 0
else cast(mut.Height as int) end) AS 'M_HT'
,cast(pct.cube_length AS INT) as 'S_LEN'
,cast(pct.cube_width AS INT) AS 'S_WD'
,cast(pct.cube_height AS INT) AS 'S_HT'
,mut.tare_Weight as 'M_Tare_lbs'
,c.Gross_weight as 'Net_Wt_lbs'
,mu.master_unit_no as 'M Number'
,g.Booking_No as 'Booking_HAWB_Num'
,concat(g.cargo_container_no, '-', g.dock_code) as 'Container_ID'
,g.outbound_scac_code AS 'Carrier'
,concat(cast(pct.cube_length as int), 'x', cast(pct.cube_width as int), 'x', cast(pct.cube_height as int)) as 'BOX_DIMS_INCHES'
,(case when row_number() over (partition by mu.master_unit_no order by mu.master_unit_no) = 1
then concat(cast(mut.length as int), 'x', cast(mut.width as int), 'x', cast(mut.Height as int))
when mu.master_unit_no is null
then ''
end)
as 'PALLET_DIMS_INCHES'
,(case when g.booking_container_type_key = 6 THEN
'DIRECT'
when g.booking_container_type_key = 5 THEN
'AIR'
else 'CEVA-Ocean'
end) as 'Shipment Type'
,(case when row_number() over (partition by mu.master_unit_no order by mu.master_unit_no) = 1
then (pct.cube_length*0.0254)*(pct.cube_width*0.0254)*(pct.cube_height*0.0254)
when mu.master_unit_no is null
then (pct.cube_length*0.0254)*(pct.cube_width*0.0254)* (pct.cube_height*0.0254)
end)
as 'CBM'
,CASE
WHEN(ROW_NUMBER() OVER (PARTITION BY mu.master_unit_no ORDER BY mu.master_unit_no)) = 1
THEN (SELECT SUM(c.Gross_weight) + mut.tare_weight
from part_v_container c where c.master_unit_no = mu.master_unit_no) END AS 'Total Weight'
from part_v_container c
So this should have fixed my part. I do have an extra comment though. You have all these different prefixs (p., c., mut., mu., g., pct.). Where do you reference all of these? I can see where you reference c (it is right after the final from). Even in my part you use mut. but I don't know how you reference it. For example, c is useable because of from part_v_container c. c represents part_v_container. You can look into joins to help you get the other tables in there. If you want you can edit your original question and add all your tables to it (whether they are actual or examples). I just need to know the different table names and column names. I don't care about the actual data. I wish I personally knew you because this would be much easier in real time xD
EDIT 5
Using this table...
I used this query...
;WITH mult AS (SELECT (m.length*0.0254)*(m.width*0.0254)*(m.height*0.0254) AS multiply, m.container FROM measurement m)
, sumMult AS (SELECT SUM((m.length*0.0254)*(m.width*0.0254)*(m.height*0.0254)) AS sumMultiply, m.container FROM measurement m GROUP BY m.container)
, combine AS (SELECT s.sumMultiply AS sumMultiply, m.multiply AS multiply, m.container FROM mult m JOIN sumMult s ON m.container = s.container)
SELECT c.container, CASE WHEN (ROW_NUMBER() OVER (PARTITION BY c.container ORDER BY c.container)) = 1
THEN (SELECT c.sumMultiply)
ELSE (SELECT c.multiply)
END AS 'Cubic Meters'
FROM combine c GROUP BY c.container, c.sumMultiply, c.multiply
It SUMS all of the volumes for all parts in a container and displays it only in the first row (first part). The rest of the parts have their volume.
I can't completely convert it for you. I trust, since you have done it successfully in my previous queries, that you can convert it properly. I tried to keep the names for the table and columns as bland and recognizable as much as I could. It appears to be working how you want it. Incase you don't know what the ;WITH mult.... is...you can think of it like a function. Put the entire with statement (that is, mult, sumMult, combine) before your gigantic query. You can see in my query that my ;WITH is comes first (above) my SELECT query that produces the actual results.

How to do a SUM() inside a case statement in SQL server

I want to add some calculation inside my case statement to dynamically create the contents of a new column but I get the error:
Column 'Test1.qrank' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
This is the code I'm working on
case
when test1.TotalType = 'Average' then Test2.avgscore
when test1.TotalType = 'PercentOfTot' then (cnt/SUM(test1.qrank))
else cnt
end as displayscore
I did try to group but it didn't work.
Any hints?
The error you posted can happen when you're using a clause in the GROUP BY statement without including it in the select.
Example
This one works!
SELECT t.device,
SUM(case when transits.direction = 1 then 1 else 0 end) ,
SUM(case when transits.direction = 0 then 1 else 0 end) from t1 t
where t.device in ('A','B') group by t.device
This one not (omitted t.device from the select)
SELECT
SUM(case when transits.direction = 1 then 1 else 0 end) ,
SUM(case when transits.direction = 0 then 1 else 0 end) from t1 t
where t.device in ('A','B') group by t.device
This will produce your error complaining that I'm grouping for something that is not included in the select
Please, provide all the query to get more support.
You could use a Common Table Expression to create the SUM first, join it to the table, and then use the WHEN to to get the value from the CTE or the original table as necessary.
WITH PercentageOfTotal (Id, Percentage)
AS
(
SELECT Id, (cnt / SUM(AreaId)) FROM dbo.MyTable GROUP BY Id
)
SELECT
CASE
WHEN o.TotalType = 'Average' THEN r.avgscore
WHEN o.TotalType = 'PercentOfTot' THEN pt.Percentage
ELSE o.cnt
END AS [displayscore]
FROM PercentageOfTotal pt
JOIN dbo.MyTable t ON pt.Id = t.Id
If you're using SQL Server 2005 or above, you can use the windowing function SUM() OVER ().
case
when test1.TotalType = 'Average' then Test2.avgscore
when test1.TotalType = 'PercentOfTot' then (cnt/SUM(test1.qrank) over ())
else cnt
end as displayscore
But it'll be better if you show your full query to get context of what you actually need.

Counting all other types but the current one

I'm trying to write this query, that would calculate the average value of all the columns except the one that contains the type value, which I'm grouping the whole query by.
So for 4 types for example, each column in the resulting table will contain the average of all the other three type's values, i need to exclude the current type's rows.
As an example, if I was to calculate each type's average value for itself, the query would look like:
SELECT
SUM(some value) / COUNT(TYPE)
FROM TEMPTABLE
GROUP BY TYPE
Now I'm trying to calculate the other three's total average. Thanks.
You can do one query to get the distinct types, and LEFT JOIN the same table, checking for type-inequality:
SELECT t1.type,
SUM(t2.some_value) / COUNT(t2.type)
FROM ( SELECT DISTINCT type FROM temptable ) t1
LEFT JOIN temptable t2 ON ( t1.type <> t2.type )
GROUP BY t1.type
Since you only want the average, you could replace the line
FROM ( SELECT DISTINCT type FROM temptable ) t1
by
FROM temptable t1
but the first solution might perform better, since the number of rows is reduced earlier.
The starting point here is to make a cartesian join between your types and your temptable (guessing your tables structure is : type(id, type), valueTable(id, type_id, some_value))
The following query
SELECT t.type, SUM(vt.someValue) /
COUNT (*) AS sum FROM type t,
valueTable vt WHERE vt.type_id != t.id
GROUP BY t.type
should do the trick.
Will this do what you need?
(Possibly with another CASE statement to avoid divide by zero errors if there is a possibility none of a type might be returned, I've also not explicitly accounted for the case that type is NULL)
SELECT
SUM(CASE WHEN TYPE <> 'Type1' THEN someValue ELSE 0 END) /
SUM(CASE WHEN TYPE = 'Type1' THEN 1 ELSE 0 END) AS T1,
SUM(CASE WHEN TYPE <> 'Type2' THEN someValue ELSE 0 END) /
SUM(CASE WHEN TYPE = 'Type2' THEN 1 ELSE 0 END) AS T2,
SUM(CASE WHEN TYPE <> 'Type3' THEN someValue ELSE 0 END) /
SUM(CASE WHEN TYPE = 'Type3' THEN 1 ELSE 0 END) AS T3,
SUM(CASE WHEN TYPE <> 'Type4' THEN someValue ELSE 0 END) /
SUM(CASE WHEN TYPE = 'Type4' THEN 1 ELSE 0 END) AS T4
FROM TEMPTABLE
I think that you can just use this:
SELECT type, avg(col_01)
FROM myTable
GROUP BY type
Should work on Sybase too:
SELECT
SUM(some value) / SUM(CASE WHEN TYPE = 1 THEN 1 ELSE 0 END)
FROM TEMPTABLE
GROUP BY TYPE