Left only MAX value per group - sql

I have got table like this:
TransactionID
…
Cost
MaxCostPerGroup
1234
...
1550
1550
2342
...
1950
2000
2342
...
2000
2000
4444
...
600
600
4444
...
400
600
4444
...
500
600
TransactionID – not unique
… - a lot of columns (30+)
Cost – could be different to one TransactionID
MaxCostPerGroup column shows max value for each TransactionID.
To continue working with data I need to bring table to the following form:
TransactionID
…
Cost
MaxCostPerGroup
1234
...
1550
1550
2342
...
1950
null
2342
...
2000
2000
4444
...
600
600
4444
...
400
null
4444
...
500
null
Then I want to sum MaxCostPerGroup by date (for example). Problem is that I must save every row, I cannot just group by. In ‘…’ section a lot of unique information, that is why I want to left only one value per TransactionID in last column. How can I do it with SQL?
Many thanks.

Using your data, I got the max value by partitioning by TransactionId and adding a IF statement to add NULLs.
See query below:
WITH sample_data as(
select '1234' as TransactionID, 1550 as Cost, 1550 as MaxCostPerGroup,
union all select '2342' as TransactionID, 1950 as Cost, 2000 as MaxCostPerGroup,
union all select '2342' as TransactionID, 2000 as Cost, 2000 as MaxCostPerGroup,
union all select '4444' as TransactionID, 600 as Cost, 600 as MaxCostPerGroup,
union all select '4444' as TransactionID, 400 as Cost, 600 as MaxCostPerGroup,
union all select '4444' as TransactionID, 500 as Cost, 600 as MaxCostPerGroup
),
get_max as (
select TransactionId,
Cost,
max(MaxCostPerGroup) OVER (PARTITION BY TransactionId) as max_per_id
from sample_data
),
add_null as (
select TransactionId,
Cost,
max_per_id,
if (Cost = max_per_id, max_per_id, NULL) as MaxCostPerGroup
from get_max
)
select TransactionId,Cost,MaxCostPerGroup from add_null
Output:

Related

SQL DB2 Toad - Sum from two tables by ID

I was hoping to find the sum from two tables with columns ID and Amount, grouping by ID.
My first attempt was to UNION the two tables first and then conduct a sum and group by, but I was hoping to know of a better way.
Inputs:
Table 1
ID Amount
123 100
123 100
145 500
167 600
Table 2
ID Amount
123 100
123 100
145 500
199 600
Output
ID Amount
123 400
145 1000
167 600
199 600
You can do:
select id, sum(amount) as amount
from (
select id, amount from table_1
union all
select id, amount from table_2
) x
group by id

Dividing a sum value into multiple rows due to field length constraint

