Loops and Updates in DBT - dbt

I have a very unique problem. I want to update a table in dbt using another dbt and having a counter that hunts for new values and then it updates the column. For eg.
SET NOCOUNT ON;
DECLARE #R INT;
SET #R = 2;
WHILE #R<10
BEGIN
UPDATE PER
SET PER.CDS_ID = PERNext.CDS_ID
FROM #P PER
INNER JOIN #E PERNext ON (PER.web_prfl_id = PERNext.web_prfl_id AND RN = #R)
WHERE PER.CDS_ID IS NULL AND PERNext.CDS_ID IS NOT NULL
SET #R = #R+1
END
RN is row number available in E table which partitions by the create date.
I know we can do update statements in post hook but how to have a counter and then do the update?
Thanks,

My understanding that you're trying to perform the UPDATE statement within dbt, no matter what the job is.
So there are 2 options you could try:
Using incremental mode. Have a read on this
Would be easier that using dbt marco - it is something the same as procedure, but within dbt. Have a read this

Related

Updating a column in every table in a schema in SQL Server

I want to update the column Last_Modified in every table in a given schema. This column is updated with latest timestamp if another column in the same table (ENDTIME) is updated.
To do this I have the following script in SQL Server:
DECLARE #TotalRows FLOAT
SET #TotalRows = (SELECT COUNT(*) FROM table1)
DECLARE #TotalLoopCount INT
SET #TotalLoopCount = CEILING(#TotalRows / 100000)
DECLARE #InitialLoopCount INT
SET #InitialLoopCount = 1
DECLARE #AffectedRows INT
SET #AffectedRows = 0
DECLARE #intialrows INT;
SET #intialrows = 1
DECLARE #lastrows INT
SET #lastrows = 100000;
WHILE #InitialLoopCount <= #TotalLoopCount
BEGIN
WITH updateRows AS
(
SELECT
t1.*,
ROW_NUMBER() OVER (ORDER BY caster) AS seqnum
FROM
table1 t1
)
UPDATE updateRows
SET last_modified = ENDTIME AT TIME ZONE 'Central Standard Time'
WHERE last_modified IS NULL
AND updateRows.ENDTIME IS NOT NULL
AND updateRows.seqnum BETWEEN #intialrows AND #lastrows;
SET #AffectedRows = #AffectedRows + ##ROWCOUNT
SET #intialrows = #intialrows + 100000
SET #lastrows = #lastrows + 100000
-- COMMIT
SET #Remaining = #TotalRows - #AffectedRows
SET #InitialLoopCount = #InitialLoopCount + 1
END
This script determines the count of a table, divides it by 100000 and runs only that many loops to perform the entire update. It breaks down the update in batches/loops and then perform updates on certain rows until it completes updating them all.
This script is only for 1 table, i.e table1. I want to now modify this script in such a way that it dynamically takes all the tables in a schema and runs the above script for each of them. Let's say the schema name is schema1 and it has 32 tables, so this script should run for all those 32 tables.
I am able to retrieve the tables in schema1 but I am not able to dynamically send those to this script. Can anyone please help me with this?
To dynamically change table names at runtime you're going to need something like sp_executesql. See here for an example of its use: https://stackoverflow.com/a/3556554/22194
Then you could have an outer cursor that fetches the table names and then assembles the queries in a string and executes them. Its going to look horrible though.
If your schema doesn't change much another approach would be to generate a long script with a section for each table. You generate the script by querying the table names and then repeating the script with each different table name. Excel is actually pretty good for doing that sort of thing - paste your table names into Excel, use Excel to generate the script then copy/paste it back into SSMS.
This will be a long repetitive script but will avoid the disadvantage of having all the SQL in strings.

sql table trigger

