How to sum amounts according their ID-s - sql

I have a database with 2 tables in SQL Server 2008 Express.
My problem is the following: I would like to create a trigger to sum some values in first table and copy the sum into second one.
For example the first table (Head) has 5 columns :
ID Transaction Acount Date Total_sum
1 some text acount1 2014.04.15 300
2 some text acount2 2014.04.15 500
3 some text acount1 2014.04.15 200
And the second table Transaction:
HeadID Amount Remarks
1 100 test1
1 200 test2
2 500 test3
3 100 test3
3 100 test4
So finally I would like to sum the values in Transaction if they have the same HeadID and copy the result into the Head table. (Total_sum column).Maybe first Could I find the last ID in the 'Head' table and group HeadID-s in the 'Transaction' table and sum the values
Please help me!

You can UPDATE table using JOIN
UPDATE h
SET h.Total_sum = t.sumTotal
FROM Head h
INNER JOIN
(
SELECT HeadID,SUM(Amount) as sumTotal
FROM [Transaction]
GROUP BY HeadID
) t
ON h.ID=t.HeadID

perhaps the following:
create trigger TransactionInsertUpdateDelete
on Transaction
for insert, update, delete
as
begin
update H
set Total_sum =
-- set the total sum to the sum of all records for this head id in transaction
(select sum(Amount)
from Transaction as T
where T.HeadID = H.HeadID
)
from Head as H
join -- join on the inserted and deleted tables to find out which HeadID's were affected.
(select HeadID
from inserted
union
select HeadID
from deleted
) as C
on C.HeadID = H.HeadID
end
go

Maybe can try like this ?
UPDATE Head h
SET h.Total_sum=(SELECT SUM(t.Amount) FROM Transaction t
Where t.HeadID = t.HeadID
GROUP BY t.HeadID)
WHERE h.ID= t.HeadID

you could achive it without using join:
UPDATE tansaction_table
SET Total_sum = (SELECT SUM(t2.Amount)
FROM head_table t2
WHERE t2.HeadID = ID)

Related

delete data based on sum of values

Hi I would like to ask if it possible to delete some data based on sum in big query.
Here is the problem I would like to delete only rows which has sum over 100. I try to use:
DELETE FROM (SELECT user, sum(paid) as money FROM test) where money > 100
but it didn't work then I try use:
with table2 as (SELECT a.*, sum(paid) as money from `test` a)
DELETE from table2 where table2.money > 100
it also didn't work
id
login
paid
1
john
99
1
john
2
2
josh
50
3
mark
800
and the result should be only 1 row here.
Try below SQL to delete data from test where sum(paid) > 100.
Once it executed, perform select on test table to see the result.
delete from `test`
where id in (select distinct id
from `test`
group by id
having sum(paid) > 100)

SQL aggregate rows with same id , specific value in secondary column

I'm looking to filter out rows in the database (PostgreSQL) if one of the values in the status column occurs. The idea is to sum the amount column if the unique reference only has a status equals to 1. The query should not SELECT the reference at all if it has also a status of 2 or any other status for that matter. status refers to the state of the transaction.
Current data table:
reference | amount | status
1 100 1
2 120 1
2 -120 2
3 200 1
3 -200 2
4 450 1
Result:
amount | status
550 1
I've simplified the data example but I think it gives a good idea of what I'm looking for.
I'm unsuccessful in selecting only references that only have status 1.
I've tried sub-queries, using the HAVING clause and other methods without success.
Thanks
Here's a way using not exists to sum all rows where the status is 1 and other rows with the same reference and a non 1 status do not exist.
select sum(amount) from mytable t1
where status = 1
and not exists (
select 1 from mytable t2
where t2.reference = t1.reference
and t2.status <> 1
)
SELECT SUM(amount)
FROM table
WHERE reference NOT IN (
SELECT reference
FROM table
WHERE status<>1
)
The subquery SELECTs all references that must be excluded, then the main query sums everything except them
select sum (amount) as amount
from (
select sum(amount) as amount
from t
group by reference
having not bool_or(status <> 1)
) s;
amount
--------
550
You could use windowed functions to count occurences of status different than 1 per each group:
SELECT SUM(amount) AS amount
FROM (SELECT *,COUNT(*) FILTER(WHERE status<>1) OVER(PARTITION BY reference) cnt
FROM tc) AS sub
WHERE cnt = 0;
Rextester Demo

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;

