SET #count = 0
SET #select = ''
WHILE #count < #c_count
BEGIN
SET #count = #count+1.
SET #select = #select+'cinema'+cast(#count AS VARCHAR)+'+'
END
SET #select = SUBSTRING(#select, 1, LEN(#select) - 1)
select #qty = qty from #qty
SET #buffer = 'UPDATE #table SET total_sales = '+#select
PRINT #buffer
EXEC(#buffer)
update #table set total_quantity = tq.qty from #table t inner join #qty tq on t.pkey =tq.id
here's my code in updating #table, i am having a problem putting the last update in #buffer,
help me pls.
My first question whenever I see someone doing this, is WHY?
If you are building up a SQL String and then trying to execute it, you are probably doing it wrong, and more than likely, you don't know enough of what you are doing that you can prevent SQL injection attacks.
Related
The problem is, sometimes in a day that no one is changing anything, a random user just enter the page and the trigger saves a change. The problem is, not only it logs a change that never has occurred in that day/moment(Because he/she didn't made a change), but it also gets a random data from INSERTED/DELETED, like we have a log of a change on may 5 2019 that has the date of change set in 2014, which is a long time ago.
My trigger is similar to this one below, just without personal information. We simulated this problem by making changes on a day, then trigger logs it correctly, after that we change the date on our computer, log in and wait a little bit, than it logs something random. Sometimes it takes a lot of time, and enter/exiting pages, but eventually something completely random appears from another date from long ago. Thanks for the help!
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[tablelog]
ON [dbo].[tablechanged]
AFTER UPDATE
AS
BEGIN
declare #OLD_DATA nvarchar(2000);
declare #NEW_DATA nvarchar(2000);
declare #Counter INT;
declare #Occurrences INT;
declare #col varchar(1000);
declare #SELECDELET nvarchar(2000);
declare #SELECINSER nvarchar(2000);
declare #user varchar(50);
declare #cod int;
declare #emp INT;
declare #isReg bit;
set #Occurrences = (SELECT COUNT(COLUMN_NAME) FROM information_schema.columns WHERE table_name = 'tablechanged')
set #Counter = 0;
set #user = (SELECT TOP 1 usuarioUltimaAlteracao FROM INSERTED);
set #emp = (SELECT TOP 1 empCodigo FROM INSERTED);
set #cod = (SELECT TOP 1 cedCodigo FROM INSERTED);
set #isReg = (SELECT TOP 1 alteracaoViaCadastro FROM INSERTED);
SELECT * INTO #Del FROM DELETED
SELECT * INTO #Ins FROM INSERTED
if(#isReg = 1)
begin
while #Counter < #Occurrences
begin
set #Counter = #Counter + 1;
set #col = (select COLUMN_NAME FROM information_schema.columns WHERE table_name = 'tablechanged' and ordinal_position = #Counter);
select #SELECDELET = 'SELECT #OLD_DATA='+#col+' FROM #Del' ;
select #SELECINSER = 'SELECT #NEW_DATA='+#col+' FROM #Ins' ;
exec sp_executesql #SELECDELET, N'#OLD_DATA nvarchar(40) OUTPUT', #OLD_DATA OUTPUT
exec sp_executesql #SELECINSER, N'#NEW_DATA nvarchar(40) OUTPUT', #NEW_DATA OUTPUT
if(#OLD_DATA <> #NEW_DATA)
begin
INSERT INTO TABLELOG (OPE_DATE,OPE_USER,OPE_TABLE,OPE_COD,OPE_EMP,OPE_FIELD,OPE,OLD_DATA,NEW_DATA)
VALUES (getdate(), #user, 'tablechanged', #cod, #emp, #col, 'UPDATE', #OLD_DATA,#NEW_DATA)
end
end
end
END
SQL Server triggers fire for every statement. Not for every row. Your trigger is obviously broken for the case of a multi-row update.
In the case of a multi-row update, the value of #NEW_DATA after running
SELECT #NEW_DATA='+#col+' FROM #Ins' ;
will be the last value in #Ins, and without an ORDER BY, it's undocumented which row it come from.
This is my code:
DECLARE #LoopCounter INT = 1,#max INT,#table nvarchar(100),#academic nvarchar(100)
SELECT #max = max(id)
FROM #tablelist
WHILE(#LoopCounter <= #max)
BEGIN
SET #table = (SELECT TABLE_NAME
FROM #tablelist WHERE id = #LoopCounter)
SET #academic = (SELECT F6
FROM #table WHERE F5 = Academic)
SET #LoopCounter = #LoopCounter + 1
END
where #tablelist is a list of all my tables in the database that are relevent.
The step:
SET #academic = (SELECT F6
FROM #table WHERE F5 = Academic)
does not work... I've tried with sp_execute but I get thrown back standard errors, at the moment the error is 'Must declare the standard variable '#table'. I have also tried an EXEC but it doesn't like that either.
What I want to do is define #academic to be a value from the #table The problem I'm having is the SET does not like being from #table.
Any help would be fab!
I think you want dynamic SQL:
DECLARE #LoopCounter INT = 1,
#max INT,#table nvarchar(100),
#academic nvarchar(100);
DECLARE #SQL NVARCHAR(MAX);;
SELECT #max = max(id)
FROM #tablelist;
WHILE(#LoopCounter <= #max)
BEGIN
SET #table = (SELECT TABLE_NAME FROM #tablelist WHERE id = #LoopCounter) ;
SET #SQL = '
SELECT #academic = F6
FROM [table]
WHERE f5 = 'Academic'
';
SET #SQL = REPLACE(#SQL, '[Table]', #table_name);
EXEC sp_executesql #SQL,
N'#academic NVARCHAR(100)',
#academic=#academic;
SET #LoopCounter = #LoopCounter + 1
END;
All that said, this is not an example of good coding (even ignoring the fact that I'm not escaping the table name).
You should not have multiple tables with the same columns, distinguished only by a variant of the name. Instead, you should have a single table with all the rows, and perhaps an additional column or two for identifying the columns.
Having to use dynamic SQL can illustrate a problem with the data model. And in this case, I think that it does.
I'm trying to increment a parameter set within my script by 1 every loop of my while.
This is an example of what I'm doing within my script:
DECLARE #I AS INT;
SET #I = 0;
DECLARE #SQL NVARCHAR(MAX)
SET #SQL =
'WHILE '+ Convert(Varchar, #I) +' < (SELECT statement here...)
BEGIN
SET '+ Convert(Varchar, #I) +' = '+ Convert(Varchar, (#I + 1))'
END'
There is a lot more to this script but this is the relevant part. I understand that '+ Convert(Varchar, #I) +' is just going to concatenate the value of #I to the string, but could anyone offer any advice in how I can make it so that the value of #I is incremented by 1.
Currently when executing the sql, the set command will end up like the following:
SET 0 = 0 + 1
where as I need it to change the actual variables value for the next loop.
Is this even possible?
You can use the '#I' as a variable in your query:
I'm trying to increment a parameter set within my script by 1 every loop of my while.
This is an example of what I'm doing within my script:
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = '
DECLARE #I AS INT;
SET #I = 0;
WHILE #I +' < (SELECT statement here...) +
'
BEGIN
SET #I = #I + 1
END'
I have a stored procedure that is called to establish sequence numbers for a specific client account. A simple table stores the last issued value for all clients and the SP will just take a parameter of SupplyChainID and how many numbers are required.
GetItemIDs
So SupplyChainID 12345 might have 5 as its last issued number, so running
GetItemIDs 12345,200
would return 5 and then set the value to 205 for next time
So the current SP does something like this as it has to check it does not go beyond 99,999,999. (goes back to 0 if it would go over)
IF (SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID) + #DocumentCount > 99999999
BEGIN
SELECT 0
UPDATE dbo.ItemIDGeneration SET EIBItemID = #DocumentCount,
LastIssuedDate = getdate() WHERE SupplyChainID = #SCID
END
ELSE
BEGIN
SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
UPDATE dbo.ItemIDGeneration SET EIBItemID = EIBItemID + #DocumentCount,
LastIssuedDate = getdate() WHERE SupplyChainID = #SCID
END
What I need to add is a check of another table to see if that has a higher value and in which case use that one instead of the last issued number from the ItemGeneration table
Something like this:
SELECT #HI_ID = MAX(EIBItemID) from
(SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
UNION ALL
SELECT ISNULL(MAX(EIBItemID),0) AS EIBItemID FROM dbo.SupplyChainID_'+ #tablename) as bigint
IF (#HI_ID) + #DocumentCount > 99999999
BEGIN
SELECT 0
UPDATE dbo.ItemIDGeneration SET EIBItemID=#DocumentCount,LastIssuedDate = getdate() WHERE SupplyChainID = #SCID END
ELSE
BEGIN
SELECT #HI_ID--EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
UPDATE dbo.ItemIDGeneration SET EIBItemID = #HI_ID +#DocumentCount,LastIssuedDate = getdate() WHERE SupplyChainID = #SCID
END
As you can see the table has the same SupplyChainID as part of the table name so I know I need to pass it in as part of a query and exec it but I can't get the following to work
SET #tablename = 'dbo.SupplyChain_'+#SCID
SET #tablequery = N'SELECT ISNULL(MAX(EIBItemID),0) AS EIBItemID FROM ' + #tablename
execute #tableID = sp_executesql #tablequery
SELECT #HI_ID = MAX(EIBItemID) from
(SELECT EIBItemID FROM ItemIDGeneration WHERE SupplyChainID = #SCID
union all
SELECT #tableID) as bigint
IF (#HI_ID) + #DocumentCount > 99999999
The process doesn't error but I think I have something wrong in my syntax as when I run the following
declare #return int
exec #return = GetItemIDs 8001377,20
select #return as result
I see EIBItemID returned as the correct result from the dbo.SupplyChain_xxxxx table but the return value from the end of the sp is the reply based on the ItemIDGeneration table (returns 200).
I think it's visibly returning the correct result when the exec is called but storing 0 in #tableid
You can try this to get the value:
DECLARE #SCID INT = 1
DECLARE #TableName NVARCHAR(100) = N'dbo.SupplyChain_' + CAST(#SCID AS NVARCHAR(10))
DECLARE #TableID BIGINT
DECLARE #TableQuery NVARCHAR(1000) = N'SELECT #TableID = ISNULL(MAX(EIBItemID), 0) FROM ' + #TableName
EXEC sp_ExecuteSql #TableQuery, N'#TableID BIGINT OUTPUT', #TableID OUTPUT
PRINT #TableID
Thanks to all that answered, I used Alex's suggestion with a small tweak
DECLARE #HI_ID as bigint
DECLARE #TableName NVARCHAR(100) = N'dbo.SupplyChain_' + CAST(#SCID AS NVARCHAR(10))
DECLARE #TableID BIGINT
DECLARE #TableQuery NVARCHAR(1000) = N'SELECT #TableID = ISNULL(MAX(EIBItemID),0) FROM ' + #TableName
EXEC sp_ExecuteSql #TableQuery, N'#TableID BIGINT OUTPUT', #TableID OUTPUT
SELECT #TableID As EIBItemID
I have to write a procedure which is able using a Table version to bring the database to a specific moment in type. For instance to move from version 1 to version 10 or the other way around. The thing is I'm pretty blurry with this chapter, and the school course has almost nothing about it. I tried using the internet to build a solution but somehow I got stuck. Please help me understand what am I doing wrong.
Table version, 1 columnm, type int
query
create procedure [dbo].[goto_vs] (
#vs int
)
as
begin
declare #current_vs int, #counter int;
declare #sqlquery nvarchar(50); --query to modify
declare #sqlsp nvarchar(30);
declare #sqlversion nvarchar(3);
declare #sqlreverse nvarchar(10);
--get the current version from table
select #current_vs=version from dbo.version;
--checking for valid version
if (#current_vs = #vs) begin
print('The database is already at this version...')
return
end
else begin
if (#vs > 5) begin
print('Setting the version of databse to last one...')
set #vs = 5
end
else begin
if (#vs < 0) begin
print('Setting the database to default...')
set #vs = 0
end
end
end
--setting up the string for exec
set #sqlsp = 'exec sp_create_table_awards'
--check if we go further or earlier in time
print('Changing database version...')
if (#vs > #current_vs) begin
set #sqlreverse = ''
goto upgrading
end
else begin
set #sqlreverse = 'undo_create_awards'
goto downgrading
end
--upgrading code
upgrading:
set #counter = #current_vs + 1
while (#counter <= #vs) begin
set #sqlquery = #sqlsp + cast(#counter as nvarchar(2)) + #sqlreverse
print(#sqlquery)
exec sp_executeSql #sqlquery
set #counter = #counter + 1
end
goto ending
downgrading:
set #counter = #current_vs
while (#counter > #vs) begin
set #sqlquery = #sqlsp + cast(#counter as nvarchar(2)) + #sqlreverse
print(#sqlquery)
exec sp_executeSql #sqlquery
set #counter = #counter - 1
end
goto ending
ending:
update dbo.version set version=#vs
print('Database version changed...')
end
Considering I figured a way, and have got no responses, I will post it as a response because it may help other students which studie computer science
To simplify I named all my procedures by this pattern do_x and undo_x where x is a int where do / undo _x are procedures which pair toughter for example do_1 and undo_1 create a table and destroy a table
ALTER PROCEDURE [dbo].[goto_vs]
-- Add the parameters for the stored procedure here
#v int = 0
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
declare #i int
declare #toexec nvarchar(70)
set #i = (select version from version)
-- If the requested version is lower than the current one, downgrade.
while(#i > #v)
BEGIN
set #i = #i - 1
set #toexec = 'Undo_' + CONVERT(varchar,#i);
exec sp_executeSql #toexec
print #toexec
END
-- Otherwise, upgrade.
while(#i < #v)
BEGIN
set #toexec = 'Update_' + CONVERT(varchar, #i);
exec sp_executeSql #toexec
set #i = #i + 1
print #toexec
END
END