Get Percentage from SubQuery ResultSet - sql

Am having a requirement to show the percentage value along with the other column values in result set.
SQl
select Name, days from table
O/P result set
Name days
Sam 20
ram 30
My required o\p is
Name days Percentage
Sam 20 40
ram 30 60
So i modified my query as below
select Name, days, (days / sum(days)) as Percentage
from (select Name, days from table) as temp
But able to get the desired o/p.
Thanks in advance

declare #tab table (name varchar(30),[days] int)
insert into #tab
select 'Sam', 20
union all
select 'ram', 30
declare #sum int
set #sum = (select sum(days) from #tab)
select name,days ,days*100/#sum as per
from #tab
output
name days per
Sam 20 40
ram 30 60

You can use CROSS JOIN
select Name, days, days * 100 / t.sum_days as Percentage
from table
cross join (
select sum(days) sum_days from table
) t
if the days is int then you should cast it first to get more accurate result: cast(days as decimal(10,2))

Another option is to use window function
select
Name, days
, Percentage = 100.0 * days / sum(days) over ()
from table

Have an uncorrelated subquery to return the total sum of days:
select t1.Name, t1.days, 100 * t1.days / (select sum(t2.days) from table t2) as Percentage
from table t1

Related

SQL Find Max Value and Number of Rows Whic Are Equal to That Value

Given a table, I am trying to find Max Months * Hackos and number of ID's with the max Months * Hackos value.
I tried the below code but it seems we cant use Max clause in the inner select.
SELECT MAX(MONTHS * HACKOS) AS MAXIMUM_HACKOS,
(SELECT COUNT(ID) FROM HACKER WHERE MONTHS*HACKOS = MAX(MONTHS*HACKOS)) AS NUMBER_OF_HACKERS
FROM HACKER ;
Correct expected output is 144 and 2 but my code is wrong.
You can use this query:
SELECT MAX(MONTHS * HACKOS) FROM HACKER
in the WHERE clause and then aggregate:
SELECT MAX(MONTHS * HACKOS) AS MAXIMUM_HACKOS,
COUNT(*) AS NUMBER_OF_HACKERS
FROM HACKER
WHERE MONTHS * HACKOS = (SELECT MAX(MONTHS * HACKOS) FROM HACKER)
select top 1
MONTHS * HACKOS,
count(*)
from HACKER
group by MONTHS * HACKOS
order by MONTHS * HACKOS desc
Can this solve your problem?
SELECT ID, NAME, MAX(MAXIMUM_HACKOS) FROM ( SELECT ID, NAME, ( MONTHS * HACKOS) as MAXIMUM_HACKOS FROM HACKER) A LIMIT 1
Try this
SELECT NAME FROM HACKER GROUP BY ID, NAME, MONTHS, MONTHS * HACKOS having MONTHS * HACKOS > 100 AND MONTHS < 10   order by ID

SQL query to select most recent of duplicates

I have a table of values, with a date stored against each entry for example
Name
Age
PaymentAmount
Date
Can someone help me to write a query that would show the most recent payment only of any person within a certain age range.
E.g If I had 5 entries, and wanted the most recent payment of all people aged 20-25
Allan, 45, $1500, 1/1/2014
Tim, 22, $1500, 1/2/2001
John, 25, $2000, 2/3/2001
Tim, 22, $2500, 1/2/2010
John, 25, $3000, 2/3/2010
It would return the bottom 2 rows only
You didn't state your DBMS, so this is ANSI SQL
select *
from (
select name,
age,
PaymentAmount,
Date,
row_number() over (partition by name order by date desc) as rn
from the_table
where age between 22 and 25
) t
where rn = 1;
Another option is to use a co-related subquery:
select name,age,paymentamount,date
from the_table t1
where age between 22 and 25
and date = (select max(date)
from the_table t2
where t2.name = t1.name
and t2.age between 22 and 25)
order by name;
Usually the solution with a window function is faster than the co-related subquery as only a single access to the table is needed.
SQLFiddle: http://sqlfiddle.com/#!15/17e37/4
Btw: having a column named age is a bit suspicious because you need to update that every year. You should rather store the date of birth and then calculate the age when retrieving the data.
This query would give you all records of most recent payment of age 20 and 25. Limit it by using TOP 2 or LIMIT 2 or rownum <=2 as per your DB syntax
SELECT NAME,AGE,PAYMENTAMOUNT,DATE FROM MY_TABLE
WHERE AGE BETWEEN 20 AND 25
AND DATE IN
(
SELECT MAX(DATE)
FROM MY_TABLE
WHERE
AGE BETWEEN 20 AND 25
);
EDIT as per horse_with_no_name:
SELECT NAME,AGE,PAYMENTAMOUNT,DATE
FROM the_table
WHERE AGE BETWEEN 20 AND 25
AND DATE IN
(
SELECT (DATE)
FROM the_table
WHERE
AGE BETWEEN 20 AND 25 order by date desc limit 2
)
limit 2;
Fiddle reference : http://sqlfiddle.com/#!15/17e37/10
Simplest of all,Try this following query
select name,age,paymentamount,date from yourtablename where date in (select max(date) from yourtablename where age between 20 and 25 and group by name);
You should Create a Table with Identity Column to make your Life easier
ColumnPrimaryKey IDENTITY (1,1)
Name
Age
PaymentAmount
Date
SELECT TOP 2 * FROM [TableName] Where Age BETWEEN 20 AND 25 ORDER BY [PrimaryKey] DESC
The above query will return the top two row Inserted in table
You can use between like
select * from meta where title='$title' and (date between '$start_date' and '$end_date').
Okay, I know you said SQL-- here's for people with two layers.
VIA SQL:
Order your SQL results by date descending (should be newest to oldest...).
VIA YOUR "BACK END":
Create an empty final set.
As you are iterating through your results, if your result row person is not in your final set, add the data to the final set.
Boom, your final set has the latest of each person.

