Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
ALTER procedure [dbo].[proc_PostVisitCountInsert](
#postCount bigint,
#postID bigint)
as
Begin
if not exists(select * from PostVisitCount where postID=#postID)
Begin
Insert into PostVisitCount(postcount,postID) values(#postCount, #postID)
end
else
Begin
--Query for Update PostVisitCount
Declare #count bigint
Set #count=(select postcount from PostVisitCount where postID=#postID)
Update PostVisitCount set postcount=(#count+1), postID=#postID
End
end --Error getting at this place
When I try to execute the query, I'm getting error with these query. I don't understand what is wrong with this query any one helps me to figure out what did I do wrong.
The Begin End for ELSE does not contain any statement (it is actually commented out). That is the reason for the error. The following will work
ALTER procedure [dbo].[proc_PostVisitCountInsert](
#postCount bigint,
#postID bigint)
as
Begin
if not exists(select * from PostVisitCount where postID=#postID)
Begin
Insert into PostVisitCount(postcount,postID) values(#postCount, #postID)
end
else
Begin
Query for Update PostVisitCount
End
end --Error getting at this place
#user6503334: I am not sure whether my post would fix your issue but you can change the "else" part like the below since I felt there is something logically missing in your update statement. I have done a couple of changes in the else part. You should add where clause otherwise all the rows would be updated.
ALTER PROCEDURE [dbo].[proc_PostVisitCountInsert] (
#postCount BIGINT
,#postID BIGINT
)
AS
BEGIN
IF NOT EXISTS (
SELECT 1
FROM PostVisitCount
WHERE postID = #postID
)
BEGIN
INSERT INTO PostVisitCount (
postcount
,postID
)
VALUES (
#postCount
,#postID
)
END
ELSE
BEGIN
--Query for Update PostVisitCount
DECLARE #count BIGINT
SET #count = (
SELECT sum(postcount) + 1
FROM PostVisitCount
WHERE postID = #postID
)
UPDATE PostVisitCount
SET postcount = #count
WHERE postID = #postID
END
END
Since the one valid answer was given in a comment and not everybody reads those, the script should look like this:
ALTER procedure [dbo].[proc_PostVisitCountInsert](
#postCount bigint,
#postID bigint
)
as
Begin
if not exists (select *
from PostVisitCount
where postId = #postId)
Begin
insert into PostVisitCount(postcount,postID) values(#postCount, #postID)
end
else
Begin
--Query for Update PostVisitCount
update PostVisitCount set postcount = postcount + 1 where postID = #postID
End
end
Probably this should work.
ALTER procedure [dbo].[proc_PostVisitCountInsert](
#postCount bigint,
#postID bigint)
as
Begin
if not exists(select * from PostVisitCount where postID=#postID)
Insert into PostVisitCount(postcount,postID) values(#postCount, #postID)
else
--Query for Update PostVisitCount
end --Error getting at this place
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 months ago.
Improve this question
I'm running a batch update script where #masterNameID in (21,22,23) but I'm getting syntax errors when I run this snippet;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE
#MasterNameID AS INT in (21,22,23)
,#RowCount AS INT
I've tried declaring a temp table by using the below but still can't get it to run;
Declare #MasterNameTlb table (MasterNameID INT (5))
Insert into #MasterNameTlb (MasterNameID) values (21,22,23)
Set #MasterNameID AS INT = select MasterNameID from #MasterNameTlb
Any ideas on how to get this to run or if there's a more efficient way to declare multiple values for an update script?
**Edit:
Apologies, What I'm trying to do here is amend an update script that will update in batches of 20k where values in (21,22,23). I'm getting syntax errors when trying "in (21,22,23)". I also tried creating a temp table to pull the values from but still getting errors. Any help would be appreciated.
Full original script:
PRINT 'Shell_Index.SQL BEGIN'
If Object_ID('tempdb..#temp') Is Not Null
DROP Table #temp
GO
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE
#MasterNameID AS INT
,#RowCount AS INT
DECLARE #Begin int
DECLARE #End int
DECLARE #Buffer int
DECLARE #MaxRec INT
SELECT
et.ESTrackLogID
,et.ESFlagSync
,ROW_NUMBER() OVER (ORDER BY et.ESTrackLogID) AS rn
INTO #temp
FROM
tbl1.ESTrackLog AS et
JOIN tbl2 AS c ON c.ContactID = et.ESContactID
WHERE
et.MasterNameID = #MasterNameID
SELECT #RowCount = ##Rowcount
print Cast(#RowCount as nvarchar) + ' row(s) inserted into #temp'
SELECT #Begin = min(rn) from #temp
SELECT #MaxRec = max(rn) from #temp
SELECT #Buffer = 20000
SELECT #End = #Buffer
WHILE #Begin <= #MaxRec
BEGIN
BEGIN TRAN;
UPDATE
et
SET
et.ESFlagSync = 1
FROM
tbl1.ESTrackLog AS et
JOIN #Temp AS a ON a.ESTrackLogID = et.ESTrackLogID
WHERE
et.MasterNameID = #MasterNameID
AND a.rn BETWEEN #Begin and #End
SELECT #RowCount = ##Rowcount
print Cast(#RowCount as nvarchar) + ' row(s) updated in ESTrackLog'
COMMIT TRAN
if #RowCount > 0
BEGIN
WAITFOR delay '00:00:01';
END
SET #Begin = #End + 1
SET #End = #End + #Buffer
END
PRINT 'Shell_Index.SQL DONE'
It looks like you are trying to insert multiple values into a table variable. The correct syntax is:
Declare #MasterNameTlb table (MasterNameID INT); -- use primary key?
Insert into #MasterNameTlb (MasterNameID) values (21),(22),(23);
select MasterNameID
from #MasterNameTlb AS t;
It's unclear exactly what you want to do with this table, but you can join it like any other.
Try these:
DROP TABLE IF EXISTS [#MasterName];
GO
-- Example 1 into a TEMP table
Select [MasterName].[ID] INTO [#MasterName] FROM ( VALUES (21),(22),(23) )[MasterName]([ID]);
Select [TBL]= '[#MasterName]', * from [#MasterName];
-- Example 2 into a DECLARE table
Declare #MasterName TABLE ([ID] INT);
INSERT INTO #MasterName([ID])
Select [MasterName].[ID] FROM ( VALUES (21),(22),(23) )[MasterName]([ID]);
Select [TBL]= '#MasterName', * from #MasterName;
Are you trying to update some other table, not shown here, where a value is in (21,22,23)? Your temp table idea could work. After you create the temp table, you would do the update like this:
update mytable
set somecolumn = somevalue
where somekey in (
select * from #MasterNameTlb
);
If that's not what you trying to do, maybe add more detail to the question.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm trying to add a row to my table only on two conditions but when inserting it retrieves error and I cannot figure it out
Create PROC [dbo].[setvisitorqueue]
#pid bigint = null , #vid int = NULL ,#regdate nvarchar(50) =NULL
AS
declare #queNum int =null
set #queNum = (select max([ticketNo]) + 1 from [dbo].[queue] where [ticketdate]= GetDate())
if( #queNum is null) begin set #queNum=1 end
Declare #Tktt int = null
set #Tktt = (select count(queue.ticketid) from queue where (queue.pid = #pid )and (queue.ticketdate = GetDate()) and (queue.vid = #vid and queue.checked = 0))
if (#Tktt is null )
begin insert into queue (vid , pid , ticketNo , ticketdate ) Values (#Vid,#pid,#queNum,#regdate ) end
Its not working for me.
Can you try it simple way like this?
CREATE PROC [dbo].[setvisitorqueue]
#pid BIGINT = null,
#vid INT = NULL,
#regdate NVARCHAR(50) = NULL
AS
IF (
SELECT COUNT(ticketid)
FROM [dbo].[queue]
WHERE checked = 0 and pid = #pid and vid = #vid and ticketdate = GetDate()
) = 0
INSERT INTO [dbo].[queue](vid pid, ticketdate, ticketNo )
SELECT #Vid, #pid, #regdate, ticketNo = IsNull(MAX([ticketNo]),0) + 1
FROM [dbo].[queue]
WHERE [ticketdate]= GetDate();
RETURN;
GO
In this code I've done following:
Improved readability by Caps, intend, spaces, etc.
Eliminated variables - you do not need them in that code You do not
need to calculate a "TicketNo" in the beginning if it won't be used.
So, it will be calculated if needed within IF statement.
You do not need to use BEGIN-END on every transaction, single
request IS a transaction
Not sure what your error was, but your procedure won't do anything just because when you do "COUNT" it returns a number. That means your "#Tktt" variable would never be NULL.
I guess your intention is to run the Insert statement when it is no records found and compared "COUNT" query to "0" value.
Here is your SP with all the issues I spotted corrected with comments, and with best practices added. As noted by the other answer you can probably simplify things. I have just aimed to correct existing issues.
-- NOTES: Keep your casing and layout consistent
-- Always terminate statements with a semi-colon
-- Don't add un-necessary brackets, they just clutter the code
-- You also have a concurrency issue:
-- if this proc is called twice at the same time you could issue the same ticket number twice
create proc [dbo].[setvisitorqueue]
(
#pid bigint = null,
#vid int = null,
-- Only every use a datetime/date datatype to store a datatime/date. Datetime2 is the current standard. Change precision to suit.
#regdate datetime2(0) = null
)
as
begin
-- Always start your SP with
set nocount, xact_abort on;
declare #queNum int = null;
set #queNum = (
select max([ticketNo]) + 1
from dbo.[queue]
-- This seems very unlikely to happen? It has to match down to the fraction of a second.
where [ticketdate] = getdate()
);
if #queNum is null begin
set #queNum = 1;
end;
declare #Tktt int = null;
-- #Tktt will *never* be null after this, it may be zero though.
set #Tktt = (
select count(*)
from dbo.[queue]
where pid = #pid
-- This seems very unlikely to happen? It has to match down to the fraction of a second.
and ticketdate = getdate()
and vid = #vid and checked = 0
);
-- Handle 0 or null just in case
-- if #Tktt is null -- THIS IS WHAT PREVENTED YOUR INSERT
if coalesce(#Tktt,0) = 0
begin
insert into dbo.[queue] (vid, pid, ticketNo, ticketdate)
values (#Vid, #pid, #queNum, #regdate);
end;
-- Always return the status of the SP, 0 means OK
return 0;
end;
We have DVD Rental company. In this particular scenario we consider only Member, Rental and Membership tables.
The task is to write a trigger that prevents a customer from being shipped a DVD
if they have reached their monthly limit for DVD rentals as per their membership contract using the function.
My trigger leads to infinite loop. It works without While loop, but then it does not work properly, if I consider multiple updates to the Rental table. Where I am wrong?
-- do not run, infinite loop
CREATE OR ALTER TRIGGER trg_Rental_StopDvdShip
ON RENTAL
FOR UPDATE
AS
BEGIN
DECLARE #MemberId INT
DECLARE #RentalId INT
SELECT * INTO #TempTable FROM inserted
WHILE (EXISTS (SELECT RentalId FROM #TempTable))
BEGIN
IF UPDATE(RentalShippedDate)
BEGIN
IF (SELECT TotalDvdLeft FROM dvd_numb_left(#MemberId)) <= 0
BEGIN
ROLLBACK
RAISERROR ('YOU HAVE REACHED MONTHLY LIMIT FOR DVD RENTALS', 16, 1)
END;
END;
DELETE FROM #TempTable WHERE RentalID = #RentalId
END;
END;
My function looks as follows:
CREATE OR ALTER FUNCTION dvd_numb_left(#member_id INT)
RETURNS #tab_dvd_numb_left TABLE(MemberId INT, Name VARCHAR(50), TotalDvdLeft INT, AtTimeDvdLeft INT)
AS
BEGIN
DECLARE #name VARCHAR(50)
DECLARE #dvd_total_left INT
DECLARE #dvd_at_time_left INT
DECLARE #dvd_limit INT
DECLARE #dvd_rented INT
DECLARE #dvd_at_time INT
DECLARE #dvd_on_rent INT
SET #dvd_limit = (SELECT Membership.MembershipLimitPerMonth FROM Membership
WHERE Membership.MembershipId = (SELECT Member.MembershipId FROM Member WHERE Member.MemberId = #member_id))
SET #dvd_rented = (SELECT COUNT(Rental.MemberId) FROM Rental
WHERE CONCAT(month(Rental.RentalShippedDate), '.', year(Rental.RentalShippedDate)) = CONCAT(month(GETDATE()), '.', year(GETDATE())) AND Rental.MemberId = #member_id)
SET #dvd_at_time = (SELECT Membership.DVDAtTime FROM Membership
WHERE Membership.MembershipId = (SELECT Member.MembershipId FROM Member WHERE Member.MemberId = #member_id))
SET #dvd_on_rent = (SELECT COUNT(Rental.MemberId) FROM Rental
WHERE Rental.MemberId = #member_id AND Rental.RentalReturnedDate IS NULL)
SET #name = (SELECT CONCAT(Member.MemberFirstName, ' ', Member.MemberLastName) FROM Member WHERE Member.MemberId = #member_id)
SET #dvd_total_left = #dvd_limit - #dvd_rented
SET #dvd_at_time_left = #dvd_at_time - #dvd_on_rent
IF #dvd_total_left < 0
BEGIN
SET #dvd_total_left = 0
SET #dvd_at_time_left = 0
INSERT INTO #tab_dvd_numb_left(MemberId, Name, TotalDvdLeft, AtTimeDvdLeft)
VALUES(#member_id, #name, #dvd_total_left, #dvd_at_time_left)
RETURN;
END
INSERT INTO #tab_dvd_numb_left(MemberId, Name, TotalDvdLeft, AtTimeDvdLeft)
VALUES(#member_id, #name, #dvd_total_left, #dvd_at_time_left)
RETURN;
END;
Will be glad for any advice.
Your main issue is that even though you populate #TempTable you never pull any values from it.
CREATE OR ALTER TRIGGER trg_Rental_StopDvdShip
ON RENTAL
FOR UPDATE
AS
BEGIN
DECLARE #MemberId INT, #RentalId INT;
-- Move test for column update to the first test as it applies to the entire update, not per row.
IF UPDATE(RentalShippedDate)
BEGIN
SELECT * INTO #TempTable FROM inserted;
WHILE (EXISTS (SELECT RentalId FROM #TempTable))
BEGIN
-- Actually pull some information from #TempTable - this wasn't happening before
SELECT TOP 1 #RentalID = RentalId, #MemberId = MemberId FROM #TempTable;
-- Select our values to its working
-- SELECT #RentalID, #MemberId;
IF (SELECT TotalDvdLeft FROM dvd_numb_left(#MemberId)) <= 0
BEGIN
ROLLBACK
RAISERROR ('YOU HAVE REACHED MONTHLY LIMIT FOR DVD RENTALS', 16, 1)
END;
-- Delete the current handled row
DELETE FROM #TempTable WHERE RentalID = #RentalId
END;
-- For neatness I always drop temp tables, makes testing easier also
DROP TABLE #TempTable;
END;
END;
An easy way to debug simply triggers like this is to copy the T-SQL out and then create an #Inserted table variable e.g.
DECLARE #Inserted table (RentalId INT, MemberId INT);
INSERT INTO #Inserted (RentalId, MemberId)
VALUES (1, 1), (2, 2);
DECLARE #MemberId INT, #RentalId INT;
-- Move test for column update to the first test as it applies to the entire update, not per row.
-- IF UPDATE(RentalShippedDate)
BEGIN
SELECT * INTO #TempTable FROM #inserted;
WHILE (EXISTS (SELECT RentalId FROM #TempTable))
BEGIN
-- Actually pull some information from #TempTable - this wasn't happening before
SELECT TOP 1 #RentalID = RentalId, #MemberId = MemberId FROM #TempTable;
-- Select our values to its working
SELECT #RentalID, #MemberId;
-- IF (SELECT TotalDvdLeft FROM dvd_numb_left(#MemberId)) <= 0
-- BEGIN
-- ROLLBACK
-- RAISERROR ('YOU HAVE REACHED MONTHLY LIMIT FOR DVD RENTALS', 16, 1)
-- END;
-- Delete the current handled row
DELETE FROM #TempTable WHERE RentalID = #RentalId
END;
-- For neatness I always drop temp tables, makes testing easier also
DROP TABLE #TempTable;
END;
Note: throw is the recommended way to throw an error instead of raiserror.
Another thing to consider is that you must try to transform your UDF into an inline TVF because of some side effects.
Like this one:
CREATE OR ALTER FUNCTION dvd_numb_left(#member_id INT)
RETURNS TABLE
AS
RETURN
(
WITH
TM AS
(SELECT Membership.MembershipLimitPerMonth AS dvd_limit,
Membership.DVDAtTime AS dvd_at_time,
CONCAT(Member.MemberFirstName, ' ', Member.MemberLastName) AS [name]
FROM Membership AS MS
JOIN Member AS M
ON MS.MembershipId = M.MembershipId
WHERE M.MemberId = #member_id
),
TR AS
(SELECT COUNT(Rental.MemberId) AS dvd_rented
FROM Rental
WHERE YEAR(Rental.RentalShippedDate ) = YEAR(GETDATE)
AND MONTH(Rental.RentalShippedDate ) = MONTH(GETDATE)
AND Rental.MemberId = #member_id
)
SELECT MemberId, [Name],
CASE WHEN dvd_limit - dvd_rented < 0 THEN 0 ELSE dvd_limit - dvd_rented END AS TotalDvdLeft,
CASE WHEN dvd_limit - dvd_rented < 0 THEN 0 ELSE dvd_at_time - dvd_on_rent END AS AtTimeDvdLeft
FROM TM CROSS JOIN TR
);
GO
Which will be much more efficient.
The absolute rule to have performances is: TRY TO STAY IN A "SET BASED" CODE instead of iterative code.
The above function can be optimized by the optimzer whilet yours cannot and will needs 4 access to the same tables.
I've got a stored procedure that i'm having some issues with.
I'm trying to lookup against my table GOTWVotes and if VotedBy hasn't voted before write the vote to the table(this is working) however if VotedBy has voted before not to write to the table and return VoteCount as 1.
Although it doesn't write to the table when VotedBy exists the value of VoteCountalways appears to be 0
Any help would be appreciated
CREATE PROCEDURE [dbo].[Votes]
#VotedMember BIGINT,
#VotedBy BIGINT
AS
DECLARE #votecount INT
BEGIN TRY
BEGIN TRANSACTION t_Transaction
SELECT TOP 1 * FROM [GOTWVotes] WITH (TABLOCKX)
SELECT #votecount = COUNT(*) FROM [dbo].[GOTWVotes]
WHERE [VotedBy] = #VotedBy
IF #votecount = 0
INSERT INTO
[dbo].[GOTWVotes] ([VotedMember],[VotedBy])
VALUES
(#VotedMember, #VotedBy)
COMMIT TRANSACTION t_Transaction
END TRY
BEGIN CATCH
SET #votecount = -1
ROLLBACK TRANSACTION t_Transaction
END CATCH
RETURN #votecount
You can do following code
CREATE PROCEDURE [dbo].[Votes]
#VotedMember BIGINT,
#VotedBy BIGINT,
#votecount INT OUTPUT
AS
BEGIN TRY
BEGIN TRANSACTION t_Transaction
SET #votecount = 0
IF NOT EXISTS(SELECT 1 FROM [dbo].[GOTWVotes]
WHERE [VotedBy] = #VotedBy)
BEGIN
INSERT INTO
[dbo].[GOTWVotes] ([VotedMember],[VotedBy])
VALUES
(#VotedMember, #VotedBy)
END
ELSE
BEGIN
SELECT #votecount = COUNT(*) FROM [dbo].[GOTWVotes]
WHERE [VotedBy] = #VotedBy
END
COMMIT TRANSACTION t_Transaction
END TRY
BEGIN CATCH
SET #votecount = -1
ROLLBACK TRANSACTION t_Transaction
END CATCH
To Call above Stored procedure you need to write following code
DECLARE #votecount int
EXEC dbo.Votes #VotedMember = 0, -- bigint
#VotedBy = 0, -- bigint
#votecount = #votecount OUTPUT -- int
SELECT #votecount
This seems so complicated. I am thinking something like this:
CREATE PROCEDURE [dbo].[Votes] (
#VotedMember BIGINT,
#VotedBy BIGINT,
#retval int output
)
BEGIN
INSERT INTO dbo.GOTWVotes (VotedMember, VotedBy)
SELECT v.VotedMember, v.VotedBy
FROM (VALUES (#VotedMember, #VotedBy)) v(VotedMember, VotedBy)
WHERE NOT EXISTS (SELECT 1
FROM dbo.GOTWVotes gwv
WHERE gwv.VotedBy = v.VotedBy
);
SET #retval = ##ROWCOUNT;
END;
I suspect that what you want to do could also be handled with constraints.
I need to find out who is deleting / updating the data on table THETABLE, the time, using what program, and the command that is sent to the database that caused the modification.
From googling and asking some colleagues, the recommended way is on delete trigger. I know how to create trigger, for example:
create trigger whodunit
on THETABLE
for delete
as begin
insert into MyAuditTbl(moddate, ...
end
But how do I get the command that is sent to the DB (query / stored procedure), application name, IP address, etc.?
I found some script and customized it to fit my needs:
create trigger AuditTHETABLE
on THETABLE
for delete, update
as begin
set nocount on
declare #shouldlog bit, #insertcount bigint, #deletecount bigint
select
#shouldlog = 1,
#insertcount = (select count(*) from inserted),
#deletecount = (select count(*) from deleted)
-- if no rows are changed, do not log
if #insertcount < 1 and #deletecount < 1 begin
select #shouldlog = 0
end
-- ... other checks whether to log or not
if #shouldlog = 1 begin
-- prepare variable to capture last command
declare #buffer table (
eventtype nvarchar(30),
parameters int,
eventinfo nvarchar(4000)
)
-- use DBCC INPUTBUFFER to capture last command
-- unfortunately only the first 255 characters are captured
insert #buffer
exec sp_executesql N'DBCC INPUTBUFFER(##spid) WITH NO_INFOMSGS'
declare #lastcommand varchar(max)
select #lastcommand = eventinfo from #buffer
-- insert into audit table
insert into myauditlog(
eventdate, tablename, hostname,
appname, insertcount, deletecount, command
) values(
getdate(),
'THETABLE',
host_name(),
app_name(),
#insertcount,
#deletecount,
#lastcommand
)
end
end