sql sum different column value descending - sql

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

Related

How to get the cumulative sum of an aggregate column?

I have this query in BigQuery that returns the representation of total contributing_factor_vehicle_1
SELECT
TBL_TOTAL.contributing_factor_vehicle_1,
TBL_TOTAL.TOTAL,
(TBL_TOTAL.TOTAL / SUM(TBL_TOTAL.TOTAL) OVER ()) * 100 AS PERCENTAGE
FROM
(SELECT
contributing_factor_vehicle_1,
COUNT(contributing_factor_vehicle_1) AS TOTAL
FROM
`bigquery-public-data.new_york_mv_collisions.nypd_mv_collisions`
WHERE
borough = 'BROOKLYN'
AND contributing_factor_vehicle_1 <> 'Unspecified'
GROUP BY
contributing_factor_vehicle_1
ORDER BY
TOTAL DESC) TBL_TOTAL
ORDER BY
TOTAL DESC
Output:
contributing_factor_vehicle_1
TOTAL
PERCENTAGE
Driver Inattention/Distraction
65427
28.913538237178777
Failure to Yield Right-of-Way
25831
11.415250679452903
Backing Unsafely
16384
7.240426895286917
Following Too Closely
12605
5.570408997503148
Passing Too Closely
10875
4.805886382217116
Now I need to get the cumulative PERCENTAGE to make a pareto analysis:
How do I achieve it please? Is it possible to use the column PERCENTAGE in a window function again?
contributing_factor_vehicle_1
TOTAL
PERCENTAGE
PERCENTAGE CUM
Driver Inattention/Distraction
65427
28.91%
28.91%
Failure to Yield Right-of-Way
25831
11.42%
40.33%
Backing Unsafely
16384
7.24%
47.57%
Following Too Closely
12605
5.57%
53.14%
Passing Too Closely
10875
4.81%
57.95%
Just add one more line into the outer SELECT as in below example
SELECT
TBL_TOTAL.contributing_factor_vehicle_1,
TBL_TOTAL.TOTAL,
ROUND((TBL_TOTAL.TOTAL/SUM(TBL_TOTAL.TOTAL) OVER ())* 100, 2) AS PERCENTAGE,
ROUND(((SUM(TBL_TOTAL.TOTAL) OVER (ORDER BY TOTAL DESC))/SUM(TBL_TOTAL.TOTAL) OVER ())* 100, 2) AS PERCENTAGE_CUM
FROM
(
SELECT
contributing_factor_vehicle_1,
COUNT(contributing_factor_vehicle_1) AS TOTAL
FROM `bigquery-public-data.new_york_mv_collisions.nypd_mv_collisions`
WHERE borough = 'BROOKLYN' AND contributing_factor_vehicle_1 <> 'Unspecified'
GROUP BY contributing_factor_vehicle_1
ORDER BY TOTAL DESC
) TBL_TOTAL
ORDER BY TOTAL DESC
with output

How to select 1000 customers who were the first to gain 1000 bonus points for purchases in categories "Taxi" and "Books"? (SQLite)

The BONUS table has attributes: client_id, bonus_date, the number of accrued bonuses (bonus_cnt), mcc code of the transaction for which added bonuses (mcc_code). The MCC_CATEGORIES table is a mcc code reference.
Attributes:
mcc-code (mcc_code), category (for example, supermarkets, transport, pharmacies, etc., mcc_category)
How to select 1000 customers who were the first to gain 1000 bonus points for purchases in
categories "Taxi" and "Books"?
BONUS table looks like:
CLIENT_ID BONUS_DATE BONUS_CNT MCC_CODE
1121 2020-01-02 23 5432
3421 2020-04-15 7 654
...
MCC_CATEGORIES table looks like:
MCC_CODE MCC_CATEGORY
5432 Taxi
3532 Music
...
I would use window functions and aggregation: first join the tables and compute the running sum of bonus per user and category. Then aggregate by user and category, and get the date when they reached a bonus of 1000. Finally, compute the date when each user reached the target on both categories, order by that, and limit:
select client_id, max(bonus_date) bonus_date
from (
select client_id, mcc_category, min(bonus_date) bonus_date
from (
select b.client_id, b.bonus_date, c.mcc_category,
sum(bonus_cnt) over(partition by b.client_id, c.mcc_category order by b.bonus_date) sum_bonus
from bonus b
inner join mcc_categories c on c.mcc_code = b.mcc_code
where mcc_category in ('Taxi', 'Books')
) t
where sum_bonus >= 1000
group by client_id, mcc_category
) t
group by client_id
having count(*) = 2
order by bonus_date
limit 1000
Window functions are available in SQLite starting version 3.25.
How to select 1000 customers who were the first to gain 1000 bonus points for purchases in categories "Taxi" and "Books"?
I am guessing you want to combine the bonuses for the two categories together. If so:
select client_id, min(bonus_date) as min_bonus_date
from (select b.client_id, b.bonus_date, b.bonus_cnt,
sum(b.bonus_cnt) over (partition by b.client_id order by b.bonus_date) as running_bonus_cnt
from bonus b join
mcc_categories c
on c.mcc_code = b.mcc_code
where mcc_category in ('Taxi', 'Books')
) bc
where running_bonus_cnt >= 1000 and
running_bonus_cnt - bonus_cnt < 1000
group by client_id
order by min_bonus_date
limit 1000;
Note how this works. The subquery calculates the running bonus amount. The where clause then gets the one row where the bonus count first exceeds 1000.
The rest is just aggregation.

getting avg of column based on the result set

I have a select statement that divides the count of sales by country, priceBanding (see example below)
The select statement looks like follows:
SELECT p.[Price Band]
,t.[Country]
,o.COUNT([Order]) as [Order Count]
FROM #price p (temp table)
INNER JOIN country t ON p.CountryCode = t.countryCode
INNER JOIN sales o ON o.salesValue >= p.startPrice and s.salesValue < p.endPrice
What i want to be able to do is based on this result i want to get an avg of the unit count i.e. For all orders that are under 20 what is the avg unit counts and the same for all others. How can i do this?
Its most likely simple but I cant think through it.
What I am after:
So as you can see, in the price band <20 in UK the order count is 50, and the avg Units of that is 2. As i mentioned earlier, I want the Avg Units of all orders that are under 20 (which is 50 in the picture).
Is that clearer?
Thanks in advance.
EDIT:
The first table: assume it to be the source
And the second table gets the avg, that's what I am after.
Wouldn't you just use avg()?
SELECT p.[Price Band], t.[Country],
o.COUNT(*) as [Order Count],
AVG(Items)
FROM #price p INNER JOIN
country t
ON p.CountryCode = t.countryCode INNER JOIN
sales o
ON o.salesValue >= p.startPrice and s.salesValue < p.endPrice
GROUP BY p.[Price Band], t.[Country]
ORDER BY t.[Country], p.[Price Band]
Note: SQL Server does integer division of integers (so 3/2 = 1 not 1.5) and similarly for AVG(). It is more accurate to use a decimal point number. An easy way is to use AVG(items * 1.0).

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.

How to find the SUM of the Calculated Percentage Column in 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