I need to write a table trigger and I've never done this before. Here's what I'm trying to accomplish. Every time an order is placed with $0, I need the payment type to be set to 100. I run the below query manually, however it would be great if this was processed automatically.
UPDATE tblPay
SET lngPayTypeID = '100'
WHERE (lngFloatID IN (14171)) AND (dateWebDate > '5/25/18 6:00PM')
AND (curTender = '0')
Any help is greatly appreciated.
Generate the trigger SetPayment on table tblPlay:
CREATE TRIGGER [dbo].[SetPayment]
ON [dbo].[tblPlay]
AFTER INSERT
AS
DECLARE
#lngFloatID float,
#curTender decimal
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT
#lngFloatID = lngFloatID,
#curTender = curTender
FROM
inserted
IF (#curTender = 0)
BEGIN
UPDATE
tblPay
SET
lngPayTypeID = '100'
WHERE
lngFloatID = #lngFloatID
END
END
When a record with curTender = 0 is inserted, it will get its lngFloatID and set its lngPayTypeID to 100.

SQL Server slow stored procedure that deletes

I have written a stored procedure.
Now I see, that this is very poor performance.
I think this is because of the while loop.
ALTER PROCEDURE [dbo].[DeleteEmptyCatalogNodes]
#CatalogId UNIQUEIDENTIFIER,
#CatalogNodeType int = null
AS
BEGIN
SET NOCOUNT ON;
DECLARE #CID UNIQUEIDENTIFIER
DECLARE #CNT int
SET #CID = #CatalogId
SET #CNT = #CatalogNodeType
DELETE cn FROM CatalogNodes cn
LEFT JOIN CatalogNodes as cnj on cn.CatalogNodeId = cnj.ParentId
LEFT JOIN CatalogArticles as ca on cn.CatalogNodeId = ca.CatalogNodeId
WHERE cn.CatalogId = #CID
AND cnj.CatalogNodeId IS NULL
AND ca.ArticleId IS NULL
AND (cn.CatalogNodeType = #CNT OR #CNT IS NULL)
WHILE (##ROWCOUNT > 0)
BEGIN
DELETE cn FROM CatalogNodes cn
LEFT JOIN CatalogNodes as cnj on cn.CatalogNodeId = cnj.ParentId
LEFT JOIN CatalogArticles as ca on cn.CatalogNodeId = ca.CatalogNodeId
WHERE cn.CatalogId = #CID
AND cnj.CatalogNodeId IS NULL
AND ca.ArticleId IS NULL
AND (cn.CatalogNodeType = #CNT OR #CNT IS NULL)
END
END
Do anyone of you can give me a hint on how to do it more 'set' like?
Thanks a lot!
EDIT for comments and answers:
The tables are build like this:
CatalogNodes:
CatalogNodeId|ParentId|Name
1|NULL|Root
2|1|Node1
3|1|Node2
4|2|Node1.1
CatalogArticles:
CatalogNodeId|Name
3|Article1
3|Article2
3|Article3
After my SP was called, Node1 and Node1.1 have to be deleted.
In the first delete statement, Node1.1 will be deleted.
In the While loop, Node1 will be deleted.
I hope my problem is now easier to understand, it is a tree structure.
You just do not need WHILE part as all matched rows will get deleted from the first DELETE statement
your loop doesn't do anything ... the first delete statement will delete a number of records if there are any that comply to your where condition ... so ##rowcount will be greater than 0 but there won't be any records left to be deleted in your second delete statement inside the loop. or did I miss something?
anyway I don't think this executing delete two times in a row has a big influence on the performance ... you should see it if you look at the query plan ...
One way to do this in my point is to create a table variable and put all elements that you have to delete there and use i with join to make delete in one single statement.
CatalogNodes is what you want to delete. Create a select that pulls out all the CatalogNodes you want to get rid of. If there are things tied by foreign key constraints go and delete them first and finally once they are all gotten rid of Delete the CatalogNodes. Temporary tables could be of benefit here as they are held in memory.

Count Rows Error in Trigger

I wrote this trigger below. it is generating Error at COUNT(*) From. I want that when any row inserts into table 'Users' with this trigger currently present folders in Assignments should assign to User.
For Example: I add new row to table Users suppose userD. Then with the help of this trigger Present folders like folderA, folderB, folderC should assign to userD with folder right Visible by default. I have written this Trigger below but it is givig Error at Count(*) From
CREATE TRIGGER Trigger_Insert ON Users
FOR INSERT
AS
declare #userid int;
declare #username nvarchar(50);
declare #useremail nvarchar(50);
declare #userpassword nvarchar(50);
select #userid=i.user_id from inserted i;
select #username=i.user_name from inserted i;
select #useremail=i.user_email from inserted i;
select #userpassword=i.user_password from inserted i;
DECLARE #intFlag INT
SET #intFlag =1
WHILE (#intFlag <=COUNT(*) FROM Assignments;) // Error Here
BEGIN
insert into UAssignment_Rights(
ua_rights_id,ua_rights_name,assignment_id,user_id)
values(#userid,'Visible','','');
SET #intFlag = #intFlag + 1
PRINT 'AFTER INSERT trigger fired.'
END
GO
Can you please help me to solve this issue.
Answer updated to comply with info from comments.
My point is that most of the times you do not need loops or cursor in Sql Server. Usually set based approach is simpler and faster. In this case you might use form of insert that does not insert fixed values but rather result of select.
CREATE TRIGGER Trigger_Insert ON Users
FOR INSERT
AS
-- this is mandatory in trigger - you do not want ##rowcount reported to applications
-- to change as a result of statement in trigger (all of them, including set and select)
set nocount on
-- You can simply take assignment_id directly from Assignments table
insert into UAssignment_Rights(ua_rights_name, assignment_id, user_id)
select 'Visible', a.assignment_id, i.user_id
from Inserted i
cross join dbo.Assignments a
PRINT 'AFTER INSERT trigger fired.'
GO
P.S. cartesian product is result of join without join condition. Meaning that returned rows are all possible cobinations of each row from left table with each row from right table.
COUNT(*) should only be used as part of a SELECT or HAVING statement, see MSDN for more information on aggregate functions.
If Assignments will not change as part of the WHILE loop, try replacing...
WHILE (#intFlag <=COUNT(*) FROM Assignments;) // Error Here
With...
DECLARE #AssignmentsCount INT
SELECT #AssignmentsCount = COUNT(*) FROM Assignments
WHILE #intFlag <= #AssignmentsCount
This means that the COUNT(*) is only done once.
However, if the number of Assignments could change during the loop, the replace it with...
WHILE #intFlag <= (SELECT COUNT(*) FROM Assignments)

Multiple Row Update SQL Trigger from Single Update SQL Statement

Ok. I am quite new to SQL triggers and have had some issues with them. Insert trigger works just fine, and the Delete trigger also. At first, doing a delete on multiple rows would only delete one, but I managed to figure that one out for myself :)
However, even after extensive searching (here and on Google) I am unable to find a satisfactory answer to the UPDATE trigger that I have. If I do an update like
UPDATE Customers Set CustomerUser = 0 Where CustomerStatus = 3
Then unfortunately, only the one record would be updated, and the other would remain as they were. Obviously, this is no good.
The trigger I am using is:
ALTER TRIGGER [dbo].[TRG_TriggerName] ON [dbo].[USER_Customers]
FOR UPDATE
AS
declare #customerid int;
declare #customervenue int;
declare #customeruser int;
declare #customerarea int;
declare #customerevent int;
declare #customerproject int;
declare #customerstatus int;
select #customerid=i.CustomerID from inserted i;
select #customervenue=i.CustomerVenue from inserted i;
select #customerarea=i.CustomerArea from inserted i;
select #customerevent=i.CustomerEvent from inserted i;
select #customerproject=i.CustomerProject from inserted i;
select #customeruser=i.CustomerUser from inserted i;
select #customerstatus=i.CustomerStatus from inserted i;
Update USER_Instances Set InstanceArea = #customerarea, InstanceVenue = #customervenue, InstanceUser = #customeruser, InstanceStatus = #customerstatus, InstanceEvent = #customerevent, InstanceLastUpdate = GetDate() Where InstanceObject = 17 AND InstanceIdentity = #customerid
GO
As you will immediately realize, this trigger is great - if you want to update just one record. Otherwise, it fails. Now - the main question here would be - How do I catch all the records that need updating, and update them all in one trigger action.
The examples I have seen here on Stack Overflow confuse me somewhat, or seem ineffective - for instance, it seems most of them deal with updating just ONE value in a second/other table, and not a whole bunch like I am trying to do. The ones that appear to work on multiple values, I can not understand :(
So after about 2 hours of searches, I give up, and hope that you can help me :) I realize this is a trigger-newbie issue, and though I know my MS-SQL, triggers are something I have never used, until now. So any help is greatly welcome :)
W
It seems that you need something like this
ALTER TRIGGER [dbo].[TRG_TriggerName] ON [dbo].[USER_Customers]
FOR UPDATE
AS
UPDATE USER_Instances
SET InstanceArea = i.CustomerArea,
InstanceVenue = i.CustomerVenue,
InstanceUser = i.CustomerUser,
InstanceStatus = i.CustomerStatus,
InstanceEvent = i.CustomerEvent,
InstanceLastUpdate = GetDate()
FROM USER_Instances JOIN inserted i
ON InstanceIdentity = i.CustomerID AND InstanceObject = 17
Since inserted virtual table can contain multiple rows you need to JOIN it to correctly do your UPDATE.