insert thousands of rows in DB2 - sql

I need to multiply a certain row in a DB2 table 18000 times. Some of the column values will remain as the original and some need to be incremented by 1.
I have very little knowledge in DB2 and I just can't find a concrete simple answer on how to do this. Can someone please give me an example on how to achieve this?
DB2 version: 9.7 / OS: Windows 2k8
For example I have the following table:
T_RES_TABLE
Col1 |Col2|Col3 |Col4|
----------------------
1 | 1| 1| 1|
What I need to achieve is:
T_RES_TABLE
Col1 |Col2|Col3 |Col4|
----------------------
1 | 1| 1| 1| - original
----------------------
2 | 1| 2| 1|
----------------------
.
.
.
----------------------
18000| 1|18000| 1|
So Col1 and Col3 need to increment and the rest must stay as is. Hope it's clear enough.

You can use a recursive query to generate new column values:
$ db2 "create table t_res_table (col1 int, col2 int, col3 int, col4 int)"
DB20000I The SQL command completed successfully.
$ db2 "insert into t_res_table values (1,1,1,1)"
DB20000I The SQL command completed successfully.
$ db2 "select * from t_res_table"
COL1 COL2 COL3 COL4
----------- ----------- ----------- -----------
1 1 1 1
1 record(s) selected.
$ db2 "insert into t_res_table \
>with t (col1, col2, col3, col4, lvl) as ( \
>select col1, col2, col3, col4, 1 from t_res_table where col1 =1 \
>union all \
>select col1+1, col2, col3+1, col4, lvl+1 from t where lvl <18) \
>select col1, col2, col3, col4 from t where col1 > 1"
DB20000I The SQL command completed successfully.
$ db2 "select * from t_res_table"
COL1 COL2 COL3 COL4
----------- ----------- ----------- -----------
1 1 1 1
2 1 2 1
3 1 3 1
4 1 4 1
5 1 5 1
6 1 6 1
7 1 7 1
8 1 8 1
9 1 9 1
10 1 10 1
11 1 11 1
12 1 12 1
13 1 13 1
14 1 14 1
15 1 15 1
16 1 16 1
17 1 17 1
18 1 18 1
18 record(s) selected.

