Is there a way to sum the rows above the current row - sql

I am trying to replicate a spreadsheet into a database and I am stumped on how to only sum the rows above the current row like I can do in excel. For example, the formula for the one column is as follows:
=SUM($B$9:$B9)/SUM($E$9:$E9)
=SUM($B$9:$B10)/SUM($E$9:$E10)
=SUM($B$9:$B11)/SUM($E$9:$E11)
.... and so on.
I need to somehow reproduce this formula in my select qry but not sure how?
SELECT Column1,Column2, SUM(Column1) + SUM(Column2) as Expr1
From tblTest
Group By Column1,Column2
Any ideas?
Col1 Col2 Col3 Total Col1/Total Trying to get this
7 0 3 10 70.00% 70.00%
1 0 1 100.00% 72.73%
2 0 4 6 33.33% 58.82%
3 1 1 5 60.00% 59.09%

The trick is you want to use a subquery with a way to identify all the previous rows.
SELECT ID,
(
SELECT SUM(ValueColumn)
FROM Test T2
WHERE T2.ID <= T1.ID
) RunningSum
FROM
Test T1
ORDER BY
T1.ID
This will work. If you have a large data set you may want to just select the data and calculate in your application as you'll be able to keep a running-sum as you loop through the data more efficiently than this query will run.

Related

how to set a range of defaults in a count query

I have a simple table of values:
column1
-------
2
5
7
5
8
7
and this simple query of number count:
SELECT column1, count(column1) as counter
FROM table
GROUP BY column1
ORDER BY count(column1) DESC
The question how can I add rows with values 0 when I have a number range for example from 1 to 8.
I want to get the result like this:
column1 Counter
-------- -------
5 2
7 2
2 1
8 1
1 0 <-- Row Add
2 0 <-- Row Add
3 0 <-- Row Add
4 0 <-- Row Add
6 0 <-- Row Add
Thanks very much.
If you are willing to use more than 1 query and to put your range of numbers in a table at least temporarily then you can do this with a full outer join. To do a Full outer join in access you combine a left join and a right join using either UNION OR UNION ALL.
copy the sql from the right and left joins into a union query then add the union and the order by statements to the union query.
SELECT SpecialNumbers.Numbers, mytable.Column1, Count(mytable.Column1) AS CountOfColumn1
FROM SpecialNumbers LEFT JOIN mytable ON SpecialNumbers.Numbers = mytable.Column1
GROUP BY SpecialNumbers.Numbers, mytable.Column1
UNION
SELECT SpecialNumbers.Numbers, mytable.Column1, Count(mytable.Column1) AS CountOfColumn1
FROM SpecialNumbers RIGHT JOIN mytable ON SpecialNumbers.Numbers = mytable.Column1
GROUP BY SpecialNumbers.Numbers, mytable.Column1
ORDER BY CountOfColumn1 DESC;
Given my special numbers where 1 to 10 This turns
to
Assuming that you only wish the four missing rows added, this is not that difficult in Access, as it is easy to create a small query generating numbers from a system table:
SELECT
T.Column1,
Count(Table.[Column1]) AS [Counter]
FROM
(SELECT DISTINCT Abs([id] Mod 10) AS Column1
FROM MSysObjects
WHERE (Abs([id] Mod 10)) Between 1 And 8) As T
LEFT JOIN
[Table]
ON T.Column1 = Table.Column1
GROUP BY
T.Column1
ORDER BY
Count(Table.[Column1]) DESC,
T.Column1;
Output:

SQL query Splitting a column into Multiple rows divide by percentage

