bulk update one table using value in another table - postgresql

If I find a max value in my database of LIM50177
lim_id
LIM50172
LIM50173
LIM50174
LIM50175
LIM50176
LIM50177
How can I loop through another table and for every base_id go and bulk replace the temp_id with a new lim_id?
temp_id base id desc
1008 720 GP
1009 721 GT
1010 722 GA
1021 723 P
1021 724 G
1021 725 X
In other words
The data will be updated as follows:
temp_id base id desc
LIM50178 720 GP
LIM50179 721 GT
LIM50180 722 GA
LIM50181 723 P
LIM50182 724 G
LIM50183 725 X

Use a sequence every time you generate the lim_id values so you get unique values.
(Don't use the values in the other table to calculate the maximum value as, if the table is updated in two sessions at the same time and you are always basing the next value off the maximum value in the table then neither session will see the updates performed by the other session and you can end up generating identical "next" values in each session. Instead, every time you generate the "next" value always get that "next" value from the sequence.)
Oracle Setup:
CREATE SEQUENCE lim_id_seq START WITH 50178;
CREATE TABLE temp_data ( temp_id, base_id, "desc" ) AS
SELECT CAST( 1008 AS VARCHAR2(10) ), 720, 'GP' FROM DUAL UNION ALL
SELECT CAST( 1009 AS VARCHAR2(10) ), 721, 'GT' FROM DUAL UNION ALL
SELECT CAST( 1010 AS VARCHAR2(10) ), 722, 'GA' FROM DUAL UNION ALL
SELECT CAST( 1021 AS VARCHAR2(10) ), 723, 'P' FROM DUAL UNION ALL
SELECT CAST( 1021 AS VARCHAR2(10) ), 724, 'G' FROM DUAL UNION ALL
SELECT CAST( 1021 AS VARCHAR2(10) ), 725, 'X' FROM DUAL
Update using the Sequence:
UPDATE temp_data
SET temp_id = 'LIM' || lim_id_seq.NEXTVAL;
Result:
SELECT * FROM temp_data;
TEMP_ID | BASE_ID | desc
:------- | ------: | :---
LIM50178 | 720 | GP
LIM50179 | 721 | GT
LIM50180 | 722 | GA
LIM50181 | 723 | P
LIM50182 | 724 | G
LIM50183 | 725 | X
db<>fiddle here

Related

Pivot sum in PostgreSQL

I'm using PosgreSQL 4.2. And I have the following code:
SELECT ID, Num1, Num2 FROM Tab1
WHERE ID IN(1,2,3,4.....50);
Returns results as:
ID | Num1 | Num2
----+--------------------
1 | 100 | 0
2 | 50 | 1
3 | 30 | 2
4 | 110 | 3
5 | 33 | 4
6 | 46 | 5
7 | 36 | 6
8 | 19 | 7
9 | 20 | 8
10 | 31 | 9
11 | 68 | 10
12 | 123 | 11
13 | 588 | 0
14 | 231 | 1
15 | 136 | 2
I want to Pivot sum to return result with pairs of number in IN clause, and result return like this:
| ID | Meaning
-------------------------
Num1 | 150 | 1+2(num1)
Num2 | 1 | 1+2(num2)
Num1 | 140 | 3+4(num1)
Num2 | 5 | 3+4(num2)
Num1 | 79 | 5+6(num1)
Num2 | 9 | 5+6(num2)
.........................
How can I do that?
PostgreSQL 4.2. No you must have another application ans confusing your application versions:
In 1996, the project was renamed to PostgreSQL to reflect its support
for SQL. The online presence at the website PostgreSQL.org began on
October 22, 1996.[26] The first PostgreSQL release formed version 6.0
on January 29, 1997.
Wikipedia. You might want to run the query: select version();
However, any supported version is sufficient for this request. Actually the SQL necessary to supply the necessary summations is simple once you understand LEAD (LAG) functions. The LEAD function permits access to the following row. Using that then the query:
select id, nid, n1s, n2s
from ( select id
, coalesce(lead(id) nid
, num1 + coalesce(lead(num1) over (order by id),0) n1s
, num2 + coalesce(lead(num2) over (order by id),0) n2s
, row_number() over() rn
from tab1
) i
where rn%2 = 1;
Provides all the necessary data for the presentation layer to format the the result as desired. However, that's not the result requested, that requires some SQL gymnastics.
We begin the gymnastics show by wrapping the above into an CTE adding a little setup for the show to follow. The main event then breaks the results into 2 sets in order to add the syntactical sugar tags before bringing then back together. So for the big show:
with joiner(id,nid,n1s,n2s,rn) as
( select *
from ( select id
, coalesce(lead(id) over (order by id),0)
, num1 + coalesce(lead(num1) over (order by id),0)
, num2 + coalesce(lead(num2) over (order by id),0)
, row_number() over() rn
from tab1
) i
where rn%2 = 1
)
select "Name","Sum","Meaning"
from (select 'Num1' as "Name"
, n1s as "Sum"
, concat(id::text, case when nid = 0
then null
else '+' || nid::text
end
) || ' (num1)'as "Meaning"
, rn
from joiner
union all
select 'Num2'
, n2s
, concat(id::text, case when nid = 0
then null
else '+' || nid::text
end
) || ' (num2)'
, rn
from joiner
) j
order by rn, "Name"
See fiddle. Note: I used "Sum" instead of ID for the column title, as it indicates the id not at all. That is just in the "Meaning" column.

Salary Accumulation by mgr (DB2 for Oracle CONNECT_BY)

We have data from scott.emp table:
select empno, ename,mgr, sal
from emp
order by empno
;
EMPNO|ENAME | MGR| SAL
-----|----------|-----|----------
7369|SMITH | 7902| 800
7499|ALLEN | 7698| 1600
7521|WARD | 7698| 1250
7566|JONES | 7839| 2975
7654|MARTIN | 7698| 1250
7698|BLAKE | 7839| 2850
7782|CLARK | 7839| 2450
7788|SCOTT | 7566| 3000
7839|KING | | 5000
7844|TURNER | 7698| 1500
7876|ADAMS | 7788| 1100
7900|JAMES | 7698| 950
7902|FORD | 7566| 3000
7934|MILLER | 7782| 1300
14 rows selected.
Then I want to list hirearchy of emp as well as Salary Accumulation, which returns rows like this:
DESKRIPSI | EMPNO| MGR| AMOUNT
----------|------|------|--------
KING | 7839| | 29.025
.JONES | 7566| 7839| 10.875
..SCOTT | 7788| 7566| 4.100
...ADAMS | 7876| 7788| 1.100
..FORD | 7902| 7566| 3.800
...SMITH | 7369| 7902| 800
.BLAKE | 7698| 7839| 9.400
..ALLEN | 7499| 7698| 1.600
..WARD | 7521| 7698| 1.250
..MARTIN | 7654| 7698| 1.250
..TURNER | 7844| 7698| 1.500
..JAMES | 7900| 7698| 950
.CLARK | 7782| 7839| 3.750
..MILLER | 7934| 7782| 1.300
14 rows selected.
With Oracle RDBMS, the approach is like this:
WITH pohon
AS (SELECT
DISTINCT CONNECT_BY_ROOT empno parent_id, empno AS id
FROM
emp
CONNECT BY
PRIOR empno = mgr),
trx
AS (SELECT
pohon.parent_id, SUM (tx.sal) AS amount
FROM
pohon JOIN emp tx ON pohon.id = tx.empno
GROUP BY
pohon.parent_id)
SELECT
LPAD (r0.ename, LENGTH (r0.ename) + LEVEL * 1 - 1, '.') AS deskripsi,empno, mgr,
trx.amount
FROM
emp r0 JOIN trx ON r0.empno = trx.parent_id
START WITH
r0.mgr IS NULL
CONNECT BY
r0.mgr = PRIOR r0.empno
;
How can I get the same result in DB2 RDBMS?
Regards.
There are two ways, either enable the Oracle-compatible CONNECT_BY clause
or use SQL Standard recursive SQL as per the example on this page
Example 2: Summarized explosion The second example is a summarized
explosion. The question posed here is, what is the total quantity of
each part required to build part '01'. The main difference from the
single level explosion is the requirement to aggregate the quantities.
The first example indicates the quantity of subparts required for the
part whenever it is required. It does not indicate how many of the
subparts are needed to build part '01'.
WITH RPL (PART, SUBPART, QUANTITY) AS
(
SELECT ROOT.PART, ROOT.SUBPART, ROOT.QUANTITY
FROM PARTLIST ROOT
WHERE ROOT.PART = '01'
UNION ALL
SELECT PARENT.PART, CHILD.SUBPART, PARENT.QUANTITY*CHILD.QUANTITY
FROM RPL PARENT, PARTLIST CHILD
WHERE PARENT.SUBPART = CHILD.PART
)
SELECT PART, SUBPART, SUM(QUANTITY) AS "Total QTY Used"
FROM RPL
GROUP BY PART, SUBPART
ORDER BY PART, SUBPART;
The following statement returns the results desired. Run it as is.
WITH EMP (EMPNO, ENAME, MGR, SAL) AS
(
VALUES
(7369, 'SMITH ', 7902, 800)
, (7499, 'ALLEN ', 7698, 1600)
, (7521, 'WARD ', 7698, 1250)
, (7566, 'JONES ', 7839, 2975)
, (7654, 'MARTIN ', 7698, 1250)
, (7698, 'BLAKE ', 7839, 2850)
, (7782, 'CLARK ', 7839, 2450)
, (7788, 'SCOTT ', 7566, 3000)
, (7839, 'KING ', NULL, 5000)
, (7844, 'TURNER ', 7698, 1500)
, (7876, 'ADAMS ', 7788, 1100)
, (7900, 'JAMES ', 7698, 950)
, (7902, 'FORD ', 7566, 3000)
, (7934, 'MILLER ', 7782, 1300)
)
, C (LVL, EMPNO, MGR, ENAME, SAL, CHAIN) AS
(
SELECT
0 AS LVL, EMPNO, MGR, ENAME, SAL
, CAST('|' || TRIM(CHAR(EMPNO)) || '|' AS VARCHAR(1024)) AS CHAIN
FROM EMP C
WHERE NOT EXISTS (SELECT 1 FROM EMP P WHERE P.EMPNO = C.MGR)
UNION ALL
SELECT C.LVL + 1 AS LVL, E.EMPNO, E.MGR, E.ENAME, E.SAL
, C.CHAIN || TRIM(CHAR(E.EMPNO)) || '|' AS CHAIN
FROM C, EMP E
WHERE E.MGR = C.EMPNO
)
SELECT
REPEAT('.', LVL) || ENAME AS DESKRIPSI
, EMPNO
, MGR
, (SELECT SUM(SAL) FROM C C2 WHERE C2.CHAIN LIKE C1.CHAIN || '%') AS AMOUNT
FROM C C1
ORDER BY CHAIN;

results mismatched when retrieved dates from column of type character varying

I have two tables,i want to get the min and max date stored in table1 cfrange column which is of type character varying.
table1 and table2 is mapped using sid. i want to get the max and min date range when compared with sid of table2.
table1:
sid cfrange
100 3390
101 8000
102 5/11/2010
103 11/12/2016
104 01/03/2016
105 4000
106 4000
107 03/12/2017
108 03/11/2016
109 4/04/2018
110 10/12/2016
table2:
sid description
102 success
103 success
104 Proceeding
107 success
108 success
I tried as below but its not giving the correct min and max value.Please advice.
select max(t1.cfrange),min(t1.cfrange) from table1 t1,table2 t2 where t1.sid=t2.sid;
You should join two tables and cast cfrange as a date and cross your fingers. (May be you must format it as a date before to cast it).
create table table1 (sid int, cfrange varchar(30));
insert into table1 values
(100, '3390'),
(101, '8000'),
(102, '5/11/2010'),
(103, '11/12/2016'),
(104, '01/03/2016'),
(105, '4000'),
(106, '4000'),
(107, '03/12/2017'),
(108, '03/11/2016'),
(109, '4/04/2018'),
(110, '10/12/2016');
create table table2 (sid int, description varchar(30));
insert into table2 values
(102, 'success'),
(103, 'success'),
(104, 'Proceeding'),
(107, 'success'),
(108, 'success');
select 'Min' as caption, min(cfrange) as value
from (select table1.sid, table1.cfrange::date
from table1
inner join table2
on table1.sid = table2.sid) tt
UNION ALL
select 'Max' as caption, max(cfrange) as value
from (select table1.sid, table1.cfrange::date
from table1
inner join table2
on table1.sid = table2.sid) tt;
caption | value
:------ | :---------
Min | 2010-11-05
Max | 2017-12-03
dbfiddle here

Renumbering a column in postgresql based on sorted values in that column

Edit: I am using postgresql v8.3
I have a table that contains a column we can call column A.
Column A is populated, for our purposes, with arbitrary positive integers.
I want to renumber column A from 1 to N based on ordering the records of the table by column A ascending. (SELECT * FROM table ORDER BY A ASC;)
Is there a simple way to accomplish this without the need of building a postgresql function?
Example:
(Before:
A: 3,10,20,100,487,1,6)
(After:
A: 2,4,5,6,7,1,3)
Use the rank() (or dense_rank() ) WINDOW-functions (available since PG-8.4):
create table aaa
( id serial not null primary key
, num integer not null
, rnk integer not null default 0
);
insert into aaa(num) values( 3) , (10) , (20) , (100) , (487) , (1) , (6)
;
UPDATE aaa
SET rnk = w.rnk
FROM (
SELECT id
, rank() OVER (order by num ASC) AS rnk
FROM aaa
) w
WHERE w.id = aaa.id;
SELECT * FROM aaa
ORDER BY id
;
Results:
CREATE TABLE
INSERT 0 7
UPDATE 7
id | num | rnk
----+-----+-----
1 | 3 | 2
2 | 10 | 4
3 | 20 | 5
4 | 100 | 6
5 | 487 | 7
6 | 1 | 1
7 | 6 | 3
(7 rows)
IF window functions are not available, you could still count the number of rows before any row:
UPDATE aaa
SET rnk = w.rnk
FROM ( SELECT a0.id AS id
, COUNT(*) AS rnk
FROM aaa a0
JOIN aaa a1 ON a1.num <= a0.num
GROUP BY a0.id
) w
WHERE w.id = aaa.id;
SELECT * FROM aaa
ORDER BY id
;
Or the same with a scalar subquery:
UPDATE aaa a0
SET rnk =
( SELECT COUNT(*)
FROM aaa a1
WHERE a1.num <= a0.num
)
;

Sql join and remove distinct in two separate column

I have table ordered
form_id | procedure_id
----------+-------------
101 | 24
101 | 23
101 | 22
102 | 7
102 | 6
102 | 3
102 | 2
And another table have table performed
form_id | procedure_id
----------+-------------
101 | 42
101 | 45
102 | 5
102 | 3
102 | 7
102 | 12
102 | 13
Expected output
form_id o_procedure_id p_procedure_id
101 24 42
101 23 45
101 22 NULL
102 7 7
102 6 5
102 3 3
102 2 12
102 NULL 13
I tried the below query:
with ranked as
(select
dense_rank() over (partition by po.form_id order by po.procedure_id) rn1,
dense_rank() over (partition by po.form_id order by pp.procedure_id) rn2,
po.form_id,
po.procedure_id,
pp.procedure_id
from ordered po,
performed pp where po.form_id = pp.form_id)
select ranked.* from ranked
--where rn1=1 or rn2=1
The above query return the value with repeat value ordered and procedure ID.
How to get Excepted output?
I wasn't quite sure how you would want to handle multiple null values and/or null values on both sides of your tables. My example therefor assumes the first table to be leading and include all entries while the second table might include holes. Query ain't pretty but i suppose it does what you expect it to:
select test1_sub.form_id, test1_sub.process_id as pid_1, test2_sub.process_id as pid_2 from (
select form_id,
process_id,
rank() over (partition by form_id order by process_id asc nulls last)
from test1) as test1_sub
left join (
select * from (
select form_id,
process_id,
rank() over (partition by form_id order by process_id asc nulls last)
from test2
) as test2_nonexposed
) as test2_sub on test1_sub.form_id = test2_sub.form_id and test1_sub.rank = test2_sub.rank;