SQLite: accumulator (sum) column in a SELECT statement - sql

I have a table like this one:
SELECT value FROM table;
value
1
3
13
1
5
I would like to add an accumulator column, so that I have this result:
value accumulated
1 1
3 4
13 17
1 18
5 23
How can I do this? What's the real name of what I want to do? Thanks

try this way:
select value,
(select sum(t2.value) from table t2 where t2.id <= t1.id ) as accumulated
from table t1
but if it will not work on your database, just add order by something
select value,
(select sum(t2.value) from table t2 where t2.id <= t1.id order by id ) as accumulated
from table t1
order by id
this works on an oracle ;) but it should on a sqlite too

Here's a method to create a running total without the inefficiency of summing all prior rows. (I know this question is 6 years old but it's one of the first google entries for sqlite running total.)
create table t1 (value integer, accumulated integer, id integer primary key);
insert into t1 (value) values (1);
insert into t1 (value) values (3);
insert into t1 (value) values (13);
insert into t1 (value) values (1);
insert into t1 (value) values (5);
UPDATE
t1
SET
accumulated = ifnull(
(
SELECT
ifnull(accumulated,0)
FROM
t1 ROWPRIOR
WHERE
ROWPRIOR.id = (t1.id -1 )),0) + value;
.headers on
select * from t1;
value|accumulated|id
1|1|1
3|4|2
13|17|3
1|18|4
5|23|5
This should only be run once after importing all the values. Or, set the accumulated column to all nulls before running again.

The operation is called a running sum. SQLite does not support it as is, but there are ways to make it work. One is just as Sebastian Brózda posted. Another I detailed here in another question.

Related

Insert multiple rows using SQL Merge statement when condition matched

Have Table with Non Identity Primary key. so whenever we insert new record we have to pass Primary key also.
I have to insert into the above table when record is not matched using Merge statement. But the problem is i could not increment the Primary key for each insert. it it throwing can not insert duplicate in Primary key column.
Please find the Sample Merge query below.
Is it possible to insert multiple rows by increment primary key.
MERGE DBO.Table1 T1
USING (DBO.Table2 )T2
ON (T1.ID = T2.ID)
WHEN MATCHED
THEN UPDATE SET
T1.CURVE = T2.CURVE
WHEN NOT MATCHED
THEN INSERT (ID, CURVE )
Values ( T2.ID, T2.CURVE);
The code in your example works, here's a demo easy to reproduce
;with cteT as ( SELECT * FROM (VALUES (1,'T1 Val 1') , (2,'T1 Val 2') , (4,'T1 Val 4') ) as T1(ID, Curve)
)SELECT * INTO #Dest FROM cteT
;with cteT as ( SELECT * FROM (VALUES (3,'T2 Val 3') , (4,'T2 Val 4') , (5,'T2 Val 5') ) as T1(ID, Curve)
)SELECT * INTO #Srce FROM cteT;
MERGE INTO #Dest as T1
USING #Srce as T2 ON T1.ID=T2.ID
WHEN MATCHED THEN UPDATE SET T1.Curve=T2.CURVE
WHEN NOT MATCHED BY TARGET
THEN INSERT (ID, Curve) VALUES(T2.ID, T2.Curve)
;
SELECT * FROM #Dest ORDER BY ID
DROP TABLE #Dest
DROP TABLE #Srce
This is the output, note that for 1 & 2 the value is unchanged, for 4 it's updated from T2, and for 3 and 5 it's inserted from T2.
ID Curve
1 T1 Val 1
2 T1 Val 2
3 T2 Val 3
4 T2 Val 4
5 T2 Val 5
This means that most likely either the problem is in your values for T2.ID or your sample is too pared down and misses a complication in your actual code. I'd start by checking your data in T2.ID
SELECT ID, COUNT(ID) as IDCount FROM DBO.Table2 GROUP BY ID HAVING COUNT(*) > 1
SELECT * FROM DBO.Table2 WHERE ID IS NULL
and see if any records turn up. If those are both empty, look at your actual merge code and see how it might differ from what you posted. If you post updated sample code I'll try to have a look.