How to get percentage of a column and then inserting it as rows
Col1 item TotalAmount**
1 ABC 5558767.82
2 ABC 4747605.5
3 ABC 667377.69
4 ABC 3844204
6 CTB 100
7 CTB 500.52
I need to create a new column percentage for each item which is I have done as :-
Select item, (totalAmount/select sum(totalAmount) from table1) as Percentage
From table1
Group by item
Col1 item TotalAmount percentage
1 ABC 5558767.82 38
2 ABC 4747605.5 32
3 ABC 667377.69 5
4 ABC 3844204 26
6 CTB 100 17
7 CTB 500.52 83
Now, the complex part I have to calculate another amount by multiplying this percentage to an amount from another table say table2
ii) update the Total amount column by spilt the total amount column of table 1 into 2 rows – 1st row of the new Calculate PledgeAmount and 2nd row – (totalAmount – PledgeAmount)
*Select t1.percentage * t2.new amount as [PledgeAmount]
From table 1 join table2 where t1.item=t2.item*
. e.g. for col1 Amount of 5558767.82 will split into two rows.
Final Result sample for :-
Col1 item TotalAmount Type
1 ABC 363700.00 Pledge
1 ABC 5195067.82 Unpledge
....
I am using Temporary table to do calculations.
One of the way I think is to calculate the Pledged and Unpledged amount as new column and Pivot it but its huge table with hundreds of columns it will not perform fast.
Any other efficient way?
You can use a windowing function to solve this problem -- first in a sub-query calculate the total and then in the main query the percent:
Select *, (totalAmount/total_for_item)*100 as percent_of_total
from (
SELECT t.*,
SUM(totalAmount) OVER (PARTITION BY item) as total_for_item
FROM table t
) sub
First, let's get the total amount per item:
SELECT item, SUM( totalAmount ) as sumTotal
INTO #totalperitem
FROM table1
GROUP BY item
Now it's easy to get to the percentages:
SELECT t1.Col1,
t1.item,
t1.totalAmount,
t1.totalAmount/tpi.sumTotal*100 AS percentage
FROM table1 t1
INNER JOIN #totalperitem tpi on ...
Tricky part: Separate rows with/without match in table2. Can be done with a WHERE NOT EXISTS, or, my preference, with a single outer join:
SELECT t1.item,
CASE WHEN tpledged.item IS NULL
THEN "Unpledged"
ELSE "Pledged"
END,
SUM( t1.totalAmount ) AS amount
FROM table1 t1
LEFT OUTER JOIN table2 tpledged ON t1. ... = tpledged. ...
GROUP BY t1.item,
CASE WHEN tpledged.item IS NULL
THEN "Unpledged"
ELSE "Pledged"
END
The basic trick is to create an artificial column from the presence/absence of records in table2 and to also group by that artificial column.

Apply a Substr to a distinct result in oracle

In Oracle, I need to do the average of a column (timeInmillis) from a join query that shows "duplicated" values (relative to the timeInmillis column from table1). I need to mantain the values from the join, but get the right result for the average.
I'm trying to do something like this:
select AVG(SUBSTR(DISTINCT(concat(id1,timeInMillis)),LENGTH(id1)+1,LENGTH(CONCAT(id1,timeInMillis)))), someColumn, otherColumn
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id1 = t2.id1 group by somestuff,someotherStuff;
If I try to do this, I get:
ORA-00936: missing expression
This would be an example:
Table1:
id1 timeInMillis otherColumn
1 5 X
2 15 X
Table2:
id2 id1 otherColumn
--------------------
1 1 X
2 1 X
3 2 X
From my join I get a resultset like this:
id1 id2 timeInmillis moreColumns
--------------------------------
1 1 5 X
1 2 5 X
2 3 15 X
I need to get the average of 5 and 15 (with distinct id1), but I can't modify the where part of the sql (cause of the other values I'm getting)
My result should be:
AVG(TIMEINMILLIS) otherResults
----------------------------------
10 'whatever'
Thanks in advance.
1) Option
select SUBSTR(someColumn,n,m) from (
select DISTINCT someColumn from MYTABLE
);
2) Option
select DISTINCT SUBSTR(someColumn,n,m) from MYTABLE;
*) Queries can return different result.
Your last edit finally explains clearly what you want. You want one line only, showing the avarage of table1's values, but of course without the duplicates that you got because of joining with table 2.
One solution is to get to the final value in two steps:
select avg(distinct_time), sum(sub_sum)
from
(
select max(timeinmillis) as distinct_time, sum(some_other_colum) as sub_sum
from (query)
group by id1
);
The other solution would be to rewrite the query.
Your syntax is wrong. You can try somthing like this either:-
select avg(TimeInMillis), other_cols_as_well
from(SELECT TAB1.id1, TAB2.id2, avg(TimeInMillis) as TimeInMillis
FROM TAB1, TAB2
WHERE TAB1.id1 = TAB2.id1
group by TAB1.id1, TAB2.id2) temp
where temp.id1 <> temp.id2
group by other_cols_as_well
Here is the fiddle
http://sqlfiddle.com/#!4/1fc017/16

