I have a table SaleOrder(SO) and SaleOrderDetail(SOD) with one to may relation ship. ID and SOID are primary key foreign key.
i need to update SO Table with Values of SOD Tables after some aggregation based on primary key.
please see below.
SO
-----------------------------------
ID SaleOrderQty
1 --
2 --
SOD
-------------------------------------
SOID Qty PerPack
1 3 10
1 7 6
2 4 5
2 5 8
multiply Qty with PerPack
1 3*10 = 30
1 7*6 = 42
2 4*5 = 20
2 5*8 = 40
and add up all multiplication results based on keys
1 30+42 = 72
2 20+40 = 60
and update Parent table
SO
-----------------------------------
ID SaleOrderQty
1 72
2 60
i tried this
Declare #Id varchar(50)
declare #Next int
set #Next =1
WHILE #Next <= 30
Begin
Select #Id = Id From SO Where SOSerial=#Next
Update SO
Set SaleOrderQty = (SELECT sum((SOD.Quantity* SOD.PerPack)) total
FROM SO INNER JOIN
SOD ON SO.Id = SOD.SOId
WHERE SOD.SOId=#Id
group by SOD.SOId)
set #Next=#Next+1
--print #Id
End
sums are ok but it set all SaleOrderQty values with the last sum.
One more thing. i have 30 records in parent table. when query completes it shows 30 messages.
Per my prior comment, you want to avoid loops.
update so
set SaleOrderQty = a.calc
from SO so
join (select sod.soid,sum((SOD.Quantity* SOD.PerPack)) as calc
from sod
group by sod.SOID) a on a.SOID=so.ID
where so.SaleOrderQty is null --optional
Related
suppose I have 100000 records in A table and 1000 records in B table. both have primary/foreign key relationship. now i want to update a column value for first 100 records in table A with column value from table B first record. similary i want to update all the 100000 records in table A as a batch 100 records for 1000 times with values from table B.
no. of records updated per batch is 100 i.e. 100000/1000=100
Lets assume you have table_a with 20 rows with a unique id column and you want to update the value column:
CREATE TABLE table_a (id, value) AS
SELECT LEVEL, CAST(NULL AS NUMBER(8,0)) FROM DUAL CONNECT BY LEVEL <= 20;
And table_b with 5 rows containing the values you want to update from:
CREATE TABLE table_b (id, value) AS
SELECT LEVEL, LEVEL FROM DUAL CONNECT BY LEVEL <= 5;
Then, you can use a correlated UPDATE statement:
UPDATE table_a a
SET value = (SELECT value
FROM table_b b
WHERE CEIL(a.id*5/20) = b.id);
or a MERGE statement:
MERGE INTO table_a a
USING table_b b
ON (CEIL(a.id*5/20) = b.id)
WHEN MATCHED THEN
UPDATE
SET value = b.value;
Both statements result in:
ID
VALUE
1
1
2
1
3
1
4
1
5
2
6
2
7
2
8
2
9
3
10
3
11
3
12
3
13
4
14
4
15
4
16
4
17
5
18
5
19
5
20
5
db<>fiddle here
Having data like this:
id text bit date
1 row 1 2016-11-24
2 row 1 2016-11-25
3 row 0 2016-11-26
4 row 1 2016-11-27
I want to select the data based on where the text and bit columns are distinct, but based on some order, in this case the id, the data changes between two identical rows, it should duplicate this row on the selection.
So, if I use distinct on SQL, I would get rows 1 and 3, but I want to retreive rows 1, 3 and 4, because even 1 and 4 being identical, row 3 is between then when ordering by id.
With a larger dataset, like:
id text bit date
1 row 1 2016-11-24
2 row 1 2016-11-25
3 row 0 2016-11-26
4 row 1 2016-11-27
5 foo 1 2016-11-28
6 bar 1 2016-11-29
7 row 1 2016-11-30
8 row 0 2016-12-01
9 row 0 2016-12-02
10 row 1 2016-12-03
Again, selecting with distinct on text and bit columns, the query would retrieve rows 1,3,5 and 6, but actually I want rows 1,3,4,5,6,7,8 and 10.
;with tb(id,[text],[bit],[date]) AS (
SELECT 1,'row',1,'2016-11-24' union
SELECT 2,'row',1,'2016-11-25' union
SELECT 3,'row',0,'2016-11-26' union
SELECT 4,'row',1,'2016-11-27' union
SELECT 5,'foo',1,'2016-11-28' union
SELECT 6,'bar',1,'2016-11-29' union
SELECT 7,'row',1,'2016-11-30' union
SELECT 8,'row',0,'2016-12-01' union
SELECT 9,'row',0,'2016-12-02' union
SELECT 10,'row',1,'2016-12-03')
select t1.* from tb as t1
OUTER APPLY (select top 1 [text],[bit] from tb as tt where tt.id<t1.id order by id desc ) as t2
where t1.[text]!=isnull(t2.[text],'') or t1.[bit]!=isnull(t2.[bit],1-t1.[bit])
result set:
1 row 1 2016-11-24
3 row 0 2016-11-26
4 row 1 2016-11-27
5 foo 1 2016-11-28
6 bar 1 2016-11-29
7 row 1 2016-11-30
8 row 0 2016-12-01
10 row 1 2016-12-03
It seems that you need a row-by-row operator. You need to know if the new row is the same as the previous one or not. If it is, neglect it, if not, keep it. Here is my solution:
declare #text varchar(100)=(select [text] from Mytable where id = 1)
declare #bit bit = (select [bit] from Mytable where id = 1)
declare #Newtext varchar(100)
declare #Newbit bit
declare #Mytable table(id int, [text] varchar(100), [bit] bit)
Insert into #Mytable select id,text, bit from Mytable where id = 1
declare #counter int =2
while #counter<=(select COUNT(*) from MyTable)
Begin
select #Newtext=(select [text] from Mytable where id = #counter)
select #Newbit=(select [bit] from Mytable where id = #counter)
IF #Newtext!=#text or #Newbit!=#bit
Begin
Insert into #Mytable
select * from Mytable where id = #counter
End
set #text = #Newtext
set #bit = #Newbit;
set #counter = #counter+1
END
select * from #Mytable
I am new to the recursive CTE concept and a problem at hand, I got a tiny feeling that the problem can be solved by using recursive CTE. Let me know what you guys think.
Two tables:
Table one is a self referencing Location table with ID, ParentID, Level and Description.
Table two is an asset table which records individual assets and has a foreign key to Location table ID field.
Table1:
ID Description ParentID Level
1 Site1 NULL 1
2 Site2 NULL 1
3 Building1 1 2
4 Building2 1 2
5 Floor1 3 3
6 Floor2 3 3
7 Floor3 4 3
8 Place1 5 4
9 Place2 7 4
Table2:
ID Description Quantity LocationID
1 Desk 3 8
2 Lamp 1 8
3 PC 10 9
I would like to create a stored procedure with a input parameter of #Level and returns all the Location records at that level and the number of assets within the location (including sub levels).
For example, if #Level = 3, the stored procedure should return:
ID Description AssetCount
5 Floor1 4
6 Floor2 0
7 Floor3 10
If #Level = 2, the stored procedure should return:
ID Description AssetCount
3 Building1 4
4 Building2 10
If the problem is not clear, please let me know.
Well, nothing special here, just a recursive CTE joined with the other table, and the results are what you expected:
declare #level int = 3
;with CTE as (
select id as origid, id, Description, parentid
from table1 where level = #level
union all
select CTE.origid, t1.id, CTE.Description, t1.parentid
from CTE join table1 t1 on
CTE.id = t1.parentid
)
select origid, CTE.description, isnull(sum(t2.Quantity),0) as Quantity
from CTE left outer join table2 t2 on CTE.id = t2.locationid
group by origid, CTE.description
SQL Fiddle
I am trying to update a lead table to assign a random person from a lookup table. Here is the generic schema:
TableA (header),
ID int,
name varchar (30)
TableB (detail),
ID int,
fkTableA int, (foreign key to TableA.ID)
recordOwner varchar(30) null
other detail colums..
TableC (owners),
ID int,
fkTableA int (foreign key to TableA.ID)
name varchar(30)
TableA has 10 entries, one for each type of sales lead pool. TableB has thousands of entries for each row in TableA. I want to assign the correct recordOwners from TableC to and even number of rows each (or as close as I can). TableC will have anywhere from one entry for each row in tableA or up to 10.
Can this be done in one statement? It doesn't have to be. I can't seem to figure out the best approach for speed. Any thoughts or samples are appreciated.
Updated:
TableA has a 1 to many relation ship with TableC. For every record of TableA, TableC will have at least one row, which represents an owner that will need to be assigned to a row in TableB.
TableA
int name
1 LeadSourceOne
2 LeadSourceTwo
TableC
int(id) int(fkTableA) varchar(name)
1 1 Tom
2 1 Bob
3 2 Timmy
4 2 John
5 2 Steve
6 2 Bill
TableB initial data
int(id) int(fkTableA) varchar(recordOwner) (other detail columns)
1 1 NULL ....
2 1 NULL ....
3 1 NULL ....
4 2 NULL ....
5 2 NULL ....
6 2 NULL ....
7 2 NULL ....
8 2 NULL ....
9 2 NULL ....
TableB end result
int(id) int(fkTableA) varchar(recordOwner) (other detail columns)
1 1 TOM ....
2 1 BOB ....
3 1 TOM ....
4 2 TIMMY ....
5 2 JOHN ....
6 2 STEVE ....
7 2 BILL ....
8 2 TIMMY ....
9 2 BILL ....
Basically I need to randomly assign a record from tableC to tableB based on the relationship to tableA.
UPDATE TabB SET name = (SELECT TOP 1 coalesce(tabC.name,'') FROM TabC INNER JOIN TabA ON TabC.idA = TabA.id WHERE tabA.Id = TabB.idA )
Should work but its not tested.
Try this:
UPDATE TableB
SET recordOwner = (SELECT TOP(1) [name]
FROM TableC
ORDER BY NEWID())
WHERE recordOwner IS NULL
I ended up looping thru and updating x percent of the detail records based on how many owners I had. The end result is something like this:
create table #tb_owners(userId varchar(30), processed bit)
insert into #tb_owners(
userId,
processed)
select userId = name,
processed = 0
from tableC
where fkTableA = 1
select #percentUpdate = cast(100 / count(*) as numeric(8,2))
from #tb_owners
while exists(select 1 from #tb_owners o where o.processed = 0)
begin
select top 1
#userFullName = o.name
from #tb_owners o
where o.processed = 0
order by newId()
update tableB
set recordOwner = #userFullName
from tableB ptbpd
inner join (
select top (#percentUpdate) percent
id
from tableB
where recordOwner is null
order by newId()
) nd on (ptbpd.id = nd.id)
update #tb_owners
set processed = 1
where userId = #oUserId
end
--there may be some left over, set to last person used
update tableB
set recordOwner = #userFullName
from tableB
where ptbpd.recordOwner is null
I have two tables both of which have a column named column_value which holds a number value. Now what i want is to sum the values of column_value in both the tables individually for each row and then update the same column (column_value) in the first table with the sum that i get for each row.
For example I have table A and table B, both of them have a column name AMOUNT.
Table A:
id AMOUNT
1 20
2 30
Table B:
id AMOUNT
1 10
2 25
First of all i want to get the following result
id AMOUNT AMOUNT TOTALAMOUNT
1 20 10 30
2 30 25 55
Now i would like to update each row of the A table with the TOTALAMOUNT against each id
so that after the Update the table A should look like
id AMOUNT
1 30
2 55
Selection :
SELECT A.ID,
NVL(A.AMOUNT,0) A_AMOUNT ,
NVL(B.AMOUNT,0) B_AMOUNT ,
NVL(A.AMOUNT,0) + NVL(B.AMOUNT,0) AS TOTAL_AMOUNT
FROM TABLEA A, TABLEB B
WHERE A.ID = B.ID
Update:
UPDATE TABLEA A
SET A.AMOUNT = (SELECT NVL(A.AMOUNT,0) + NVL(B.AMOUNT,0)
FROM TABLEB B
WHERE A.ID = B.ID)
You should have to use left join. For example:
Table_a
id val
1 10
2 20
Table_b
id val
1 20
2 30
update Table_a a left join Table_b b on a.id = b.id set a.val = (a.val+b.val);
After this operation:
Table_a
id val
1 30
2 50