Emulate SQL Server Update in Oracle - sql

How could I emulate the following SQL Server query in Oracle?
declare #index = 4
update tablex set
id_product = #index
, #index = #index + 1
where Id_Person = 4037
In SQL Server it works.

If you are asking what would be the equivalent of the SQL Server code:
DECLARE #index INT = 4
UPDATE tablex SET id_product = #index, #index = #index + 1 where Id_Person = 4037
fiddle
Then you can use a sequence:
CREATE SEQUENCE tablex__id_product__seq START WITH 5;
UPDATE tablex
SET id_product = tablex__id_product__seq.NEXTVAL
WHERE Id_Person = 4037
or could use ROWNUM:
UPDATE tablex
SET id_product = 4 + ROWNUM
WHERE Id_Person = 4037
fiddle

Related

SQL - slow While loop

I have the following T-SQL code that is either adding or updating 1 record at a time to a temp table. Does anyone have any suggestions to speed this process up?
DECLARE #Total AS INT
SELECT #Total = count(AgentsID) from #TempAgentsConcat
DECLARE #counter AS INT
SET #counter = 1
DECLARE #CurrentVal AS NVARCHAR(1024)
DECLARE #RowCount AS INT
DECLARE #OBJ_ID AS INT
while (#counter <= #Total)
begin
SELECT #OBJ_ID = Id FROM #TempAgentsConcat WHERE AgentsId = #counter
SELECT #CurrentVal = SVRMachine FROM #TempAgentsConcat WHERE ID = #OBJ_ID
IF EXISTS (SELECT * FROM #TempEndpoints WHERE ID = #OBJ_ID)
BEGIN
UPDATE #TempEndpoints SET SVRMachine = #CurrentVal WHERE ID = #OBJ_ID
END
ELSE
BEGIN
INSERT INTO #TempEndpoints (SVRMachine, IPPort, ID)
VALUES (#CurrentVal, NULL, #OBJ_ID)
END
--END
SET #counter = #counter + 1
end
It looks like, you are trying to merge one table into other. First lets talk of couple of issues in your query-
1. Avoid using loops unless it's extremely necessary.
2. You are assigning two different variables by reading same row in 2 queries.
You can do this in single query like
SELECT #OBJ_ID = Id,#CurrentVal = SVRMachine FROM #TempAgentsConcat WHERE AgentsId = #counter
instead of 2 queries
SELECT #OBJ_ID = Id FROM #TempAgentsConcat WHERE AgentsId = #counter
SELECT #CurrentVal = SVRMachine FROM #TempAgentsConcat WHERE ID = #OBJ_ID
Let's rewrite the query without using loops. The answer by #Cetin is one of the solutions. Your requirement looks classic example of merging tables, so you may use SQL MERGE (SQL server 2008 and above). You can read more about MERGE, here, checkout the example 'C'.
Using MERGE, your query will look like below.
MERGE INTO #TempEndpoints AS Target
USING (SELECT SVRMachine , Id from #TempAgentsConcat)
AS Source (SVRMachine, ID)
ON Target.ID = Source.ID
WHEN MATCHED THEN
UPDATE SET SVRMachine = Source.SVRMachine
WHEN NOT MATCHED BY TARGET THEN
INSERT (ID, IPPort, SVRMachine) VALUES (Id, NULL,SVRMachine)
Why would you use a lot of variables and loop. SQL server (any SQL series database as well) works best with sets, rather than loops:
UPDATE #TempEndpoints
SET SVRMachine = ac.SVRMachine
FROM #TempAgentsConcat ac
WHERE #TempEndpoints.Id = ac.ID;
INSERT INTO #TempEndpoints
(
SVRMachine,
ID
)
SELECT SVRMachine,
ID
FROM #TempAgentsConcat ac
WHERE NOT EXISTS
(
SELECT * FROM #TempEndpoints ep WHERE ep.ID = ac.ID
);

SQL Server generate script for views and how to decide order?

I am generating the script for views using SQL Server built-in feature (Task -> Generate script). I am creating separate file for each object (of view). I have say around 400 files (containing SQL script of all views) to be executed on another database and to do that automatically I have created BAT file which takes care of that.
There are views which are dependent on other views and due to that many views failed to execute. Is there any way by which we can set order of execution and get rid off the failure ?
Any pointers would be a great help.
Please let me know if you need more details.
Thanks
Jony
Could you try this query? You can execute the create scripts in order to "gen" (generation).
DECLARE #cnt int = 0, #index int;
DECLARE #viewNames table (number int, name varchar(max))
DECLARE #viewGen table (id uniqueidentifier, gen int, name varchar(max), parentId uniqueidentifier)
INSERT INTO #viewNames
SELECT ROW_NUMBER() OVER(ORDER BY object_Id), name FROM sys.views
SELECT #cnt = COUNT(*) FROM #viewNames
SET #index = #cnt;
WHILE ((SELECT COUNT(*) FROM #viewGen) < #cnt)
BEGIN
DECLARE #viewName varchar(200)
SELECT #viewName = name FROM #viewNames WHERE number = #index;
DECLARE #depCnt int = 0;
SELECT #depCnt = COUNT(*) FROM sys.dm_sql_referencing_entities ('dbo.' + #viewName, 'OBJECT')
IF (#depCnt = 0)
BEGIN
INSERT INTO #viewGen SELECT NEWID(), 0, name, null FROM #viewNames WHERE number = #index;
END
ELSE
BEGIN
IF EXISTS(SELECT * FROM sys.dm_sql_referencing_entities ('dbo.' + #viewName, 'OBJECT') AS r INNER JOIN #viewGen AS v ON r.referencing_entity_name = v.name)
BEGIN
DECLARE #parentId uniqueidentifier = NEWID();
INSERT INTO #viewGen SELECT #parentId, 0, name, null FROM #viewNames WHERE number = #index;
UPDATE v
SET v.gen = (v.gen + 1), parentId = #parentId
FROM #viewGen AS v
INNER JOIN sys.dm_sql_referencing_entities('dbo.' + #viewName, 'OBJECT') AS r ON r.referencing_entity_name = v.name
UPDATE #viewGen
SET gen = gen + 1
WHERE Id = parentId OR parentId IN (SELECT Id FROM #viewGen WHERE parentId = parentId)
END
END
SET #index = #index - 1
IF (#index < 0) BEGIN SET #index = #cnt; END
END
SELECT gen as [order], name FROM #viewGen ORDER BY gen
Expecting result:
order name
0 vw_Ancient
1 vw_Child1
1 vw_Child2
2 vw_GrandChild

Looping SQL Server for one or more criteria

I have SQL Server 2008 R2 and I am trying to run an query with a parameter from the client app that will return dynamic values. This should then be run independently for each parameter...
i.e.
PARAM VALUE contains 1,2,3,4,5
Loop for each <PARAM VALUE>
Select * from Table where ID = <PARAM VALUE>
Next
How would I loop for each comma delimited value and run the query independently?
The end all goal is I am going to insert each pass into a new temp table as results.
You can use a table variable to loop through the values:
DECLARE #Values TABLE (Index INT)
INSERT #Values VALUES (1, 2, 3, 4, 5)
DECLARE #Index INT
WHILE EXISTS (SELECT * FROM #Values) BEGIN
SET #Index = (SELECT TOP 1 Index FROM #Values)
SELECT * FROM Table WHERE ID = #Index
DELETE #Values WHERE Index = #Index
END
If the list of values is a sequence, then a more typical loop can be used:
DECLARE #Index INT = 1
WHILE #Index <= 5 BEGIN
SELECT * FROM Table WHERE ID = #Index
SET #Index = #Index + 1
END

SQL Query return values in a set sequence

I have been trying for a while now to return data from the database with the ID(int) values in the following order.
3, 6, 1, 9, 2, 5.
Is there anyway this can be done?
EDIT: Ok i made a bit of a stuff up in my post. the ID's above are just an example.
I am trying to do this dynamically, based around how many records from another table are linked to the record i want to pull out, e.g. i host 3 branches and each branch has a group of shops how would i determine which has the most?
I hope this helps.
Yes, something like this:
select ID from tablename
order by
CASE WHEN ID = 3 THEN 1
WHEN ID = 6 THEN 2
WHEN ID = 1 THEN 3
WHEN ID = 9 THEN 4
WHEN ID = 2 THEN 5
WHEN ID = 5 THEN 6
ELSE 7 END, ID ASC
This will put 3,6,1,9,2,5 and afterwords the other numbers in ascending order.
select cols from table where
order by
case ID when 3 then 0
when 6 then 1
when 1 then 2
when 9 then 3
...
end
You get the idea...
Create a table for the sorting.
CREATE TABLE SortPriority (
SourceID int NULL,
Priority int NULL)
Populate it with the ids and what order they should showup in. Join to the table. and use SortPriority.Priority in your sorting.
You can more easily change the sorting around this way. You would just need to modify the data. You can also later write scripts to populate the table to handle predictable needs in the changing of the sorting.
A split function like this one:
CREATE FUNCTION fnSplit(#str varchar(max), #dlm char(1))
RETURNS #result TABLE (id int, value varchar(50))
AS BEGIN
DECLARE
#id int, #value varchar(50),
#lastpos int, #pos int, #len int;
SET #id = 0;
SET #len = LEN(#str);
SET #lastpos = 1;
SET #pos = CHARINDEX(#dlm, #str + #dlm);
IF #pos <> 0
WHILE 1 = 1 BEGIN
SET #value = SUBSTRING(#str, #lastpos, #pos - #lastpos);
IF #value <> '' BEGIN
SET #id = #id + 1;
INSERT INTO #result VALUES (#id, #value);
END;
IF #pos > #len BREAK;
SET #lastpos = #pos + 1;
SET #pos = CHARINDEX(#dlm, #str + #dlm, #lastpos);
END;
RETURN;
END
would return a row set containing not only the values, but also their indexes within the list. You could then use the function in this way:
SELECT
…
FROM atable t
LEFT JOIN dbo.Split('3,6,1,9,2,5', ',') s ON t.Value = s.Value
ORDER BY
CASE WHEN s.id IS NULL THEN 2147483647 ELSE s.id END

SQL increment a number

Problem:
I want to increment a number based on a table.
So for example, if a table contains
row
1 1 2 3 4 4 4 5
mytable column should increment based on this taking the max(row) + 1 in the above column. So the outcome should look like this:
6 6 7 8 9 9 9 10
This is the code so far:
OPEN cur
DECLARE #WORKING_ON_ID INT
FETCH NEXT FROM cur INTO #WORKING_ON_ID
WHILE ##FETCH_STATUS = 0
BEGIN
SET #MAX_ID = #MAX_ID + 1
UPDATE
#WorkingTable
SET
ID = #MAX_ID
WHERE
ID = #WORKING_ON_ID
FETCH NEXT FROM cur INTO #WORKING_ON_ID
END
CLOSE cur
DEALLOCATE cur
Could you please help me in getting a solution to this problem.
Thanks!
I think you could do it easily with this:
UPDATE your_table
SET id = id + (SELECT MAX(id) FROM your_table)
Wouldn't it be easier to just take the maximum and add it to this ID column? (Remember: the ID column can't be an identity column, otherwise an update will fail)
DECLARE #MAXID INT
SELECT #MAXID = MAX(ID) FROM #WorkingTable
UPDATE #WorkingTable SET ID = ID + #MAXID
Please Try this Code:
Declare #count int = 0
UPDATE table
SET #count = code = #count + 1
Why use a cursor? Wouldn't this solve your problem as well:
DECLARE #MAXID int
SELECT #MAXID=MAX(ID) FROM YourTable
UPDATE YourTable SET ID = ID + #MAXID
In SQL Server 2005 or later version:
WITH cte AS (
SELECT ID, MAX(ID) OVER () AS delta FROM atable
)
UPDATE cte
SET ID = ID + delta;