SQLServer Calculate Average of Multiple Columns - sql-server

I have generated a table using PIVOT and the ouput of columns are dynamic. One of the output is as given below:
user test1 test2 test3
--------------------------------
A1 10 20 30
A2 90 87 75
A3 78 12 34
The output of above table represents a list of users attending tests. The tests will be added dynamically, so the columns are dynamic in nature.
Now, I want to find out average marks of each user as well as average marks of each test.
I am able to calculate the average of each test, but got puzzled to find out the average of each user.
Is there a way to do this??
Please help.
Mahesh

You can add the marks for each user then divide by the number of columns:
SELECT
user,
(test1 + test2 + test3) / 3 AS average_mark
FROM users
Or to ignore NULL values:
SELECT
user,
(ISNULL(test1, 0) + ISNULL(test2, 0) + ISNULL(test3, 0)) / (
CASE WHEN test1 IS NULL THEN 0 ELSE 1 END +
CASE WHEN test2 IS NULL THEN 0 ELSE 1 END +
CASE WHEN test3 IS NULL THEN 0 ELSE 1 END
) AS average_mark
FROM users
Your table structure has two disadvantages:
Because your table structure is created dynamically you would also have to construct this query dynamically.
Because some students will not have taken all tests yo may have some NULL values.
You may want to consider changing your table structure to fix both of these problems. I would suggest that you use the following structure for your table:
user test mark
-------------------
A1 1 10
A2 1 90
A3 1 78
A1 2 20
A2 2 87
A3 2 12
A1 3 30
A2 3 75
A3 3 34
Then you can do this to get the average mark per user:
SELECT user, AVG(mark) AS average_mark
FROM users
GROUP BY user
And this to get the average mark per test:
SELECT test, AVG(mark) AS average_mark
FROM users
GROUP BY test

Can you do it on your data source before you pivot it?

The simple answer is to UNPIVOT the same way you just PIVOTed. But the best answer is to not do the PIVOT in the first place! Store the unpivoted data in a table first, then from that do your PIVOT and your average.

Related

Alternate for Array Sum Formula

Table copied as Text
Column1 Column2 Column3 Column4 Column5 Column6
A AA AAA 100 95 92
A AA AAA 85 83 81
A AA BBB 200 199 160
A BB AAA 65 55 49
B AA AAA 89 88 83
B AA BBB 150 149 145
B BB AAA 140 135
B BB BBB 190 185
B AA AAA 510
AA
AAA BBB
A 173 160
B 593 145
and some more explanation
Basically i want the sum of "Column 6" for the given criteria but the data in Column 6 can only be entered after some delay w.r.t. Column 1, Column 2, Column 3 & Column 4.
Till Column 6 data is entered, i want excel to use the number available in Column 5 which is also entered after some delay w.r.t. Column 1, Column 2, Column 3 & Column 4 but before Column 6.
And till Column 5 data is entered, i want excel to use the number available in Column 4.
Now I am familiar with two SUM/IF arrangements as included below in post.
First one is array sum/if arrangement which is convenient to write but results in terribly long calculation time with 1.5 seconds for just one column and I have over 100 columns in one sheet and about 9 sheets.
Second one is using SUMIFS which requires extensive time to write but relatively better calculation time of 0.5 seconds for column but is still quite high.
Now I need to do away with the array arrangement but doing so will take quite some time and I want to know if there is any better/other arrangement.
Just let me know other arrangement which can get the required result and I will check the arrangement for calculation timing. If the other arrangement is also convenient to write than that is a plus.
This is my table:
And I want to add the right most columns which are not empty i.e. have a number in it, but with the criteria for the first three columns in cell D15.
I only found option to add image. Please let me know how to upload excel file.
enter image description here
Can somebody please suggest an alternate to this array formula so it can calculate way faster
{=SUM(
IF(
($B$2:$B$10=$C15)*
($C$2:$C$10=$C$13)*
($D$2:$D$10=D$14)>0,
IF(
$G$2:$G$10<>"",
$G$2:$G$10,
IF(
$F$2:$F$10<>"",
$F$2:$F$10,
$E$2:$E$10))))}
I have tried below which reduces the calculation time to 1/3 but it is too much typing for the large data I am dealing with
=SUMIFS(
$G$2:$G$10,
$B$2:$B$10,$C15,
$C$2:$C$10,$C$13,
$D$2:$D$10,H$14,
$G$2:$G$10,"<>"&"")
+SUMIFS(
$F$2:$F$10,
$B$2:$B$10,$C15,
$C$2:$C$10,$C$13,
$D$2:$D$10,H$14,
$G$2:$G$10,"="&"",
$F$2:$F$10,"<>"&"")
+SUMIFS(
$E$2:$E$10,
$B$2:$B$10,$C15,
$C$2:$C$10,$C$13,
$D$2:$D$10,H$14,
$G$2:$G$10,"="&"",
$F$2:$F$10,"="&"")
If you're OK with using a helper column (which you should be), you can use this formula in a helper cell and drag down. (In my example at bottom, this formula is in cell H2 and drag down.)
= INDEX(E2:G2,MATCH(-1E+300,E2:G2,-1))
This gets all of the data in either column 4 5 or 6 all into one column.
Then you can use a simpler SUMIFS formula in cell D15:
= SUMIFS($H$2:$H$10, // Sum range (helper column)
$B$2:$B$10,$C15, // Criteria 1 (A or B)
$C$2:$C$10,$C$13, // Criteria 2 (AA or BB)
$D$2:$D$10,D$14) // Criteria 3 (AAA or BBB)
See below, working example:
DISCLAIMER
This answer will simplify your formulas, but I'm not sure if this will help with the performance problems you are experiencing. SUMIFS in itself I don't see being likely the cause of long calculation times. Probably you are experiencing long calculation times because other parts of your spreadsheet are using inefficient formulas and/or formulas involving volatile cells, but that is just a guess because I have no idea what the rest of your spreadsheet looks like.