Oracle -- Update the exact column referenced in the ON clause

I think this requirement is rarely encountered so I couldn't search for similar questions.
I have a table that needs to update the ID. For example ID 123 in table1 is actually supposed to be 456. I have a separate reference table built that stores the mapping (e.g. old 123 maps to new id 456).
I used the below query but apparently it returned error 38104, columns referenced in the ON clause cannot be updated.
MERGE INTO table1
USING ref_table ON (table1.ID = ref_table.ID_Old)
WHEN MATCHED THEN UPDATE SET table.ID = ref_table.ID_New;
Is there other way to achieve my purpose?
Thanks and much appreciated for your answer!
Use the ROWID pseudocolumn:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TABLE1( ID ) AS
SELECT 1 FROM DUAL UNION ALL
SELECT 2 FROM DUAL UNION ALL
SELECT 3 FROM DUAL;
CREATE TABLE REF_TABLE( ID_OLD, ID_NEW ) AS
SELECT 1, 4 FROM DUAL UNION ALL
SELECT 2, 5 FROM DUAL;
MERGE INTO TABLE1 dst
USING ( SELECT t.ROWID AS rid,
r.id_new
FROM TABLE1 t
INNER JOIN REF_TABLE r
ON ( t.id = r.id_old ) ) src
ON ( dst.ROWID = src.RID )
WHEN MATCHED THEN
UPDATE SET id = src.id_new;
Query 1:
SELECT * FROM table1
Results:
| ID |
|----|
| 4 |
| 5 |
| 3 |
You can't update a column used in the ON clause in a MERGE. But if you don't need to make other changes that MERGE allows like WHEN NOT MATCHED or deleting, etc. you can just use a UPDATE to achieve this.
You mentioned this is an ID that needs an update. Here's an example using a scalar subquery. As it is an ID, this presumes UNIQUE ID_OLD values in REF_TABLE. I wasn't sure if Every row needs an update or only a sub-set, so set the update here to only update rows that have a value in REF_TABLE.
CREATE TABLE TABLE1(
ID NUMBER
);
CREATE TABLE REF_TABLE(
ID_OLD NUMBER,
ID_NEW NUMBER
);
INSERT INTO TABLE1 VALUES (1);
INSERT INTO TABLE1 VALUES (2);
INSERT INTO TABLE1 VALUES (100);
INSERT INTO REF_TABLE VALUES (1,10);
INSERT INTO REF_TABLE VALUES (2,20);
Initial State:
SELECT * FROM TABLE1;
ID
1
2
100
Then make the UPDATE
UPDATE TABLE1
SET TABLE1.ID = (SELECT REF_TABLE.ID_NEW
FROM REF_TABLE
WHERE REF_TABLE.ID_OLD = ID)
WHERE TABLE1.ID IN (SELECT REF_TABLE.ID_OLD
FROM REF_TABLE);
2 rows updated.
And check the change:
SELECT * FROM TABLE1;
ID
10
20
100

duplicates removal in database [duplicate]

I am using postgres.
I want to delete Duplicate rows.
The condition is that , 1 copy from the set of duplicate rows would not be deleted.
i.e : if there are 5 duplicate records then 4 of them will be deleted.
Try the steps described in this article: Removing duplicates from a PostgreSQL database.
It describes a situation when you have to deal with huge amount of data which isn't possible to group by.
A simple solution would be this:
DELETE FROM foo
WHERE id NOT IN (SELECT min(id) --or max(id)
FROM foo
GROUP BY hash)
Where hash is something that gets duplicated.
delete from table
where not id in
(select max(id) from table group by [duplicate row])
This is random (max Value) choice which row you need to keep.
If you have aggre whit this please provide more details
The fastest is is join to the same table.
http://www.postgresql.org/docs/8.1/interactive/sql-delete.html
CREATE TABLE test(id INT,id2 INT);
CREATE TABLE
mapy=# INSERT INTO test VALUES(1,2);
INSERT 0 1
mapy=# INSERT INTO test VALUES(1,3);
INSERT 0 1
mapy=# INSERT INTO test VALUES(1,4);
INSERT 0 1
DELETE FROM test t1 USING test t2 WHERE t1.id=t2.id AND t1.id2<t2.id2;
DELETE 2
mapy=# SELECT * FROM test;
id | id2
----+-----
1 | 4
(1 row)
delete from table t1
where rowid > (SELECT min(rowid) FROM table t2 group by
t2.id,t2.name );
DELETE f1 from foo as f1, foo as f2
where f1.duplicate_column= f2.duplicate_column
AND f1.id > f2.id;

