I have a table with 1 row and 2 columns: col1 and col2,
--------------------------------------------------
| col1 | col2 |
--------------------------------------------------
| 1 | 2 |
--------------------------------------------------
now I want to update the row record:
db2 "update myschema.mytable set col1=3, col2=col1"
I expect the result to be col1=3 and col2=3, but it gives me col1=3,col2=1
how do I update one column base on a newly updated column?
Try This:
DECLARE #A INT
SELECT #A = Col1 FROM Mytable
UPDATE MyTable SET Col1 = 4, Col2 = #A
Related
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
I have requirement to update column value of two rows with different keys. Constraint is that i want to do this in single query.
For example:
Coll1 Coll2
---------------
A 1
B 2
C 3
Should be like
Coll1 Coll2
--------------
A 3
B 2
C 1
using a case expression:
update t
set Coll2 = case when Coll1 = 'A' then 3 else 1 end
where Coll1 in ('A','C')
rextester demo: http://rextester.com/HUBDAP9516
returns:
+-------+-------+
| Coll1 | Coll2 |
+-------+-------+
| A | 3 |
| B | 2 |
| C | 1 |
+-------+-------+
update for a parameterized version:
declare #key1 char(1) = 'A';
declare #key2 char(1) = 'C';
update t
set t.Coll2 = x.Coll2
from t
inner join t x
on t.Coll1 <> x.Coll1
and t.Coll1 in (#key1,#key2)
and x.Coll1 in (#key1,#key2)
rextester demo: http://rextester.com/PKQSAV63963
returns:
+-------+-------+
| Coll1 | Coll2 |
+-------+-------+
| A | 3 |
| B | 2 |
| C | 1 |
+-------+-------+
Perhaps you mean a single transaction. Either way, I don't understand why--but since that is what you want, here's an easy way.
declare #table table (Col1 char(1), Col2 int)
insert into #table
values
('A',1),
('B',2),
('C',3)
update #table
set
Col2 = case
when Col1 = 'A' then 3
when Col1 = 'C' then 1
end
where Col1 in ('A','C')
select * from #table
BEGIN TRANSACTION
UPDATE t SET Coll2 = 3 WHERE Coll1 = 'A'
UPDATE t SET Coll2 = 1 WHERE Coll1 = 'C'
COMMIT
I'd like to try the following answer without hard-code col2
create table #t (col1 char(301), col2 int);
go
insert into #t (col1, col2)
values ('A', 1), ('B', 2), ('C', 3)
; with c as (
select col1, col2
from #t
)
update t
set t.col2 = c.col2
from #t t
inner join c
on abs(ascii(t.col1) - ascii(c.col1))=2
select * from #t
This is a generic solution where you have values to switch as a parameter or as a subquery.
It also works con char data, but need some tweaking on string manipulation.
declare #table table (Col1 char(1), Col2 int)
insert into #table
values
('A',1),
('B',2),
('C',3)
declare #swap1 char='A'
declare #swap2 char='C'
update #table
set col2 = (select sum(col2) from #table
where col1 in (#swap1,#swap2))-col2
where col1 in (#swap1,#swap2)
Table1
COL1 | COL2
1 | 2
1 | 2
Table2
COL1 | COL2 | EDIT | FLAG
1 | 2 | N | 0
1 | 2 | N | 0
--Deleting from Table2
Table2
COL1 | COL2 | EDIT | FLAG
1 | 2 | D | 1 --Delete this row
1 | 2 | N | 0
--Trigger executing
Table1
COL1 | COL2
1 | 2 --Trigger deleting same row as in Table1
1 | 2
I have 2 identical tables (except for the part that the second Table has the EDIT and FLAG columns that the trigger should use). I wanted to make a trigger that if i change the N to D in Table2 and FLAG from 0 to 1, trigger will look at EDIT see it is D and delete the row in Table2 and the same row in Table1. Or maybe i would insert values in Table2 (3,3,'I',1) the trigger would look at EDIT see insert and make an insert value (3,3) into Table1.
I was trying this some time now, I failed miserably. Any ideas how to accomplish that.
Cheers
create trigger delete_trigger on table2
for update,insert as
if exists(select * from inserted where edit = 'I' and flag = 1)
begin
insert into table1 (col1, col2) select col1,col2 from inserted
end
else if exists(select * from inserted) and exists(select * from table2 where edit = 'D' and flag = 1)
begin
delete table 2 select * from table2 where edit = 'D' and flag = 1
delete table1 select t.* from table1 t left join table2 wt on t.id = wt.id where wt.col1 is null and wt.col2 is null --delete
end
This is the answer i figured it out myself. For future reference, maybe it can help others. And tip for the user SpectralGhost, if someone makes an example like the one i did above, and you dont understand it and cant write a simple example of how the code should look like or try to put someone on the right way, pls do not comment anything, it is not helpful.
This trigger would work for your specifications, but you did not define the handling for deleting rows in Table2 and the behavior for changing values in Col1 or Col2 with Edit=I and Flag=1 will lead to new inserts in Table1, you will have to decide if this is your intention or not.
CREATE TRIGGER [dbo].[tr_insUp_Table2]
ON [dbo].[Table2]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
Insert into Table1 Select i.Col1,i.Col2
from Inserted i
LEFT JOIN Table1 t2 on t2.Col1=i.Col1 and t2.Col2=i.Col2
where i.Edit='I' and i.Flag=1 and t2.Col1 IS NULL
Delete Table1 // if you want to
From inserted i where Table1.Col1=i.Col1 and Table1.Col2=i.Col2 and i.Edit='D' and i.Flag=1
Delete Table2
From inserted i where Table2.Col1=i.Col1 and Table2.Col2=i.Col2 and i.Edit='D' and i.Flag=1
END
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;
Is there any way to map the first table to the second table with an SQL query or, if too complicated, a PL/SQL block?
Original
--------------------------------------
| col1 | col2 | col3 | col4 |
--------------------------------------
| key | case 1 | case 2 | case 3 |
| value1 | v1c1 | v1c2 | v1c3 |
| value2 | v2c1 | v2c2 | v2c3 |
--------------------------------------
Target
-----------------------------
| key | case | result |
-----------------------------
| value1 | case 1 | v1c1 |
| value1 | case 2 | v1c2 |
| value1 | case 3 | v1c3 |
| value2 | case 1 | v2c1 |
| value2 | case 2 | v2c2 |
| value2 | case 3 | v2c3 |
-----------------------------
The original table can have a variable number of columns, and 'key' is a hardcoded string and is always in column 1 of the original table. No other row has “key” in column 1, so this row is a unique pivot.
Thank you
If dynamic sql is allowed, then it is possible to have all your requirements fullfilled using one query:
SELECT col1 as "key"
,extractvalue(dbms_xmlgen.getXMLType('select "' || tc.Column_Name ||
'" as v from Original where col1 = ''key''')
,'/ROWSET/ROW/V') "case"
,extractvalue(dbms_xmlgen.getXMLType('select "' || tc.Column_Name ||
'" as v from Original where col1 = ''' ||
replace(col1, '''', '''''') || '''')
,'/ROWSET/ROW/V') "result"
FROM Original
,(SELECT Column_Name
FROM All_Tab_Columns tc
WHERE tc.Owner = 'YOURSCHEMA'
and tc.Table_Name = 'ORIGINAL'
and Column_Name != 'COL1'
ORDER BY tc.COLUMN_ID) tc
WHERE col1 != 'key'
ORDER BY "key"
,"case"
Some more details as requested:
dbms_xmlgen.getXMLType returns an XmlType instance which is basically the result of the supplied query string as XML.
The format is ROWSET for the root node and ROW for each row. Every column will be an element as well.
The 2 selects that I am creating are only returning one value and to makes things easier, I gave them a column alias "V" so that I know which value to pick from the XML.
extractValue is a function that returns the result of an XPath expression from an XmlType.
'/ROWSET/ROW/V' returns the first V node, from the first ROW node that resides under the root node ROWSET.
<ROWSET><ROW><V>Abc</V></ROW></ROWSET>
The original table can have a variable
number of columns
Really?
The straightforward way is to select and union the parts you want.
select col1 as key, 'case1' as case, col2 as result
from test
where col1 <> 'key'
union all
select col1 as key, 'case2' as case, col3 as result
from test
where col1 <> 'key'
union all
select col1 as key, 'case3' as case, col4 as result
from test
where col1 <> 'key'
Straightforward, but not dynamic.
Later . . .
Based on your comment . . . although I don't think it's necessary.
select col1 as key, (select col2 from test where col1='key') as case, col2 as result
from test
where col1 <> 'key'
union all
select col1 as key, (select col3 from test where col1='key') as case, col3 as result
from test
where col1 <> 'key'
union all
select col1 as key, (select col4 from test where col1='key') as case, col4 as result
from test
where col1 <> 'key'
Oracle 11 also supports UNPIVOT, which I haven't used.
I don't know which parts can change, but this should be a start for you. If the column names can change (key, case 1, etc.) you will have to have another query to get the correct column names. If you have questions feel free to ask:
declare
v_query VARCHAR2(5000);
v_case VARCHAR2(255);
v_colcount PLS_INTEGER;
begin
-- Get number of columns
select count(*)
INTO v_colcount
from user_tab_columns
where table_name = 'T1';
-- Build case statement to get correct value for result column
v_case := 'case';
for i in 1 .. v_colcount-1
loop
v_case := v_case||' when rn = '||to_char(i)||' then col'||to_char(i+1);
end loop;
v_case := v_case||' end result';
-- Build final query
v_query := 'select col1 key, ''case ''||rn case, '||v_case||'
from t1
cross join (
select rownum rn
from dual
connect by level <= '||to_char(v_colcount-1)||'
) cj
where col1 <> ''key''
order by key, case';
-- Display query (would probably be replaced with an insert using execute immediate)
dbms_output.put_line(v_query);
end;
This produces the following query (which assumes your original table is called t1):
select col1 key, 'case '||rn case, case when rn = 1 then col2 when rn = 2 then col3 when rn = 3 then col4 end result
from t1
cross join (
select rownum rn
from dual
connect by level <= 3
) cj
where col1 <> 'key'
order by key, case
Try this:
with data as
(select level l from dual connect by level <= 3)
select col1,
'case' || l as "case",
decode(l,1,col2,2,col3,3,col4) as "values"
from myTable, data
order by 1,2;
Cheers