need help in solving sql problems using order by to order building floor

i have this building floor data selected:
6
5
4
3
2
1
UG
GM
G
LG
5B
5A
B1
B2
for this sorting i use this kind of Order by :
order by
(case when ISNUMERIC(floorNo) = 1 then CAST(floorNo AS Int) end) desc ,
(case when ISNUMERIC(left(floorNo,1)) = 0 and ISNUMERIC(substring(floorNo,2,1)) = 1 then floorNo end) asc,
(case when ISNUMERIC(floorNo) = 0 and left(floorNo,1) <>'L' then floorNo end) desc
but i want to make it like this :
6
5B
5A
5
4
3
2
1
UG
GM
G
LG
B1
B2
Can ANy one Help me solve it?
If you make a complicated enough (set of) case statement(s), you would eventually be able to handle all the possibilities, but it is likely to run very slow if you have a lot of data.
If I had to do this, I would probably make a separate lookup table (FloorOrder) with two columns; this floor code and an order column (integer). Create a script to populate the lookup table with all the various possibilities - pick a maximum number of floors, basements, and subfloors per floor, and make all of the possibilities with some loops. Then add all the various floors near ground floor. Make sure the order numbers are spread out enough that you can easily add other codes in between when somebody comes up with a new option (because they will). Something like this subset.
Code Order
2 2000
1C 1300
1B 1200
1A 1100
1 1000
UG 800
GM 500
G 0
LG -300
B1 -1000
It doesn't really matter what the order codes are, as long as they sort the list in the right order, can be easily generated when creating the table, and leave space for fitting things in the gap. Whenever somebody comes up with a new weird floor code (some I've seen near me are things like M (Mezzanine, UM for Upper Mezzanine, etc), add new records to the FloorOrder table to fit them in. Make sure you table has an index on the floor codes
To use it, join to the FloorOrder table, sort by the Order column.

Excel, Frequent string value with IF condition

I would like to find the modal area code for each ID number in excel.
I have 2 columns
ID no. Area Code
1 ABC
1 ABC
1 ABC
1 DEF
2 HIJ
2 HIJ
2 KLM
So far I am finding the mode of the whole column using:
=(INDEX(B:B,MODE(MATCH(B:B,B:B,0))))
But I would like all ID no. 1 area codes to be ABC and ID no. 2 to be HIJ
Any advice would be great! Thanks
You could use a lookup table with the following array formula:
=INDEX($B$2:$B$13,MODE(IF($A$2:$A$13=D2,MATCH($A$2:$A$13,$A$2:$A$13,0))))
You enter array formulas by pressing Ctrl + Shift + Enter to enter the formula
In the example shown below the formula would go in E2 next to the first listed ID and then you would drag it down for all the IDs in the adjacent column.
Example:

AVG giving a Count instead of Average

This is probably a silly mistake on my end but I can't quite figure it out on my on.
I'm trying to calculate average over a set of data pulled from a sub-query presented in the following way:
TotalPDMPs DefaultClinicID
13996 -1
134 23
432 29
123 26
39 27
13 21
40 24
46 30
1 25
Now the average for each 'DefaultClinicID' calculated for 'TotalPDMPs' is the same as the data above.
Here's my query for calculating the average:
select DefaultClinicID as ClinicID, AVG(TotalPDMPs)
from
(select count(p.PatientID) as TotalPDMPs, DefaultClinicID from PatientPrescriptionRegistry ppr, Patient p
where p.PatientID = ppr.PatientID
and p.NetworkID = 2
group by DefaultClinicID) p
group by DefaultClinicID
can someone tell me what I'm doing wrong here?
Thanks.
The group by column is the same so it gets a count in the inner query by DefaultClinicID and then it tries to take an average of the same DefaultClinicID.
Does that make sense? Any aggregation on that column while you group by the same thing will return the same thing. So for clinic 23 the average calculation would be: 134 / 1 = 134.
I think you just need to do the average in your inner query and you get what you want. Or maybe avg(distinct p.patientID) is what you are after?
In the inner sub-query you already grouped by DefaultClinicID,
So every unique DefaultClinicID has already only one row.
And the avg of x is x.

Do arithmatic inside database. Is this possible?

Is it possible to this dynamically Add(stage_1 + stage_2) and get the total saved into the column called total. I am using phpMyAdmin. And the stage columns are of type float.
Car stage_1 stage_2 total
1 30 50 80
2 28 51 79
3 31 51 82
Thanks in advance for any help.
Try this:
update cartable set total = stage_1 + stage_2
In fact, instead of storing the column total in the database, you could just create a view:
create view carview as
select Car, state_1, stage_2, stage_1 + stage_2 as total
from cartable

Resources