How to perform multiple updates in stored procedure? [duplicate] - sql-server

This question already has answers here:
Passing a varchar full of comma delimited values to a SQL Server IN function
(27 answers)
Closed 3 years ago.
I will update some columns and some rows from table1 to table2 togetherly based of model column.
ex. table1 in DATA1DB database
| id | name | address | color | model |
| 1 avi aadd blue mod1
| 2 bref ddff red mod2
| 3 cind ffdd red mod1
| 4 davi ffgg green mod1
table2 in DATA2DB database
| id | name | address | color | model |
| 1 avi aadd red mod1
| 2 bref dddd red mod2
| 3 cind ffff red mod1
| 4 davi gggg red mod1
when execute update based id=(1,3,4), i want table2 to be the same as table1.
in my store procedure i have this code
ALTER PROCEDURE [dbo].[updatemultiple]
#id varchar (5)
AS BEGIN SET NOCOUNT ON
begin
UPDATE DATA2DB.table2
SET [DATA2DB].table2.address= [DATA1DB].table1.address,
[DATA2DB].table2.color = [DATA1DB].table1.color,
FROM [DATA2DB].table2
INNER JOIN [DATA1DB].table1
ON [DATA2DB].table2.id = [DATA1DB].table2.id
where LTRIM(RTRIM([DATA1DB].table1.id)) = LTRIM(RTRIM(#id))
I want result table2 in DATA2DB database
| id | name | address | color | model |
1 avi aadd blue mod1
3 cind ffdd red mod1
4 davi ffgg green mod1

I assume you want to update the DB2 whenever the DB1 gets updated.
If so, you can add an update trigger to your table in DB1.
ALTER TRIGGER [dbo].[tr_UPDATE_DB2TABLE]
ON [DATA1DB].table1
AFTER UPDATE
AS BEGIN
SET NOCOUNT ON;
UPDATE DATA2DB.table2
SET [DATA2DB].table2.address= [DATA1DB].table1.address,
[DATA2DB].table2.color = [DATA1DB].table1.color,
FROM [DATA2DB].table2
INNER JOIN Inserted I ON I.Id = [DATA1DB].table1.Id
INNER JOIN [DATA1DB].table1 ON [DATA2DB].table2.id = [DATA1DB].table2.id
where LTRIM(RTRIM([DATA1DB].table1.model)) = LTRIM(RTRIM(I.model))
END
Each time the table in DB1 gets updates it will update the table in DB2.

Took me a while to understand what your problem is...
If I understand you right, you want to execute your procedure with #id=('1,3,4')
Then you want to take each single id (1 and 3 and 4) and run the update for each id with the value from table1.. If this is all correct your sp could look like this:
ALTER PROCEDURE [dbo].[updateMultiple] #id VARCHAR(5)
AS
BEGIN
DECLARE #single_id INT;
DECLARE my_cursor CURSOR
FOR SELECT value
FROM STRING_SPLIT(#id, ',')
WHERE RTRIM(value) <> '';
OPEN my_cursor;
FETCH NEXT FROM my_cursor INTO #single_id;
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE [db2]
SET
[db2].[address] = [db1].[address],
[db2].[color] = [db1].[color]
-- declare #id varchar(5) = (1,3,4);Select *
FROM [data2db] [db2]
JOIN [data1db] [db1] ON [db2].[id] = [db1].[id]
WHERE [db1].[id] = #single_id;
FETCH NEXT FROM my_cursor INTO #single_id;
END;
CLOSE my_cursor;
DEALLOCATE my_cursor;
END;
GO
You need to split your input string into each single id and perform the update..
This is possible, but probably not the best way to do it... Just saying...
Hope it helps.
PS: In my example, I've used two tables in the same DB, but it should work over two different databases as well.
EDIT: Or it should even work without cursor:
ALTER PROCEDURE [dbo].[updateMultiple] #id VARCHAR(5)
AS
BEGIN
UPDATE [db2]
SET
[db2].[address] = [db1].[address],
[db2].[color] = [db1].[color]
--declare #id varchar(5) = '1,3,4';Select *
FROM [data2db] [db2]
JOIN [data1db] [db1] ON [db2].[id] = [db1].[id]
WHERE [db1].[id] IN
(
SELECT value
FROM STRING_SPLIT(#id, ',')
WHERE RTRIM(value) <> ''
);
END;
GO

Related

ORACLE PLSQL - Query data in a package with the result of a table column

I have 1 table with 500k records records and for each record in the table I would like to query an oracle package and return the rows from this query. How can I do this with PL SQL ORACLE?
I tried to do it here:
declare
cursor c_t is select COLUM_TABLE from SCHEMA.COMPANY;
szSql varchar2(2048);
begin
for rec in c_t loop
szSql := 'SELECT * FROM SCHEMA.PKG_COMPANY.GET_DATA_COMPANY('||rec.COLUM_TABLE||')';
dbms_output.put_line(szSql);
execute immediate szSql;
end loop;
end;
I would like to know how to return the data as a common query and if there is a more performant way to do it.
Could you help me with examples?
EDIT
When I call the package, I get the following return:
This data is the result of a complex query that the package makes
ID_COMPANY | REGION | LATITUDE | LONGITUDE | DENSITY | COUNTRY | ROLE
1. WEST. -0110110. -0110110. 22. EUA. SUBS
how to return the data as a common query and if there is a more performant way to do it
How about a function that returns ref cursor? You'd just pass table name to it and get the result:
SQL> create or replace function f_test (par_table_name in varchar2)
2 return sys_refcursor
3 is
4 l_rc sys_refcursor;
5 begin
6 open l_rc for 'select * from ' || dbms_assert.sql_object_name(par_table_name);
7 return l_rc;
8 end;
9 /
Function created.
Let's test it:
SQL> select f_test('dept') from dual;
F_TEST('DEPT')
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
Another table:
SQL> select f_test('invoice') from dual;
F_TEST('INVOICE')
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
DATA_RUN_ FI INVOICE_ID INVOICE_
--------- -- ---------- --------
01-JUL-22 Q4 12345 Paid
01-JAN-22 Q1 12345 Not Paid
01-JUL-22 Q4 12678 Paid
01-JAN-22 Q1 12678 Not Paid
SQL>
As of your code: it is unclear what it does. There's some package and a function, but that's a black box for us as you didn't post it. Also, you're fetching values from the company table; what does it contain? Too many unknown things to debug your code.
If SCHEMA.PKG_COMPANY.GET_DATA_COMPANY() is a function and return a 'select' query like this:
select x,y,...,z from table where ....
then you can write the result into a target table:
cl scr
set SERVEROUTPUT ON
declare
cursor c_t is select COLUM_TABLE from SCHEMA.COMPANY;
szSql varchar2(3000);
begin
for rec in c_t loop
szSql := 'insert into tbl_target '||SCHEMA.PKG_COMPANY.GET_DATA_COMPANY(rec.COLUM_TABLE)||' ';
dbms_output.put_line(szSql);
execute immediate szSql;
commit;
end loop;
end;
in this manner you execute s statement like bellow and insert the result in tbl_target:
insert into tbl_target select x,y,...,z from table where ....
I can not write exact code because SCHEMA.PKG_COMPANY.GET_DATA_COMPANY() is not defined for me.

Execute a stored procedure with multiple IDs

I have a PersonInformation table that contains the information below:
| PersonID | Name | Status
+----------+------+------------
| 1234 | John | Active
| 5678 | Mary | Inactive
| 1090 | Tery | Active
| 1554 | Cary | Inactive
I also have a stored procedure called SpStats that does some calculations using PersonID and returns the results of stat_a, stat_b.
I need to execute the SpStats stored procedure for each active person in the PersonInformation table using their PersonID.
It is basically
SELECT PersonId, Name, Status, {Exec SpStats for related PersonID}
FROM PersonInformation
WHERE status = 'Active'
The expected result is this:
| PersonID | Name | Status | stat_a | stat_b |
+----------+------+--------+--------+--------+
| 1234 | John | Active | 25 | 45 |
| 1090 | Tery | Active | 10 | 67 |
If you can create a user defined table function that will do what your stored procedure does, you could use cross apply to get it's results for each row in the select.
Assuming it accepts the PersonID value, it can be done like this:
SELECT PersonId, [Name], [Status], stat_a, stat_b
FROM PersonInformation
CROSS APPLY dbo.UDFStats(PersonID) as stats
WHERE [Status] = 'Active'
Note that CROSS APPLY will not work with stored procedures.
Create your own custom type like so
--Table Valued Parameter Type used for passing lists of Int IDs.
CREATE TYPE [MySchema].[UniqueIDListType] AS TABLE
(
[ID] Int NOT NULL
);
Then in your stored proc set the input parameter to your type
CREATE PROCEDURE [MySchema].[MyProc]
#MyIDList [MySchema].[UniqueIDListType] READONLY
AS
And there you go, you can use your parameter like a table in your select
WHERE EXISTS (SELECT * FROM #MyIDList WHERE ID = PersonID);
You will get a full result set for each id then. Pass it in to the proc like you would any other parameter, you'll just need to format the ids into this single collection. And the bonus is you can reuse your new table valued parameter everywhere you need to do this again. Reusability!! Yay!
If you can't do this, then I'm assuming you can't with your requirements or permissions make a function either, I would then just loop through programmatically and make a table variable in your sql, call the proc for each person, insert that result in your table, and join that on your final select result set when you're all done.
If you have a table
CREATE TABLE Country (
CountryId UNIQUEIDENTIFIER
,Abbreviation VARCHAR(10)
,Name VARCHAR(100)
)
And a User Defined Function
CREATE FUNCTION udfConcatenate(#value1 VARCHAR(4000), #value2 VARCHAR(4000))
RETURNS VARCHAR(8000)
AS
BEGIN
RETURN CONCAT(#value1, #value2)
/* HERE YOU CAN EXECUTE YOU SOTRED PROCEDURE AND RETURN THE RESULT */
END
You can execute
select c.CountryId, dbo.udfConcatenate(c.Abbreviation, c.Name) from country AS C
The User Defined Function can be applied for each row.
So, the User Defined Function execute you Sotred Procedure and return the result.
And, you use the User Defined Function in you SELECT.
EDIT
WHILE way
DECLARE #abb VARCHAR(10)
DECLARE #name VARCHAR(200)
DECLARE cur1 CURSOR FOR
SELECT Abbreviation, Name FROM Country
OPEN cur1
FETCH NEXT FROM cur1 INTO #abb, #name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT dbo.udfConcatenate(#abb, #name)
/* HERE YOU CAN EXECUTE THE SP AND STORE THE RESULTS IN A TEMP TABLE */
FETCH NEXT FROM cur1 INTO #abb, #name
END
CLOSE cur1
DEALLOCATE cur1
Hope this help you.

Two results from a stored procedure in MS SQL server 2008 R2

I have a stored procedure
CREATE PROCEDURE [dbo].[Sp_getdistrictreport]
-- Add the parameters for the stored procedure here
#DistrictName NVARCHAR(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET nocount ON;
-- Insert statements for procedure here
SELECT a.talukname,
Count (DISTINCT b.globalid) AS Samples_Collected
FROM dbo.village a WITH (INDEX ([S22_idx]))
INNER JOIN dbo.gridpoint_1 b
ON a.shape.Stintersects(b.shape) = 1
INNER JOIN dbo.gridpoint_1__attach c
ON b.globalid = c.rel_globalid
WHERE districtname = #DistrictName
GROUP BY a.talukname
END
which will result
TalukName Samples_Collected
Heggadadevankote | 1
Hunsur | 6
Krishnarajanagara | 4
Mysore | 4
Tirumakudal - Narsipur | 1
But I want to add one more column to this result (Total_SAMPLE), which gets the data from 1st INNER JOIN with the STintersect result. Please help me in modifying the stored procedure.
I got the answer.But it is taking 7.05 minutes for the result.Can anybody help to improve execution time or by any alternative method.
PROCEDURE [dbo].[sp_GetDistrictReportForDashboard]
-- Add the parameters for the stored procedure here
#DistrictName nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
SELECT samples_collected.talukname,sample_count,TotalSamples from
(
SELECT a.TalukName talukname, COUNT (DISTINCT b.GlobalID) sample_count
FROM dbo.VILLAGE a WITH (INDEX ([S22_idx])) , DBO.GRIDPOINT_1 b , dbo.GRIDPOINT_1__ATTACH c
WHERE a.SHAPE.STIntersects(b.Shape)=1
and b.GlobalID=c.REL_GLOBALID
and a.DistrictName=#DistrictName
GROUP BY a.TalukName
) samples_collected,
(
SELECT a.TalukName talukname,COUNT (DISTINCT b.GlobalID) TotalSamples
FROM dbo.VILLAGE a
INNER JOIN
dbo.GRIDPOINT_1 b WITH (INDEX ([S26_idx])) ON a.SHAPE.STIntersects(b.Shape)=1
WHERE a.DistrictName=#DistrictName
GROUP BY a.TalukName
) total
WHERE samples_collected.talukname=total.talukname
END
Result
talukname sample_count TotalSamples
Heggadadevankote | 1 | 55001
Hunsur | 6 | 31316
Krishnarajanagara | 4 | 34297
Mysore | 4 | 18168
Tirumakudal - Narsipur | 1 | 38668

update one table from another selected table

I select one column from a table and generated the second column by select case:
(select Id , case
when education=0 then '0::ALL'
when education=1 then '1::HIGH_SCHOOL'
when education=2 then '2::UNDERGRAD'
when education=3 then '3::ALUM'
when education=4 then '4::HIGH_SCHOOL_GRAD'
when education=5 then '5::SOME_COLLEGE'
when education=6 then '6::ASSOCIATE_DEGREE'
when education=7 then '7::IN_GRAD_SCHOOL'
when education=8 then '8::SOME_GRAD_SCHOOL'
when education=9 then '9::MASTER_DEGREE'
when education=10 then '10::PROFESSIONAL_DEGREE'
when education=11 then '11::DOCTORATE_DEGREE'
when education=12 then '12::UNSPECIFIED'
end as myeducation
from ids_table where Id = '4fcc-a519-15db04651b91')
assuming it returns:
------------------------------------------------
| Id myeducation |
| 4fcc-a519-15db04651b91, 9::MASTER_DEGREE |
------------------------------------------------
in the same table (ids_table), I have an empty column is called: allEducations
I want to set allEducations = myeducation where id (of the table above that I "created") is equal to the id of the table (ids_table)
before:
ids_table:
----------------------------------------------
| Id allEducation |
| 4fcc-a519-15db04651b91, |
------------------------------------------------
after:
----------------------------------------------
| Id allEducation |
| 4fcc-a519-15db04651b91, 9::MASTER_DEGREE |
------------------------------------------------
I tried to do something like:
`;WITH b AS (THE SQL QUERY ABOVE) update ids_table c set c.allEducations = b.myeducation where c.id = b.id'
any help appreciated!
This should be enough:
begin tran updateEducation
update ids_table set allEducations =
case
when education=0 then '0::ALL'
when education=1 then '1::HIGH_SCHOOL'
when education=2 then '2::UNDERGRAD'
when education=3 then '3::ALUM'
when education=4 then '4::HIGH_SCHOOL_GRAD'
when education=5 then '5::SOME_COLLEGE'
when education=6 then '6::ASSOCIATE_DEGREE'
when education=7 then '7::IN_GRAD_SCHOOL'
when education=8 then '8::SOME_GRAD_SCHOOL'
when education=9 then '9::MASTER_DEGREE'
when education=10 then '10::PROFESSIONAL_DEGREE'
when education=11 then '11::DOCTORATE_DEGREE'
when education=12 then '12::UNSPECIFIED'
end
---- if it is not good
-- rollback
---- if it is good
-- commit

A trigger to update one column value to equal the pkid of the record

I need to write a trigger that will set the value in column 2 = to the value in column 1 after a record has been created.
This is what I have so far:
create trigger update_docindex2_to_docid
ON dbo.TABLENAME
after insert
AS BEGIN
set DOCINDEX2 = DOCID
END;
I answered my own question one I sat and thought about it long enough....
This seems way to simple. I'm concerned that I'm going break something because I don't have a where condition that would identify the correct record. I want this to update docindex2 to the newly created DOCID after a record is created in the database. The docid is the pkid.
Any ideas/suggestions are appreciated....
Are you looking for something like this?
CREATE TABLE Table1 (docid INT IDENTITY PRIMARY KEY, docindex2 INT);
CREATE TRIGGER tg_mytrigger
ON Table1 AFTER INSERT
AS
UPDATE t
SET t.docindex2 = t.docid
FROM Table1 t JOIN INSERTED i
ON t.docid = i.docid;
INSERT INTO Table1 (docindex2) VALUES(0), (0);
Contents of Table after insert
| DOCID | DOCINDEX2 |
---------------------
| 1 | 1 |
| 2 | 2 |
Here is SQLFiddle demo

Resources