months worth of data in database table help

I have a table of records like the following
Month Amount Sum
1 100 100
2 50 150
3 NULL NULL
4 NULL NULL
5 50 200
ETC.
How do I keep a running total sum column and I'd like to cascade the previous valid sum into null records like follows in one SQL Statement?
1 100 100
2 50 150
3 0 150
4 0 150
5 50 200
Any ideas?
This isn't something you'd typically store in the database, but rather get with a query. You would do a subquery on the table to get a sum:
SELECT
t1.Month, t1.Amount,
SUM(SELECT t2.Amount FROM my_table t2 WHERE t2.Month <= t1.Month)
FROM my_table t1
In this way I use the table twice, once as t1 and once as t2.
Assuming the new month and amount being inserted are represented by variables #month and #amount:
INSERT INTO t (Month, Amount, [Sum])
SELECT #month,
CASE WHEN #amount IS NULL THEN 0 ELSE #amount END,
CASE WHEN #amount IS NULL THEN SUM(Amount) ELSE SUM(Amount) + #amount END
FROM t
If the months are always going to consecutive, you could use MAX(Month) + 1 instead of #month as the inserted value.
(Though I agree with #JHolyHead's caveat that I'd be hesitant to store a running total inside the table...)
Either store the running sum value somewhere else where you can read and update it on every transaction, or do some clever logic in a SP that calculates it during the transaction.
If I'm honest, I wouldn't store it. I'd probably prefer to calculate it in the application when I need it. That way you can filter by date/whatever other criteria you like.
Works from version 2005
;with a as(
select month, coalesce(amount, 0) amount, row_number() over(order by /*year?,*/ month) rn
from yourtable
),
cte as
(
select month, amount, amount [sum1]
from a where rn = 1
union all
select a.month, a.amount, a.amount + b.amount
from cte join a on a.rn = cte.rn - 1
)
select month, amount, [sum1] from cte
I surgest you do not use column names like 'sum' not even for computed columns.
Don't waste a table column on a sum, imagine what happens when someone updates a column in the database. Just use a computed column in a view.

how to select values that sum up to 60% of the total

assume I have a table of this kind:
A B 3
C D 1
E F 2
G H 4
The sum of the last column is 10, and I want the biggest values that sum up to at least 60% of the total value. So, in this case, it will return
G H 4
A B 3
It goes up to 70% but if only the 1st value was selected, it will only go up to 40%. Even though there could be a combination that will return exactly 60%, we want to take the largest numbers.
So, I think I know how to sort the values from biggest to smallest and how to sum up all the values, but I don't know how to then take only lines that sum up to 60%.
--save the whole sum into a variable
summa = select sum(val) from sometable;
select *
from sometable o
where (
select sum(val)
from sometable i
where i.val <= o.val
) >= 0.6*summa;
I think this gives you the correct result. Need to work with a temporary table though, not sure if this can be avoided.
DECLARE #total bigint
select #total = SUM(value) from SampleTable
select st.*,
convert(decimal(10,2), (select SUM(value) from SampleTable st2 where st2.Value >= st.Value))/#total as percentage
into #temptable
from sampletable st
select * from #temptable
where Value >= (select max(Value) from #temptable where percentage >= 0.6)

Simple SQL select sum and values of same column

I have a co-worker who is working on a table with an 'amount' column.
They would like to get the top 5 amounts and the sum of the amounts in the same query.
I know you could do this:
SELECT TOP 5 amount FROM table
UNION SELECT SUM(amount) FROM table
ORDER BY amount DESC
But this produces results like this:
1000 (sum)
100
70
50
30
20
When what they really need is this:
100 | 1000
70 | 1000
50 | 1000
30 | 1000
20 | 1000
My intuitive attempts to achieve this tend to run into grouping problems, which isn't such an issue when you are selecting a different column, but is when you want to use an aggregate function based on the column you are selecting.
You can use a CROSS JOIN for this:
SELECT TOP 5 a.amount, b.sum
FROM table a
CROSS JOIN (SELECT SUM(amount) sum FROM table) b
ORDER BY amount DESC
This might work
SELECT TOP 5 amount, (SELECT SUM(amount) FROM table)
FROM table
ORDER BY amount DESC
Not really pretty, but this shouls do it:
SELECT TOP 5 amount, SAmount
FROM table Join
(SELECT SUM(amount) As SAmount FROM table)
ORDER BY amount DESC
As said by others, I'd probably use two queries.
Another approach using analytic functions (SQL Server 2005+):
SELECT TOP 5 amount, SUM(amount) OVER()
FROM table
ORDER BY
amount DESC