In Clause With Subquery In Oracle

I have two tables say table1 and table2 with below details
create table test1(id number, name varchar2(20));
insert into test1 values(11,'micro');
insert into test1 values(22,'soft');
create table test2(id number, name varchar2(20));
insert into test2 values(77,'micro,soft');
1) if I use below query I am getting no rows selectd
select * from test1 t1 where t1.name in ( select ''''||replace(t2.name,',',''',''')||'''' from test2;
2) if I fire subquery alone output I am getting is : 'micro','soft'
select ''''||replace(t2.name,',',''',''')||'''' from test2;
but if I fire query(1) I need the result
id name
------------
11 micro
22 soft
can some one please help me to get the same result with query (1).
You have a very strange data layout and should probably change it.
You can do what you want with a join or with a correlated subquery using like:
select *
from test1 t1
where exists (select 1
from test2 t2
where ','||t2.name||',' like '%,'||t1.name||',%'
);
You version doesn't work because the expression:
where x in ('a,b,c')
tests where x is equal to the string value 'a,b,c', not whether it is equal to one of the three values.
Use REGEXP_SUBSTR function to get this done.
SELECT *
FROM test1 t1
WHERE t1.NAME IN(SELECT regexp_substr(t2.NAME, '[^,]+', 1, ROWNUM)
FROM test2 t2
CONNECT BY LEVEL <= LENGTH (regexp_replace (t2.NAME, '[^,]+')) + 1
);

SQL query to get ID from multiple inputs

I'm not sure the title is clear, but this is the situation.
I have a table that looks like this:
ID inputID value
4 1 10
4 2 20
4 3 100
6 1 15
6 2 20
6 3 44
I have user input that gives me the values for inputID 1 and inputID 2, after which I want to get the ID to get the other information corresponding to that ID.
Example: If the user gives inputID(1)=10, inputID(2)=20, I want to get 4
Using simple AND statements don't solve this problem. I have asked already asked a few people, but I can't seem to solve this seemingly simple problem.
What about something like this?
SELECT t1.ID
FROM table t1
INNER JOIN table t2
ON t1.ID = t2.ID
WHERE
t1.inputID = 1 AND t1.value = #input1 AND
t2.inputID = 2 AND t2.value = #input2
select ID from T as T1
where inputID=1 and value=10
and EXISTS(select id from T where ID=T1.ID and inputID=2 and value=20)
Try this query:
Create Table #tmp ( Id int, inputId int, value int)
insert into #tmp values (4,1,10)
insert into #tmp values (4,2,20)
insert into #tmp values (4,3,100)
insert into #tmp values (6,1,15)
insert into #tmp values (6,2,20)
insert into #tmp values (6,3,44)
-- my query
Select top 1 id from
(Select id,count(id) as cnt from #tmp where (inputId=1 and value=10) OR (inputId=2 and value=20) Group by id) tbl
order by cnt desc
-- Scoregraphic's query
SELECT t1.ID
FROM #tmp t1
INNER JOIN #tmp t2
ON t1.ID = t2.ID
WHERE
t1.inputID = 1 AND t1.value = 10 AND
t2.inputID = 2 AND t2.value = 20
Drop table #tmp
On seeing the execution plan my query is takes overall 23% and ScoreGraphic's query takes 21%