This will do your job. Just change it as your needs, change table name and column names and hit run.
I dont know what you want to achieve but, it sounds you just need an Dummy Data in a table. So, i just make it for dummy purpose.
Modify it for your another requirements. The example below contains everything what you need, but you may have to modify according to that.
DECLARE #I INT=0
SET #I=1
DECLARE #LASTF2 INT
DECLARE #LASTF4 INT
SELECT #LASTF2=ISNULL(MAX(F2),1) FROM TEST --JUST CHANGE TEST TO YOUR TABLENAME, AND F1,F2,F3,F4
SELECT #LASTF4=ISNULL(MAX(F4),1) FROM TEST -- AS YOUR FIELD NAMES
WHILE #I<10000
BEGIN
INSERT INTO TEST (F1,F2,F3,F4)
VALUES (#I,#LASTF2,#I,#LASTF4)
SET #I=#I+1
END
GO
SELECT * FROM TEST

Related

running sum with window function

I have the following data in a table:
col1
---
1
2
5
9
10
I want to update col2 in the table with the running sum of the difference between col1 and the previous value of col1 minus 1
col2 = col2.prev + col1 - col1.prev - 1
The result would be:
col1 | col2
--------------
1 | 0
2 | 0
5 | 2
9 | 5
10 | 5
I tried using a window function:
SELECT sum(col1 - lag(col1) OVER (ORDER BY col1) - 1) AS col2 FROM table1
But this is not allowed - ERROR: aggregate function calls cannot contain window function calls
Is there another way I can accomplish this? I know I could easily write a function to loop through the rows but I get the impression from what I've read that this method is not efficient and discouraged in most cases. Please correct me if I have the wrong impression.
ERROR: aggregate function calls cannot contain window function calls
This error message is displayed because it is not permitted to apply an aggregate function on a column generated through a windowed expression. Nor is it permitted to apply a second windowed expression. The solution is to simply wrap the result in a cte & apply the second windowed expression in a subsequent select statement.
WITH mytable(col1) AS (
VALUES (1), (2), (5), (9), (10)
)
, lagdiff AS (
SELECT
col1
, COALESCE(col1 - lag(col1) OVER (ORDER BY col1) - 1, 0) col2_
FROM mytable
)
SELECT
col1
, SUM(col2_) OVER (ORDER BY col1) col2
FROM lagdiff
Produces Output:
col1 | col2
------+------
1 | 0
2 | 0
5 | 2
9 | 5
10 | 5
(5 rows)

Update column value in all rows of a table on mod(rownum,10) = number

I have a table tab1 that looks like this:
col1 | col2 | col3
------|------|------
abc | 100 | text
abc | 100 | text
abc | 100 | text
... | ... | ...
I need to update col2 value in each row like this:
update tab1
set col2 = 1,23
when mod(rownum,10) = 1;
update tab1
set col2 = 12,34
when mod(rownum,10) = 2;
update tab1
set col2 = 123,45
when mod(rownum,10) = 3;
and etc. until when mod(rownum,10) = 9.
But obviously this query doesn't work, and the reason is that rownum always returns 1 in this situation, afaik. However, I've got the correct last digits for each row number with select mod(rownum,10) as lastDig from tab1 query. But I don't understand how to use the result of this select for my update when conditions.
Could you please provide an example of a query that will do the job in this situation? Do I need to use a subquery or select in a temporary table? Please explain. I'm a junior frontend guy, but I need to create a demo table this way. I believe, pl/sql is v10, as well as PL/SQL Developer.
Result wanted looks like this:
col1 | col2 | col3
------|-------|------
abc | 1.23 | text
abc | 12.34 | text
abc | 123.45| text
... | ... | ...
You could use CASE expression or DECODE:
update tab1
set col2 = CASE mod(rownum,10) WHEN 1 THEN 1.23
WHEN 2 THEN 12.34
WHEN 3 THEN 123.45
-- ...
ELSE col2
END
-- WHERE ...
UPDATE tab1
SET col2 = DECODE(mod(rownum,10), 1, 1.23, 2, 12.34, 3, 123.45, ..., col2)
-- WHERE ...;
DBFiddle Demo
You have not told us if there is a specific order in which you want to treat rows as 1,2,3 .. If there is indeed an order, then ROWNUM is unreliable and may not work, you would need row_number() with a specific order by column. That can be combined with a MERGE statement.
MERGE INTO tab1 tgt USING (
SELECT
CASE mod( ROW_NUMBER() OVER(
ORDER BY
col1 -- the column which is in order and unique
),10)
WHEN 1 THEN 1.23
WHEN 2 THEN 12.34
WHEN 3 THEN 123.45
--..
--.. 9
ELSE col2
AS col2
FROM
tab1 t
)
src ON ( tgt.rowid = src.rowid ) --use primary key/unique key if there is one instead of rowid
WHEN MATCHED THEN UPDATE SET tgt.col2 = src.col2;
Demo

Fill column from other data in row being inserted

I am trying to come up with a trigger that fills a column of a row that I insert/update with a score that depends on the the numeric values on other columns of that same row.
For example
+------+------+------+------+------+------+
| col1 | col2 | col3 | col4 | col5 | col6 |
+------+------+------+------+------+------+
| 1 | 2 | 1 | 3 | 1 | |
+------+------+------+------+------+------+
This is the row I want to insert, I would like to fill col6 with a score calculated using the values of the other columns
(100 - avg(col1:col5)/4*100)
Can I do this through a trigger or procedure? Should I do this before or after the insert?
From Oracle 11g you can use a virtual column:
Oracle Setup:
CREATE TABLE table_name (
col1 NUMBER,
col2 NUMBER,
col3 NUMBER,
col4 NUMBER,
col5 NUMBER,
col6 NUMBER GENERATED ALWAYS AS ( 100 - (col1+col2+col3+col4+col5)*5 ) VIRTUAL
);
INSERT INTO table_name ( col1, col2, col3, col4, col5 )
VALUES ( 1, 2, 1, 3, 1 );
Query:
SELECT * FROM table_name;
Output:
COL1 COL2 COL3 COL4 COL5 COL6
---- ---- ---- ---- ---- ----
1 2 1 3 1 60
A trigger would look like.
CREATE OR REPLACE TRIGGER ti
BEFORE UPDATE OR INSERT ON yourtable
FOR EACH ROW
BEGIN
:new.col6 :=
( 100
- (:new.col1 + :new.col2 + :new.col3 + :new.col4 + :new.col5)/ 5 * 100);
end;
I did it this way to avoid the possible null values that might exist. Thank you all for the precious help.
create or replace TRIGGER SCORE_SYMP_TRG
BEFORE INSERT OR UPDATE ON KOOS
FOR EACH ROW
DECLARE
BEGIN
:NEW.SCORE_SYMP := 100 - ROUND(((NVL(:NEW.S1,0) + NVL(:NEW.S2,0) + NVL(:NEW.S3,0) + NVL(:NEW.S4,0) + NVL(:NEW.S5,0) + NVL(:NEW.R6, 0) + NVL(:NEW.R7, 0))/(
NVL((NVL(:NEW.S1,0)/NVL(:NEW.S1,1)),0) + NVL((NVL(:NEW.S2,0)/NVL(:NEW.S2,1)),0) + NVL((NVL(:NEW.S3,0)/NVL(:NEW.S3,1)),0) + NVL((NVL(:NEW.S4,0)/NVL(:NEW.S4,1)),0)
+ NVL((NVL(:NEW.S5,0)/NVL(:NEW.S5,1)),0) + NVL((NVL(:NEW.R6,0)/NVL(:NEW.R6,1)),0) + NVL((NVL(:NEW.R7,0)/NVL(:NEW.R7,1)),0)) /4)*100,0);
END;

Comparing with LAG Analytic function

I am using oracle PL/SQL.
I am trying to compare column values with LAG function.
Following is the statement:
decode(LAG(col1,1) OVER (ORDER BY col3),col1,'No Change','Change_Occured') Changes
As for first row, LAG will always compare with the previous empty row. So for my query the first row of column 'Changes' is always showing the value as Change_Occured when in fact no change has happened. Is there any way to handle this scenario ?
Assume this table:
| col1 | col2 |
| 2 | 3 |
| 2 | 6 |
| 2 | 7 |
| 2 | 9 |
Each row of col1 is compared with previous value so result will be
| col1 | col2 | Changes |
| 2 | 3 | Change_occured |
| 2 | 9 | No Change |
| 2 | 5 | No Change |
| 2 | 8 | No Change |
So how should I handle the first row of column Changes
The syntax for LAG Analytic function is:
LAG (value_expression [,offset] [,default]) OVER ([query_partition_clause] order_by_clause)
default - The value returned if the offset is outside the scope of the window. The default value is NULL.
SQL> WITH sample_data AS(
2 SELECT 2 col1, 3 col2 FROM dual UNION ALL
3 SELECT 2 col1, 6 col2 FROM dual UNION ALL
4 SELECT 2 col1, 7 col2 FROM dual UNION ALL
5 SELECT 2 col1, 9 col2 FROM dual
6 )
7 -- end of sample_data mimicking real table
8 SELECT col1, LAG(col1,1) OVER (ORDER BY col2) changes FROM sample_data;
COL1 CHANGES
---------- ----------
2
2 2
2 2
2 2
Therefore, in the DECODE expression you are comparing the NULL value with a real value and it is evaluated as Change_Occurred
You could use the default value as the column value itself:
DECODE(LAG(col1,1, col1) OVER (ORDER BY col2),col1,'No Change','Change_Occured') Changes
For example,
SQL> WITH sample_data AS(
2 SELECT 2 col1, 3 col2 FROM dual UNION ALL
3 SELECT 2 col1, 6 col2 FROM dual UNION ALL
4 SELECT 2 col1, 7 col2 FROM dual UNION ALL
5 SELECT 2 col1, 9 col2 FROM dual
6 )
7 -- end of sample_data mimicking real table
8 SELECT col1,
9 DECODE(
10 LAG(col1,1, col1) OVER (ORDER BY col2),
11 col1,
12 'No Change',
13 'Change_Occured'
14 ) Changes
15 FROM sample_data;
COL1 CHANGES
---------- --------------
2 No Change
2 No Change
2 No Change
2 No Change
SQL>
May be:
decode(LAG(col1,1, col1) OVER (ORDER BY col3),col1,'No Change','Change_Occured') Changes
The optional default value is returned if the offset goes beyond the scope of the window. If you do not specify default, then its default is null.

Oracle column number increase

I would like to know how to increase the row number by 1 in Column 1 when Column 2 value changes in Oracle
What I am looking for is to achieve this :
COL1 COL2 COL3 |
1 2000 xx |
1 2000 xy |
1 2000 xyz |
2 3020 x |
2 3020 xiii |
3 5666666 ueueu
Any idea ?
I think you are looking for a window function:
select row_number() over (partition by col2 order by col3) as col1,
col2,
col3
from the_table;
If you want to increase col1 value after updating col2 on table t_ then you can use trigger.
CREATE OR REPLACE TRIGGER upcol1
AFTER UPDATE ON t_ FOR EACH ROW
WHEN (old.col2 != new.col2)
BEGIN
UPDATE t_ SET col1=:new.col1+1
WHERE col2=:new.col2 AND col3=:new.col3;
END;