How to find the SUM of the Calculated Percentage Column in SQL - sql

I have a Column which calculates the Percentage , like this
Convert(decimal(5,2),(PatCount*100)/#PatientCount) as Per
Now i want the Total Sum of the above calculated Percentage. So i tried doing this,
,SUM(Convert(decimal(5,2),(PatCount*100)/#PatientCount)) as pa
But i am not geting the Desired Result . For ex
Per % Total %
6.00 6.00
7.00 7.00
85.00 85.00
I want the total Col to print as 98%. Please can Somebody help me with this.

Try this
SQL FIDDLE Example
select
cast(PatCount * 100 / #PatientCount as decimal(5,2)) as Per,
sum(cast(PatCount * 100 / #PatientCount as decimal(5,2))) over() as Total
from Patients as P

For the sum to work you will need a GROUPBY, then the sum is over the group.
Simplest is to do this in a separate query. There may be a way to do this with a sub-query or you could look into a cumulative sum: Create a Cumulative Sum Column in MySQL

You have some options but using a CROSS APPLY should have pretty good performance characteristics.
;WITH q AS (
SELECT SUM(CONVERT(decimal(5,2),(PatCount*100)/#PatientCount)) as Per
FROM YourTable
)
SELECT CONVERT(decimal(5,2),(PatCount*100)/#PatientCount) as Per
, q.Per
FROM YourTable
CROSS APPLY q
or perhaps even better (to read)
;WITH q AS (
SELECT CONVERT(decimal(5,2),(PatCount*100)/#PatientCount) as Per
FROM YourTable
)
SELECT q.Per, qtot.PerTot
FROM q CROSS APPLY (SELECT SUM(Per) as PerTot FROM q) qtot

Related

SQL select distinct count division

I have a select statement with a distinct count and I need to divide the result of the select count with a number . How can I do it?
I have for example:
select distinct count(profile_entity_name)
from table_name
where visit_id like 'JWM%' and profile_entity_name not in ('JWM 2.0 COM','JWM 2.0 MASTER')
and it gives the result 2000
I want to divide the 2000 with 130 for example on the fly
How can I do it?
I tried the whole select with the division at the end '/130' and it doesn't work
As an complement to Md. Suman Kabir's Answer, if you want the select to return the exact division, just cast the "count" function and the divisor number as float, like this:
select cast(count(distinct profile_entity_name) as float) / cast(130 as float) from table_name
Use of distinct before count has no meaning. Perhaps you want to count distinct profile_entity_name, So you can try this :
select count(distinct profile_entity_name) / 130 from ....
save your result and divide with 130
select TB1.[total count]/130 from (select distinct count(profile_entity_name)as[total count]
from table_name
where visit_id like 'JWM%' and profile_entity_name not in ('JWM 2.0 COM','JWM 2.0 MASTER') ) as TB1

How to get mean ,median , mode and range in a single select query?

I'm trying to get mean, median, mode and range for a set of values in a table. I was able to get the average but median, range and mode I'm getting a wrong one.
Below is my code which I tried for the above concept.
Select
CDS.[Commodity_SourceSeriesID_LongDesc] AS 'Description',
TD.TimeDimension_Year AS 'Year',
AVG(DV.DataValues_AttributeValue) AS 'Average/Mean',
MAX(dv.DataValues_AttributeValue) AS 'Maximum value for the Year',
MIN(dv.DataValues_AttributeValue) AS 'Minimum value for the Year',
((MAX(dv.DataValues_AttributeValue) + MIN(dv.DataValues_AttributeValue)) / 2) AS 'Median',
--,(SELECT TOP 1 with ties DataValues_AttributeValue
--FROM [CoSD].[DataValues]
--WHERE DataValues_AttributeValue IS Not NULL AND DataValues_ERSCommodity_ID = 157 and DataValues_DataRowLifecyclePhaseID = 1
--GROUP BY DataValues_AttributeValue
--ORDER BY COUNT(*) DESC) AS Mode
(MAX(dv.DataValues_AttributeValue) - MIN(dv.DataValues_AttributeValue)) AS 'Range'
FROM
[CoSD].[DataValues] DV
INNER JOIN
[CoSD].[CommodityDataSeries] CDS ON CDS.Commodity_ID = DV.DataValues_Commodity_ID
INNER JOIN
[CoSD].[TimeDimension_LU] TD ON TD.TimeDimension_ID = DV.DataValues_TimeDimension_ID
WHERE
DataValues_Commodity_ID = 157
AND DataValues_DataRowLifecyclePhaseID IN (1, 4)
GROUP BY
DV.DataValues_TimeDimension_ID,
CDS.Commodity_SourceSeriesID_LongDesc,
TD.TimeDimension_Year
Is there a way to achieve this?
Thanks
In SQL 2012 or later, it's often easier to use the percentile_cont function to calculate the median. It looks like the rest of your question has already been addressed, but I thought you'd want to know about this option as well.
https://msdn.microsoft.com/en-us/library/hh231473.aspx
Not sure if this will help, but here is some sql which allows me generate some stats (..., mean, median, mode,..) within a group by
cteBase would be your core data (non-aggregated or groupded)
cteMedian would generate the median of cteBase
cteMode would calculate the mode of cteBase
I am calculated only one measure, but I suspect it can easily be expanded
Where I have "GrpByYear", this would have to be expanded into your compound fields.
;with cteBase as (
Select RowNr=Row_Number() over (Partition By Year(TR_Date) Order By Year(TR_Date),TR_Y10)
,GrpByYear = Year(TR_Date)
,Measure = TR_Y10
From [Chinrus-Series].[dbo].[DS_Treasury_Rates]
Where Year(TR_Date)>2014
)
,cteMedian as (Select A.GrpByYear,Measure From cteBase A Join (Select GrpByYear,RowNr=Max(RowNr)/2 from cteBase Group by GrpByYear) B on (A.GrpByYear=B.GrpByYear and A.RowNr=B.RowNr))
,cteMode as (Select * from (Select RowNr=Row_Number() over (Partition By GrpByYear Order by Count(*) Desc),GrpByYear,Measure,Hits=count(*) From cteBase Group by GrpByYear,Measure) A Where RowNr=1)
Select A.GrpByYear
,RecordCount = Count(*)
,DistinctCount = Count(Distinct A.Measure)
,SumTotal = Sum(A.Measure)
,Minimum = Min(A.Measure)
,Maximum = Max(A.Measure)
,Mean = Avg(A.Measure)
,Median = Max(B.Measure)
,Mode = Max(C.Measure)
,StdDev = STDEV(A.Measure)
From cteBase A
Join cteMedian B on A.GrpByYear=B.GrpByYear
Join cteMode C on A.GrpByYear=C.GrpByYear
Group By A.GrpByYear
Order By A.GrpByYear
Year RecordCount DistinctCount SumTotal Minimum Maximum Mean Median Mode StdDev
2016 110 43 204.82 1.63 2.25 1.862 1.84 1.83 0.128568690811108
2015 251 69 536.71 1.68 2.50 2.1382 2.16 2.20 0.1662836533952
I imagine that you may rather want to do something like this:
select dbo.Median(DataValues_AttributeValue)
from ...
There is no slick way to get the median or mode in a manner similar to using the native aggregates such as avg, max, min, max, etc. However, you may want to try a .NET CLR aggregate implementation where you implement the median and mode in, for example, C# if you want something elegant, e.g. like the above code snippet.
This is what I've done in the past.

how to perform multiple aggregations on a single SQL query

I have a table with Three columns:
GEOID, ParcelID, and PurchaseDate.
The PKs are GEOID and ParcelID which is formatted as such:
GEOID PARCELID PURCHASEDATE
12345 AB123 1/2/1932
12345 sfw123 2/5/2012
12345 fdf323 4/2/2015
12346 dfefej 2/31/2022 <-New GEOID
What I need is an aggregation based on GEOID.
I need to count the number of ParcelIDs from last month PER GEOID
and I need to provide a percentage of that GEOID of all total sold last month.
I need to produce three columns:
GEOID Nbr_Parcels_Sold Percent_of_total
For each GEOID, I need to know how many Parcels Sold Last month, and with that Number, find out how much percentage that entails for all Solds.
For example: if there was 20 Parcels Sold last month, and 4 of them were sold from GEOID 12345, then the output would be:
GEOID Nbr_Parcels_Sold Perc_Total
12345 4 .2 (or 20%)
I am having issues with the dual aggregation. The concern is that the table in question has over 8 million records.
if there is a SQL Warrior out here who have seen this issue before, Any wisdom would be greatly appreciated.
Thanks.
Hopefully you are using SQL Server 2005 or later version, in which case you can get advantage of windowed aggregation. In this case, windowed aggregation will allow you to get the total sale count alongside counts per GEOID and use the total in calculations. Basically, the following query returns just the counts:
SELECT
GEOID,
Nbr_Parcels_Sold = COUNT(*),
Total_Parcels_Sold = SUM(COUNT(*)) OVER ()
FROM
dbo.atable
GROUP BY
GEOID
;
The COUNT(*) call gives you counts per GEOID, according to the GROUP BY clause. Now, the SUM(...) OVER expression gives you the grand total count in the same row as the detail count. It is the empty OVER clause that tells the SUM function to add up the results of COUNT(*) across the entire result set. You can use that result in calculations just like the result of any other function (or any expression in general).
The above query simply returns the total value. As you actually want not the value itself but a percentage from it for each GEOID, you can just put the SUM(...) OVER call into an expression:
SELECT
GEOID,
Nbr_Parcels_Sold = COUNT(*),
Percent_of_total = COUNT(*) * 100 / SUM(COUNT(*)) OVER ()
FROM
dbo.atable
GROUP BY
GEOID
;
The above will give you integer percentages (truncated). If you want more precision or a different representation, remember to cast either the divisor or the dividend (optionally both) to a non-integer numeric type, since SQL Server always performs integral division when both operands are integers.
How about using sub-query to count the sum
WITH data AS
(
SELECT *
FROM [Table]
WHERE
YEAR(PURCHASEDATE) * 100 + MONTH(PURCHASEDATE) = 201505
)
SELECT
GEOID,
COUNT(*) AS Nbr_Parcels_Sold,
CONVERT(decimal(18,8), COUNT(*)) /
(SELECT COUNT(*) FROM data) AS Perc_Total
FROM
data t
GROUP BY
GEOID
EDIT
To update another table by the result, use UPDATE under WITH()
WITH data AS
(
SELECT *
FROM [Table]
WHERE
YEAR(PURCHASEDATE) * 100 + MONTH(PURCHASEDATE) = 201505
)
UPDATE target SET
Nbr_Parcels_Sold = source.Nbr_Parcels_Sold,
Perc_Total = source.Perc_Total
FROM
[AnotherTable] target
INNER JOIN
(
SELECT
GEOID,
COUNT(*) AS Nbr_Parcels_Sold,
CONVERT(decimal(18,8), COUNT(*)) /
(SELECT COUNT(*) FROM data) AS Perc_Total
FROM
data t
GROUP BY
GEOID
) source ON target.GEOID = source.GEOID
Try the following. It grabs the total sales into a variable then uses it in the subsequent query:
DECLARE #pMonthStartDate DATETIME
DECLARE #MonthEndDate DATETIME
DECLARE #TotalPurchaseCount INT
SET #pMonthStartDate = <EnterFirstDayOfAMonth>
SET #MonthEndDate = DATEADD(MONTH, 1, #pMonthStartDate)
SELECT
#TotalPurchaseCount = COUNT(*)
FROM
GEOIDs
WHERE
PurchaseDate BETWEEN #pMonthStartDate
AND #MonthEndDate
SELECT
GEOID,
COUNT(PARCELID) AS Nbr_Parcels_Sold,
CAST(COUNT(PARCELID) AS FLOAT) / CAST(#TotalPurchaseCount AS FLOAT) * 100.0 AS Perc_Total
FROM
GEOIDs
WHERE
ModifiedDate BETWEEN #pMonthStartDate
AND #MonthEndDate
GROUP BY
GEOID
I'm guessing your table name is GEOIDs. Change the value of #pMonthStartDate to suit yourself. If your PKs are as you say then this will be a quick query.

percentage calculation for each row in hive

i have got a table in hive with the following schema
(diference int,count_value int)
The values are
5 2,
30 1,
90 1,
100 1
Now i want to find percentage of each count_value with sum of count_value. Something like count_value/sum(count_value) for each row. Can anybody please help. Thanks in advance
With the new analytics and windowing functions introduced in Hive 0.11, you can do:
SELECT count_value / sum(count_value) over () as p from myTable
This avoids a join, plus easier to do the calculation if partitioned by another field. For example, if the source table had a key field and you wanted the calculation to use the sum from the rows with the same key, you could do:
SELECT count_value / sum(count_value) over (partition by key) as p from myTable
How about using a subquery to calculate the total first, then joining the total to each row?
SELECT
count_value / count_value_sum AS p
FROM
myTable t
JOIN
(SELECT SUM(count_value) AS count_value_sum FROM myTable) s
Hope that helps.

sql sum different column value descending

I have this query:
Available Total Usage
7000.0 7021.9
7000.0 -15000.00
7000.0 -7700.85
I want to create new column to sum both column in descending order.The result I wish is
Available Total Usage Total
7000.0 7021.9 -700.85+(-15000.00) = -15700.85
7000.0 -15000.00 7000+(-7700.85) = -700.85
7000.0 -7700.85 7000
How can I do this?
try this:
with cte as(select Available, [Total Usage], Available+[Total Usage] as Total from <table>)
select * from CTE order y Total