Update with results of another sql

With the sql below I count how many records I have in tableB for each code. The total field is assigned the result of the count and the code the code field of the record.
SELECT
"count" (*) as total,
tableB."code" as code
FROM
tableB
WHERE
tableB.code LIKE '%1'
GROUP BY
tableB.code
In tableA I have a sequence field and I update with the result of total (obtained in the previous sql) plus 1 Do this for each code.
I tried this and it did not work, can someone help me?
UPDATE tableA
SET tableA.sequence = (tableB.total + 1) where tableA."code" = tableB.code
FROM
(
SELECT
"count" (*) as total,
tableB."code" as code
FROM
tableB
WHERE
tableB.code LIKE '%1'
GROUP BY
tableB.code
)
I edited for my tables are as mostar believe facillita understanding of my need
tableA
code sequence
100 null
200 null
table B
code sequence
100 1
100 2
100 3
100 4
......
100 17
200 1
200 2
200 3
200 4
......
200 23
Need to update the sequence blank field in tableA with the number 18 to code = 100
Need to update the sequence blank field in tableA with the number 24 to code = 200
This assumes that code is unique in table_a:
with max_seq as (
select code,
max(sequence) + 1 as max_seq
from table_b
group by code
)
update table_a
set sequence = ms.max_seq
from max_seq ms
where table_a.code = ms.code;
SQLFiddle example: http://sqlfiddle.com/#!15/745a7/1
UPDATE tbl_a a
SET sequence = b.next_seq
FROM (
SELECT code, max(sequence) + 1 AS next_seq
FROM tbl_b
GROUP BY code
) b
WHERE a.code = b.code;
SQL Fiddle.
Only columns of the target table can be updated. It would not make sense to table-qualify those. Consequently, this is not allowed.
Every subquery must have a table alias for the derived table.
I would not use a CTE for a simple UPDATE like this. A subquery in the FROM clause is typically simpler and faster.
No point in double-quoting the aggregate function count(). No pint in double-quoting perfectly legal, lower case identifiers, either. No point in table-qualifying columns in a subquery on a single table in a plain SQL command (no harm either).
You don't need a WHERE condition, since you want to UPDATE all rows (as it seems). Note that only row with matching code are updated. Other rows in tbl_b remain untouched.
Basically you need to read the manual about UPDATE before you try any of this.

Help for a Sql statement

Hy at all, today is the day of ...question.
I've a single table, with a relation master-detail like this:
RecordID MasterID Field1 Field2 .... NrDetail
1 0 xxx yyyy 1
2 0 aaaa bbbb 2
3 1 hhhhh ssss 0
4 2 eee sssss 0
5 2 jjj hhhh 0
As you can see, NrDetail contain the total of "child record".
Unfortunately, i've to create this field... and i would like to write it in my table.
So my SQL question is: how to do this type of SQL to write the field NrDetail ?
Something like:
UPDATE table SET NrDetail=
(SELECT COUNT(*) as Total FROM table WHERE MasterID= RecordID)
But i think there's some mistake...
Thank you in advance !
I think that you have forgetten to specify which MasterID you want to compare with which RecordID.
How about:
UPDATE table t1 SET NrDetail=
(SELECT COUNT(*) as Total FROM table t2 WHERE t1.MasterID=t2.RecordID)
UPDATE table
SET NrDetail = (
Select Count(*)
FROM table t2
Where t2.RecordID = table.MasterID
)
In an update statement, when you want to reference the table being updated, you need to use the full reference for columns(tablename.columnname, or ideally schema.tablename.columnname). If you are using the same table in a subquery, you need to alias the table in the subquery but again use the full reference for the outer table.
ADDITION Since you mentioned that you are using MySql, you could try something like so:
Update post
Join (
Select p1.idpadre, Count(*) Total
From post p1
Group By p1.idpadre
) Z
On Z.idpadre = post.idpost
Set post.NrDetail = Z.Total