shifting some columns one record back or forward

I have a table with about 8000 rows and 15 columns. After I have inserted the data I saw that my data was wrong after a number of records (let's say 1000) some column values belong to the previous record some thing like this:
A B C (A+B)
==================================
1 1 2
2 2 4
3 3 6
4 4 8
5 5
6 6 10
7 7 12
8 8 14
9 9 16
Now I have to either move some column values a record back or forward and I don't actually have much option testing it I'm afraid I may overwrite some data and ruin the whole table
I should do something like this but for about 7000 records:
update table1
set B = (select B from table1 where id = 1000)
where id = 999
Any ideas?
If you know the ids are sequential with no gaps, you can use a join to look up the value you want:
update t1
set c = tt1.c
from table1 t1 join
table1 t2
on t1.id = t2.id - 1
where t1.id > 1000;
If you cannot trust the ids, you can create the appropriate sequential number without gaps using row_number():
with toupdate as (
select t.*, row_number() over (order by id) as seqnum
from table1
)
update t1
set c = tt1.c
from toupdate t1 join
toupdate t2
on t1.seqnum = t2.seqnum - 1
where t1.id > 1000;
Create another table with the same fields as the table in question. Insert the bad records. Fix the data in the new table. Update the real table from the new one.
First, you should always test your statements before making definate changes to your data. You could start a transaction and only commit when certain it went well or make a copy of your table (select * into x from y) and test on that.
To answer your question, try something like this;
WITH dataToUpdate AS(
SELECT RowNr ,
DATA,
DataFromPreviousRow = FIRST_VALUE(data) OVER (ORDER BY RowNr ROWS 1 PRECEDING)
FROM dbo.test
)
UPDATE dataToUpdate
SET data = dataToUpdate.DataFromPreviousRow;

Add Column values in sql server query

I have result of two queries like:
Result of query 1
ID Value
1 4
2 0
3 6
4 9
Result of query 2
ID Value
1 6
2 4
3 0
4 1
I want to add values column "Value" and show final result:
Result of Both queries
ID Value
1 10
2 4
3 6
4 10
plz guide me...
select id, sum(value) as value
from (
select id, value from query1
uninon all
select id, value from query2
) x
group by id
Try using a JOIN:
SELECT
T1.ID,
T1.Value + T2.Value AS Value
FROM (...query1...) AS T1
JOIN (...query2...) AS T2
ON T1.Id = T2.Id
You may also need to consider what should happen if there is an Id present in one result but not in the other. The current query will omit it from the results. You may want to investigate OUTER JOIN as an alternative.
A not particularly nice but fairly easy to comprehend way would be:
SELECT ID,SUM(Value) FROM
(
(SELECT IDColumn AS ID,ValueColumn AS Value FROM TableA) t1
OUTER JOIN
(SELECT IDColumn AS ID,ValueColumn AS Value FROM TableB) t2
) a GROUP BY a.ID
It has the benefits of
a) I don't know your actual table structure so you should be able to work out how to get the two 'SELECT's working from your original queries
b) If ID doesn't appear in either table, that's fine