I am migrating financial data from a very large table (100 million+ of rows) by summarizing the amount and insert them into summary table. I ran into problem when the summary amount (3 billions) is larger than what the field in the summary table can hold (can only hold up to 999 millions.) Changing the field size is not an option as it requires a change process.
The only option I have is to divide the amount (the one that breach the size limit) into smaller ones so it can be inserted into the table.
I came across this SQL - I need to divide a total value into multiple rows in another table which is similar except the number of rows I need to insert is dynamic.
For simplicity, this is how the source table might look like
account_table
acct_num | amt
-------------------------------
101 125.00
101 550.00
101 650.00
101 375.00
101 475.00
102 15.00
103 325.00
103 875.00
104 200.00
104 275.00
The summary records are as follows
select acct_num, sum(amt)
from account_table
group by acct_num
Account Summary
acct_num | amt
-------------------------------
101 2175.00
102 15.00
103 1200.00
104 475.00
Assuming the maximum value in the destination table is 1000.00, the expected output will be
summary_table
acct_num | amt
-------------------------------
101 1000.00
101 1000.00
101 175.00
102 15.00
103 1000.00
103 200.00
104 475.00
How do I create a query to get the expected result? Thanks in advance.
You need a numbers table. If you have a handful of values, you can define it manually. Otherwise, you might have one on hand or use a similar logic:
with n as (
select (rownum - 1) as n
from account_table
where rownum <= 10
),
a as (
select acct_num, sum(amt) as amt
from account_table
group by acct_num
)
select acct_num,
(case when (n.n + 1) * 1000 < amt then 1000
else amt - n.n * 1000
end) as amt
from a join
n
on n.n * 1000 < amt ;
A variation along these lines might give some ideas (using the 1,000 of your sample data):
WITH summary AS (
SELECT acct_num
,TRUNC(SUM(amt) / 1000) AS times
,MOD(SUM(amt), 1000) AS remainder
FROM account_table
GROUP BY acct_num
), x(acct_num, times, remainder) AS (
SELECT acct_num, times, remainder
FROM summary
UNION ALL
SELECT s.acct_num, x.times - 1, s.remainder
FROM summary s
,x
WHERE s.acct_num = x.acct_num
AND x.times > 0
)
SELECT acct_num
,CASE WHEN times = 0 THEN remainder ELSE 1000 END AS amt
FROM x
ORDER BY acct_num, amt DESC
The idea is to first build a summary table with div and modulo:
ACCT_NUM TIMES REMAINDER
101 2 175
102 0 15
103 1 200
104 0 475
Then perform a hierarchical query on the summary table based on the number of "times" (i.e. rows) you want, with an extra for the remainder.
ACCT_NUM AMT
101 1000
101 1000
101 175
102 15
103 1000
103 200
104 475

MS-Access : How to sum multiple values from different tables according to dates

I have two similar tables as follows
Table 1
Date Amount Tax
4/1/2016 1000 100
4/1/2016 2000 200
5/3/2016 1500 150
5/6/2016 1000 100
5/6/2016 3000 300
7/9/2016 2500 250
Table 2
Date Amount Tax
4/1/2016 1000 100
4/2/2016 3000 300
5/3/2016 1500 150
5/9/2016 4000 400
8/11/2016 3000 300
10/9/2016 2000 200
dates can be similar or different in both tables.
I want two queries.
First, a query which gives me sum of amount and tax from each date from both tables between required dates. Eg: Table 1 have 2 entries and table 2 have 1 entry for 4/1/2016. so the result should be as below (summing up all three entries)
Date Amount Tax
4/1/2016 4000 400
4/2/2016 3000 300
5/3/2016 3000 300
5/6/2016 4000 400
5/9/2016 4000 400
7/9/2016 2500 250
8/11/2016 3000 300
10/9/2016 2000 200
Second,a query which gives of sum of amount and tax for each month from both tables between required dates. Eg output as below
Date Amount Tax
4/2016 4000 400
5/2016 11000 1100
7/2016 2500 250
8/2016 3000 300
10/2016 2000 200
Query that have I have written till now( not working )
SELECT date, sum(Amount),sum(Tax)
From Table1
WHERE Date BETWEEN #04/01/2016# AND #12/31/2016#
UNION ALL
SELECT date, sum(Amount),sum(Tax)
From Table2
WHERE Date BETWEEN #04/01/2016# AND #12/31/2016#
GROUP BY Date
For first query, consider a union query derived table with outer query aggregation:
SELECT q1.[Date], SUM(q1.Amount) AS DayTotalAmt, SUM(q1.Tax) AS DayTotalTax
FROM
(SELECT [Date], Amount, Tax
FROM Table1
UNION ALL
SELECT [Date], Amount, Tax
FROM Table2
) AS q1
GROUP BY q1.[Date]
For second query, consider using first query as a source with another outer query layer that runs a WHERE filter with month/year aggregation:
SELECT Format(q2.Date, "M/YYYY"), SUM(q2.DayTotalAmt) AS MonthTotalAmt,
SUM(q2.DayTotalTax) AS MonthTotalTax
FROM
(SELECT q1.[Date], SUM(q1.Amount) AS DayTotalAmt, SUM(q1.Tax) AS DayTotalTax
FROM
(SELECT [Date], Amount, Tax
FROM Table1
UNION ALL
SELECT [Date], Amount, Tax
FROM Table2) AS q1
GROUP BY q1.[Date]
) AS q2
WHERE q2.Date BETWEEN CDate("4/1/2016") AND CDate("12/31/2016")
GROUP BY Format(q2.Date, "M/YYYY")
Or if you save first query:
SELECT Format(q.Date, "M/YYYY"), SUM(q.DayTotalAmt) AS MonthTotalAmt,
SUM(q.DayTotalTax) AS MonthTotalTax
FROM Query1 q
WHERE q.Date BETWEEN CDate("4/1/2016") AND CDate("12/31/2016")
GROUP BY Format(q.Date, "M/YYYY")

