Related
I am trying to copy value from our old db to new db where there is a change in the table structure.
Below is the structure of the table
Table1
Table1ID, WheelCount, BlindCount, OtherCount
For eg values of table 1 is like below
Table1ID, 1,2,5
Table1 is now changed to TableNew with the below
TableNewID, DisableID , Quantity.
So the value should be
TableNewID1, 1,1 here 1= WheelCount from table1
TableNewID2, 2,2 here 2= BlindCount
TableNewID3, 3,5 here 5= OtherCount
how to write a cursor to transform table1 value to the new table tableNew structure.
Table1
Table1ID WheelCount BlindCount OtherCount
1 1 2 5
2 8 10 15
A master table defined to map disableid
DisableID Type
1 wheelCount
2 blindcount
3 otherCount
Expected structure
ID **Table1ID** **DISABLEID** QUANTITY
1 1 1 1
2 1 2 2
3 1 3 5
4 2 1 8
5 2 2 10
6 2 3 15
The simplest is a UNION ALL for each column you want to turn into a row.
insert into tablenew
select table1id,1,wheelcount from table1
union all
select table1id,2,blindcount from table1
union all
select table1id,3,othercount from table1
There are other, sleeker methods for avoiding multiple passes on the first table, in case it's huge.
This is how I understood it.
Current table contents:
SQL> SELECT * FROM table1;
TABLE1ID WHEELCOUNT BLINDCOUNT OTHERCOUNT
---------- ---------- ---------- ----------
1 1 2 5
2 8 10 15
Prepare new table:
SQL> CREATE TABLE tablenew
2 (
3 id NUMBER,
4 table1id NUMBER,
5 disableid NUMBER,
6 quantity NUMBER
7 );
Table created.
Sequence (will be used to populate tablenew.id column):
SQL> CREATE SEQUENCE seq_dis;
Sequence created.
Trigger (which actually populates tablenew.id):
SQL> CREATE OR REPLACE TRIGGER trg_bi_tn
2 BEFORE INSERT
3 ON tablenew
4 FOR EACH ROW
5 BEGIN
6 :new.id := seq_dis.NEXTVAL;
7 END;
8 /
Trigger created.
Copy data:
SQL> INSERT INTO tablenew (table1id, disableid, quantity)
2 SELECT table1id, 1 disableid, wheelcount AS quantity FROM table1
3 UNION ALL
4 SELECT table1id, 2 disableid, blindcount AS quantity FROM table1
5 UNION ALL
6 SELECT table1id, 3 disableid, othercount AS quantity FROM table1;
6 rows created.
Result:
SQL> SELECT *
2 FROM tablenew
3 ORDER BY table1id, disableid;
ID TABLE1ID DISABLEID QUANTITY
---------- ---------- ---------- ----------
1 1 1 1
3 1 2 2
5 1 3 5
2 2 1 8
4 2 2 10
6 2 3 15
6 rows selected.
ID TYPE ORDER_INDEX CITY_ID
-----------------------------------
1 CAT 1 1
2 DOG 2 1
3 CAT 4 2
4 DOG 5 2
5 BEE 9 1
For each city I need to swap the order_index of cat and dog.
So city with ID 1 should have cat=2 and dog=1, city with ID 2 would have cat=5 and dog=4.
How can this be done with pure SQL?
Use an update:
UPDATE yourTable t1
SET ORDER_INDEX = (SELECT t2.ORDER_INDEX FROM yourTable t2
WHERE t2.CITY_ID = t1.CITY_ID AND
t2.TYPE IN ('CAT', 'DOG') AND
t2.TYPE <> T1.TYPE)
WHERE TYPE IN ('CAT', 'DOG');
The above update logic assumes that you wish to do the ORDER_INDEX swap between dog/cat pair records having the same CITY_ID.
Well, if you don't care about ID, then there's a simple option which does what you wanted:
Before:
SQL> select * from test order by id;
ID TYP ORDER_INDEX CITY_ID
---------- --- ----------- ----------
1 CAT 1 1
2 DOG 2 1
3 CAT 4 2
4 DOG 5 2
5 BEE 9 1
Update:
SQL> update test set
2 type = decode(type, 'DOG', 'CAT', 'DOG')
3 where type in ('CAT', 'DOG');
4 rows updated.
After; requirement was
city with ID 1 should have cat=2 and dog=1, city with ID 2 would have cat=5 and dog=4.
SQL> select * from test order by id;
ID TYP ORDER_INDEX CITY_ID
---------- --- ----------- ----------
1 DOG 1 1 --> city with ID = 1 has DOG = 1 ...
2 CAT 2 1 --> ... and CAT = 2
3 DOG 4 2 --> city with ID = 2 has DOG = 4 ...
4 CAT 5 2 --> ... and CAT = 5
5 BEE 9 1
SQL>
Lets say I have a hive table that has 3 rows: merchant_id, week_id, acc_id. My goal is to collect the unique customers in the previous 4 weeks for each week and I am using a moving window to do this.
My codes:
create a test table:
CREATE TABLE table_test_test (merchant_id INT, week_id INT, acc_id INT);
INSERT INTO TABLE table_test_test VALUES
(1,0,8),
(1,0,9),
(1,0,10),
(1,2,1),
(1,2,2),
(1,2,4),
(1,4,1),
(1,4,3),
(1,4,4),
(1,5,1),
(1,5,3),
(1,5,5),
(1,6,1),
(1,6,5),
(1,6,6)
Then do the collect:
select
merchant_id,
week_id,
collect_set(acc_id) over (partition by merchant_id ORDER BY week_id RANGE BETWEEN 4 preceding AND 0 preceding) as uniq_accs_prev_4_weeks
from
table_test_test
The result table is :
merchant_id week_id uniq_accs_prev_4_weeks
1 1 0 []
2 1 0 []
3 1 0 []
4 1 2 [9,8,10]
5 1 2 [9,8,10]
6 1 2 [9,8,10]
7 1 4 [9,8,10,1,2,4]
8 1 4 [9,8,10,1,2,4]
9 1 4 [9,8,10,1,2,4]
10 1 5 [1,2,4,3]
11 1 5 [1,2,4,3]
12 1 5 [1,2,4,3]
13 1 6 [1,2,4,3,5]
14 1 6 [1,2,4,3,5]
15 1 6 [1,2,4,3,5]
As you can see, there are redundant rows in the table. This is just an example, in my actual case this table is huge and the redundancy causes memory problem.
I have tried using distinct and group by but neither of these works.
Is there a good way to do it? Thanks a lot.
Distinct works good:
select distinct merchant_id, week_id, uniq_accs_prev_4_weeks
from
(
select
merchant_id,
week_id,
collect_set(acc_id) over (partition by merchant_id ORDER BY week_id RANGE BETWEEN 4 preceding AND current row) as uniq_accs_prev_4_weeks
from
table_test_test
)s;
Result:
OK
1 0 [9,8,10]
1 2 [9,8,10,1,2,4]
1 4 [9,8,10,1,2,4,3]
1 5 [1,2,4,3,5]
1 6 [1,2,4,3,5,6]
Time taken: 98.088 seconds, Fetched: 5 row(s)
My Hive does not accept 0 preceding, I replaced with current row. It seems like this bug or this bug, my Hive version is 1.2. Yours should work fine with distinct added in the upper subquery.
can any one help to create a AUTO_INCREMENT column on a view in oracle 11g.
Thanks
While it's not possible to return a single unique identity column for a view whose underlying data does not have any single unique identifier, it is possible to return composite values that uniquely identify the data. For example given a table of CSV Data with a unique ID on each row:
create table sample (id number primary key, csv varchar2(4000));
where the CSV column contains a string of comma separated values:
insert into sample
select 1, 'a' from dual union all
select 2, 'b,c' from dual union all
select 3, 'd,"e",f' from dual union all
select 4, ',h,' from dual union all
select 5, 'j,"",l' from dual union all
select 6, 'm,,o' from dual;
The following query will unpivot the csv data and the composite values (ID, SEQ) will uniquely identify each VALue, The ID column idetifies the record the data came from, and SEQ uniquely identifies the position in the CSV:
WITH pvt(id, seq, csv, val, nxt) as (
SELECT id -- Parse out individual list items
, 1 -- separated by commas and
, csv -- optionally enclosed by quotes
, REGEXP_SUBSTR(csv,'(["]?)([^,]*)\1',1,1,null,2)
, REGEXP_INSTR(csv, ',', 1, 1)
FROM sample
UNION ALL
SELECT id
, seq+1
, csv
, REGEXP_SUBSTR(csv,'(["]?)([^,]*)\1',nxt+1,1,null,2)
, REGEXP_INSTR(csv, ',', nxt+1, 1)
FROM pvt
where nxt > 0
)
select * from pvt order by id, seq;
ID SEQ CSV VAL NXT
---------- ---------- ---------- ---------- ----------
1 1 a a 0
2 1 b,c b 2
2 2 b,c c 0
3 1 d,"e",f d 2
3 2 d,"e",f e 6
3 3 d,"e",f f 0
4 1 ,h, [NULL] 1
4 2 ,h, h 3
4 3 ,h, [NULL] 0
5 1 j,"",l j 2
5 2 j,"",l [NULL] 5
5 3 j,"",l l 0
6 1 m,,o m 2
6 2 m,,o [NULL] 3
6 3 m,,o o 0
15 rows selected.
Suppose I have a table with 10 records/tuples. Now I want to update an attribute of 6th record with the same attribute of 1st record, 2nd-7th, 3rd-8th, 4th-9th, 5th-10th in a go i.e. without using cursor/loop. Use of any number of temporary table is allowed. What is the strategy to do so?
PostgreSQL (and probably other RDBMSes) let you use self-joins in UPDATE statements just as you can in SELECT statements:
UPDATE tbl
SET attr = t2.attr
FROM tbl t2
WHERE tbl.id = t2.id + 5
AND tbl.id >= 6
This would be easy with an update-with-join but Oracle doesn't do that and the closest substitute can be very tricky to get to work. Here is the easiest way. It involves a subquery to get the new value and a correlated subquery in the where clause. It looks complicated but the set subquery should be self-explanatory.
The where subquery really only has one purpose: it connects the two tables, much as the on clause would do if we could do a join. Except that the field used from the main table (the one being updated) must be a key field. As it turns out, with the self "join" being performed below, they are both the same field, but it is required.
Add to the where clause other restraining criteria, as shown.
update Tuples t1
set t1.Attr =(
select t2.Attr
from Tuples t2
where t2.Attr = t1.Attr - 5 )
where exists(
select t2.KeyVal
from Tuples t2
where t1.KeyVal = t2.KeyVal)
and t1.Attr > 5;
SqlFiddle is pulling a hissy fit right now so here the data used:
create table Tuples(
KeyVal int not null primary key,
Attr int
);
insert into Tuples
select 1, 1 from dual union all
select 2, 2 from dual union all
select 3, 3 from dual union all
select 4, 4 from dual union all
select 5, 5 from dual union all
select 6, 6 from dual union all
select 7, 7 from dual union all
select 8, 8 from dual union all
select 9, 9 from dual union all
select 10, 10 from dual;
The table starts out looking like this:
KEYVAL ATTR
------ ----
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
with this result:
KEYVAL ATTR
------ ----
1 1
2 2
3 3
4 4
5 5
6 1
7 2
8 3
9 4
10 5