How to add summary rows to income statements in postgresql

Income statement table has structure:
sgroup char(30),
account char(10),
jan numeric(12,2),
feb numeric(12,2)
and has values:
SGroup Account Jan Feb
Sales 311 100 200
Sales 312 20 30
..
Other 410 3333 44
Other 411 333 344
...
How convert this table to have header and subtotals for each group:
Caption Jan Feb
Sales
311 100 200
312 20 30
Sales Total 120 230
Other
410 3333 44
411 333 344
Other total 3666 388
... ... ...
Grand Total ... ...
Caption column should contain group header, account numbers and group total for each group.
After total there should be empty row.
After that that there should be next group etc.
In the end there should be a "Grand Total" row containing the sum of all rows.
Using Postgres 9.1.2 in Debian.
Mono C# ASP.NET MVC application running in Debian. If it's more reasonable, this conversion can done in MVC controller also.
I would calculate sums per group in a CTE to use it three times in the main query:
WITH total AS (
SELECT sgroup, 'Sales Total'::text AS c, sum(jan) AS j, sum(feb) AS f
FROM income_statement
GROUP BY 1
)
( -- parens required
SELECT caption, jan, feb
FROM (
SELECT 1 AS rnk, sgroup, account::text AS caption, jan, feb
FROM income_statement
UNION ALL
SELECT 0 AS rnk, sgroup, sgroup::text, NULL, NULL FROM total
UNION ALL
SELECT 2 AS rnk, * FROM total
) sub
ORDER BY sgroup, rnk
)
UNION ALL
SELECT 'Grand Total', sum(j), sum(f) FROM total;
The extra set of parentheses is required to include ORDER BY.
You probably don't want to use the data type char(30):
Any downsides of using data type "text" for storing strings?

New column with rowtotals

I'm having some trouble to achieve the folowing result.
This is my current table:
ID NR COST
1 7001 100
2 7001 50
3 7020 800
4 7020 190
5 7050 205
6 7050 80
And this is the table I want to achieve:
ID NR COST TOTAL
1 7001 100 150
2 7001 50 150
3 7020 800 990
4 7020 190 990
5 7050 205 285
6 7050 80 285
So I want to create an extra column, where the sum of the same 'NR' column is.
I have tried working with SUM, but then the whole sum of the cost column is taken.
This is my current query:
SELECT distinct id, nr, cost, sum(cost) as total
FROM customers
group by id, nr, cost
You can use a subquery to calculate the total for each NR and then just add it to the original result:
SELECT id,
nr,
cost,
A.subtotal AS TOTAL
FROM table1
INNER JOIN (SELECT nr,
Sum(cost) AS subTotal
FROM table1
GROUP BY nr) AS A
ON table1.nr = A.nr
You can self join with an aggregate query:
SELECT id, mytalbe.nr, cost, total
FORM mytable
JOIN ON (SELECT nr, SUM(cost) AS total
FROM mytable
GROUP BY nr) t ON t.nr = mytable.nr