Passing in variables to SQL Server stored procedure, where clause - stored-procedures

I am writing an application responsible for archiving data and we have the configuration in a database table
Id | TableName | ColumnName | RetentionAmountInDays
1 | DeviceData | MetricTime | 3
So when faced with this configuration, I should archive all data in the DeviceData table where the MetricTime value is before 3 days ago.
The reason I am doing this dynamically is the table names and column names differ (there would be multiple rows)
For each configuration this stored procedure is called
CREATE PROCEDURE GetDynamicDataForArchive
#TableName nvarchar(100),
#ColumnName nvarchar(100),
#OlderThanDate datetime2(7)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql nvarchar(1000);
SET #sql = 'SELECT * FROM ' + #TableName + ' WHERE ' + #ColumnName + ' < #OlderThanDate';
exec sp_executesql #sql;
END
And an example exec line
exec dbo.GetDynamicDataForArchive 'DeviceData', 'MetricTime', '2017-04-16 20:29:29.647'
This results in:
Conversion failed when converting date and/or time from character string.
So something is up with how I am passing in the datetime2 or how I am forming the where clause.

Replace this statement:
SET #sql = 'SELECT * FROM ' + #TableName + ' WHERE ' + #ColumnName + ' < #OlderThanDate'
by
SET #sql = 'SELECT * FROM ' + #TableName + ' WHERE [' + #ColumnName + '] < ''' + cast(#OlderThanDate as varchar(23)) + '''';
I don't particularly like having to convert the datetime to a varchar value though, perhaps there is a better way to do this(?).

Related

Zend 2 escaping single-quote

I am using Zend Framework 2 to generate the following escaped single-quote SQL query,
SELECT
`document`.*
FROM
`document`
WHERE
(
`document`.`document_taxon` LIKE '%Men\'s Health %' --escaped quote
AND `document`.`document_source_id` = ' 5 '
AND `document`.`document_published` = ' 1 '
AND `document`.`document_deleted` = ' 0 '
)
ORDER BY
`document_id` DESC
LIMIT 25 OFFSET 0
But I am getting this instead,
SELECT
`document`.*
FROM
`document`
WHERE
(
`document`.`document_taxon` LIKE '%Men's Health%'
AND `document`.`document_source_id` = ' 5 '
AND `document`.`document_published` = ' 1 '
AND `document`.`document_deleted` = ' 0 '
)
ORDER BY
`document_id` DESC
LIMIT 25 OFFSET 0
And here is my code
class DocumentTable extends TableGateway
{
....
$select=$this->getSql()->select();
$select->columns(array('*'));
$select->where
->NEST
->like('document_taxon', '%' . $label . '%')
->and
->equalTo('document_source_id', $sourceId)
->and
->equalTo('document_published', true)
->and
->equalTo('document_deleted', 0)
->UNNEST;
$select->order('document_id DESC');
$select->limit($limit);
$select->offset($offset);
...
}
I tried,
$this->getAdapter()->getPlatform()->quoteValue($string)
\Zend\Db\Sql\Expression("%". $label . "%")
str_replace("'", "\'", $label)
But I didn’t have much luck. I welcome any suggestion to solve this issue.
I worked it out. I was passing a normalized “label” value instead of the raw value. The above code snippet works fine.

IBM DB2 Equivalent syntax for SQL Server Stored Procedure - error while deploying

I am newbie to IBM db2.Need to convert the below mentioned SP to db2 syntax. But i am stuck with many equivalents used or available in Db2. Even google research doesn't show how exactly we can compare object id of tables in db2 as I am doing in SQL Server stored procedure. Could anyone suggest me with right way to proceed?
EDIT: I have updated with equivalent DB2 syntax, but facing below error while deploying at the particular line, Can anyone identify and help me understand what is wrong with this syntax or the problem lies anywhere else in the procedure.
line no 25 : DECLARE v_sqlstate CHAR(5);
BACKUPTABLE: 25: An unexpected token "<variable declaration> was found following "". Expected tokens may include: "".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.18.60
An unexpected token variable declaration was found following "". Expected tokens may include: "".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.18.60
SQL Server Stored procedure syntax:
CREATE PROCEDURE [dbo].[BackUpTable]
#TableName sysname
AS
BEGIN
SET nocount ON
DECLARE #sql VARCHAR(500)
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = Object_id(N'[dbo].[' + #TableName+'_EST' + ']')
AND TYPE IN ( N'U' ))
BEGIN
SET #sql = 'declare #Done bit
set #Done = 0
while #Done = 0
begin
delete top (100000)
from ' + #TableName + '_Bak' +
' if ##rowcount = 0
set #Done = 1
end;'
SET #sql = #sql + 'insert into ' + #TableName + '_Bak select * from ' +
#TableName +'_EST'
EXEC(#sql)
END
ELSE
BEGIN
DECLARE #err_message VARCHAR(300)
SELECT #err_message = 'The table "' + Isnull(#TableName, 'null') +
'" does not exist'
RAISERROR (#err_message, 16, 1)
END
END
DB2 SYNTAX CREATED SO FAR:
CREATE OR REPLACE PROCEDURE BackUpTable (IN TableName VARCHAR(128))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE dynamicSql VARCHAR(500);
IF(EXISTS(
SELECT * FROM SYSIBM.SYSTABLES
WHERE NAME = TableName||'_EST'
)
)
THEN
SET dynamicSql = 'DELETE FROM '||TableName ||'_BAK';
SET dynamicSql = dynamicSql ||'insert into ' || TableName || '_BAK select * from ' ||
TableName || '_EST';
EXECUTE IMMEDIATE dynamicSql;
ELSE
DECLARE v_sqlstate CHAR(5);
DECLARE v_sqlcode INT;
DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
DECLARE SQLCODE INT DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT SQLSTATE, SQLCODE
INTO v_sqlstate, v_sqlcode
FROM sysibm.sysdummy1;
SET O_Error_Msg = 'TABLE IS NOT AVAILABLE:: SQLState : '||v_sqlstate||' SQLCode : '||v_sqlcode ;
END;
END IF;
END
on z/os you can do it:
IF( EXISTS( SELECT 1 FROM QSYS2.SYSTABLES WHERE TABLE_SCHEMA = 'YOURLIB' AND TABLE_NAME = 'YOURTABLENAME')) THEN
DROP TABLE YOURLIB.YOURTABLENAME;
END IF;

How to get user name who updated the data from UI in MVC 5 and Entity Framework

We have a website in ASP.NET MVC 5 with Entity Framework.
When a logged in user made changes in UI (i.e. update the data) we save/update/delete the data in SQL Server as per operation performed by the user.
We also have a trigger for audit trailing.
With the trigger, table format for storing data is as below:
[AuditID]
[Type] -- Contains operation performed (Insert (I), Update (U), Delete (D))
[TableName]
[PK] -- Primary Key
[FieldName]
[OldValue]
[NewValue]
[UpdateDate]
[UserName]
We are storing SYSTEM_USER in [UserName] column.
If we have any solution to store the [UserName] who actually made changes from UI instead of system_user?
Do we have any approach to pass [UserName] from application (UI) to the trigger?
Please share your thoughts.
I have one solution - to add UpdatedBy column name in all the tables so that trigger can easily get the value of UpdatedBy column from magic tables or from main tables.
Please suggest best approach.
Below is the trigger used.
CREATE TRIGGER [ids].[tr_AuditEmploee]
ON Employee
FOR INSERT, UPDATE, DELETE
AS
DECLARE #bit INT,
#field INT,
#maxfield INT,
#char INT,
#fieldname VARCHAR(128),
#TableName VARCHAR(128),
#PKCols VARCHAR(1000),
#sql VARCHAR(2000),
#UpdateDate VARCHAR(21),
#UserName VARCHAR(128),
#Type CHAR(1),
#PKSelect VARCHAR(1000)
--You will need to change #TableName to match the table to be audited
SELECT #TableName = 'Employee'
-- date and user
SELECT
#UserName = SYSTEM_USER,
#UpdateDate = CONVERT(VARCHAR(8), GETDATE(), 112) + ' ' + CONVERT(VARCHAR(12), GETDATE(), 114)
-- Action
IF EXISTS (SELECT * FROM inserted)
IF EXISTS (SELECT * FROM deleted)
SELECT #Type = 'U'
ELSE
SELECT #Type = 'I'
ELSE
SELECT #Type = 'D'
-- get list of columns
SELECT * INTO #ins FROM inserted
SELECT * INTO #del FROM deleted
-- Get primary key columns for full outer join
SELECT
#PKCols = COALESCE(#PKCols + ' and', ' on')
+ ' i.' + c.COLUMN_NAME + ' = d.' + c.COLUMN_NAME
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE
pk.TABLE_NAME = #TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
-- Get primary key select for insert
SELECT
#PKSelect = COALESCE(#PKSelect+'+','')
+ '''' + COLUMN_NAME
+ '=''+convert(varchar(100),
coalesce(i.' + COLUMN_NAME +', d.' + COLUMN_NAME + '))+'''''
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE
pk.TABLE_NAME = #TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
IF #PKCols IS NULL
BEGIN
RAISERROR('no PK on table %s', 16, -1, #TableName)
RETURN
END
SELECT
#field = 0,
#maxfield = MAX(ORDINAL_POSITION)
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = #TableName
WHILE #field < #maxfield
BEGIN
SELECT #field = MIN(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
AND ORDINAL_POSITION > #field
SELECT #bit = (#field - 1 )% 8 + 1
SELECT #bit = POWER(2,#bit - 1)
SELECT #char = ((#field - 1) / 8) + 1
IF SUBSTRING(COLUMNS_UPDATED(),#char, 1) & #bit > 0 OR #Type IN ('I','D')
BEGIN
SELECT #fieldname = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
AND ORDINAL_POSITION = #field
SELECT #sql = '
insert [audit].[AuditEmployee] ( Type,
TableName,
PK,
FieldName,
OldValue,
NewValue,
UpdateDate,
UserName)
select ''' + #Type + ''','''
+ #TableName + ''',' + #PKSelect
+ ',''' + #fieldname + ''''
+ ',convert(varchar(1000),d.' + #fieldname + ')'
+ ',convert(varchar(1000),i.' + #fieldname + ')'
+ ',''' + #UpdateDate + ''''
+ ',''' + #UserName + ''''
+ ' from #ins i full outer join #del d'
+ #PKCols
+ ' where i.' + #fieldname + ' <> d.' + #fieldname
+ ' or (i.' + #fieldname + ' is null and d.' + #fieldname + ' is not null)'
+ ' or (i.' + #fieldname + ' is not null and d.' + #fieldname + ' is null)'
EXEC (#sql)
END
END

SQL Server CE - IMAGE column

I know that IMAGE datatype is deprecated since a while, but for my project I don't have the choice.
The question is: can I have several IMAGE columns in a table in SQL Server CE?
Because when I make an insert (ADO in Delphi) with more than 1 IMAGE column, my program hangs when I call ExecSQL().
With just one IMAGE column, it works:
HSLmySQL.ADOQuery1.SQL.Clear();
HSLmySQL.ADOQuery1.SQL.Add( 'INSERT INTO ' + CONFIG_Table_Name + ' SET ' +
CONFIG_Table[ aCONFIG_PARAM ] + '=' + ':param_blob'; + ' ;' );
HSLmySQL.ADOQuery1.Parameters.ParamByName('param_blob').LoadFromStream( Mstream1, ftBlob );
HSLmySQL.ADOQuery1.ExecSQL();
But with more than one IMAGE column:
HSLmySQL.ADOQuery1.SQL.Clear();
HSLmySQL.ADOQuery1.SQL.Add( 'INSERT INTO ' + CONFIG_Table_Name + ' SET ' +
CONFIG_Table[ aCONFIG_PARAM ] + '=' + ':param_blob', +
CONFIG_Table[ aCONFIG_SCHEDULES ] + '=' + ':schedules_blob'; + '
;' );
HSLmySQL.ADOQuery1.Parameters.ParamByName('param_blob').LoadFromStream( Mstream1, ftBlob );
HSLmySQL.ADOQuery1.Parameters.ParamByName('schedules_blob').LoadFromStream( Mstream2, ftBlob );
HSLmySQL.ADOQuery1.ExecSQL(); // => Boom, no exceptions catch nothing ..
and my program hangs.

SQL Server: Error in Cursorless stored procedure

I'm having trouble with this stored procedure, could you please help.
This is error I'm getting - running all this via Oracle Sql developer on SQL Server 2000 hosted elsewhere.
Error
Error starting at line 1 in command:
execute dbo.OF_ASEQ_EH_BROWNBIN 'dbo.EH_Brownbin_Josh','Match', 1
Error report:
Incorrect syntax near the keyword 'BEGIN'.
Procedure
ALTER PROCEDURE [dbo].[OF_ASEQ_EH_BROWNBIN]
#JvarTable Varchar(250),
#varColumn Varchar(250),
#optInterval int
AS
declare #Sql_string nvarchar(4000)
declare #myERROR int
declare #myRowCount int
declare #topseed int
declare #stg_topseed varchar(100)
-- Temp table for rows with nulls in specific column
declare #RowCnt int
declare #MaxRows int
declare #col_Name nvarchar(250)
declare #col_UPRN nvarchar(250)
declare #col_JoinedOn smalldatetime
begin
set #Sql_string = 'select top 1 ' + #varColumn + ' from ' + #JvarTable + ' order by convert(int, ' + #varColumn + ') desc'
set #stg_topseed = #Sql_string
set #topseed = convert(int, #stg_topseed)
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
select #RowCnt = 1
declare #Import table
(
rownum int IDENTITY (1, 1) Primary key NOT NULL ,
col_Name nvarchar(250),
col_UPRN nvarchar(250),
col_JoinedOn smalldatetime
)
set #sql_string = 'insert into #Import (col_Name, col_UPRN, col_JoinedOn) select Name, UPRN, JoinedOn from ' + #JvarTable + ' where ' + #varColumn +' is null'
exec #Sql_string
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
select #MaxRows=count(*) from #Import
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
-- Next new seed
select #topseed = #topseed + #optInterval
<br/>
while #RowCnt <= #MaxRows
begin
select #col_Name = col_Name from #Import where rownum = #RowCnt
select #col_UPRN = col_UPRN from #Import where rownum = #RowCnt
select #col_JoinedOn = col_JoinedOn from #Import where rownum = #RowCnt
set #Sql_string = 'update ' + #JvarTable + ' set ' + #varColumn + ' = cast((' + #topseed + ') as char) where Name = ''' + #col_Name + ''' and UPRN = ''' + #col_UPRN + ''' and JoinedOn = ''' + #col_JoinedOn + ''' '
exec (#Sql_string)
select #topseed = #topseed + #optInterval
Select #RowCnt = #RowCnt + 1
end
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
HANDLE_ERROR:
RETURN #myERROR
end
Whereas in Oracle, you need to have DECLARE - BEGIN - END, in MSSQL you do not have to use the BEGIN/END keywords on the procedure body.
Note that the label HANDLE_ERROR: is outside the BEGIN/END.
My guess is that removing the BEGIN (after the DECLARE block) and the END (before SELECT #myERROR=...), the error goes away.
Edit:
I guess I don't get the following statement:
set #Sql_string = 'select top 1 ' + #varColumn + ' from ' + #JvarTable + ' order by convert(int, ' + #varColumn + ') desc'
set #stg_topseed = #Sql_string
set #topseed = convert(int, #stg_topseed)
You assign a string var, copy the value to another string var, and, instead of executing the SQL statement, you cast the string var into an int. (?)
There were several errors in that code and there's probably a better, set based, way to solve the problem this stored procedure is for. (But that's another question and requires knowledge of the target tables that was not provided.)
The following code should be a step closer to what you're looking for.
Changes:
Edited suspicious code, cast((' + #topseed + ') as char) is that column really char? or is it varchar(something)?
Corrected logic around #topseed fetch.
Corrected logic around Import table use.
Corrected update SQL generation.
Removed extraneous Begin/ENDs.
Removed extraneous HTML (<br/>).
Wrapped procedure with Begin/END.
Added Go at the end.
Code:
ALTER PROCEDURE [dbo].[OF_ASEQ_EH_BROWNBIN]
#JvarTable Varchar(250),
#varColumn Varchar(250),
#optInterval int
AS
BEGIN
DECLARE #Sql_string nvarchar(4000)
DECLARE #myERROR int
DECLARE #myRowCount int
DECLARE #topseed int
DECLARE #stg_topseed varchar(100)
-- Temp table for rows with nulls in specific column
DECLARE #RowCnt int
DECLARE #MaxRows int
DECLARE #col_Name nvarchar(250)
DECLARE #col_UPRN nvarchar(250)
DECLARE #col_JoinedOn smalldatetime
SET #Sql_string = 'select top 1 #stg_topseed = ' + #varColumn + ' from ' + #JvarTable + ' order by convert(int, ' + #varColumn + ') desc'
EXEC SP_EXECUTESQL #Sql_string, N'#stg_topseed varchar(100) OUTPUT', #stg_topseed OUTPUT
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
SET #topseed = CONVERT(int, #stg_topseed)
/* Can't use a table variable with EXEC and/or SP_EXECUTESQL.
Therefore, forced to use a temporary table.
*/
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id('#Import') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
DROP TABLE #Import
CREATE table #Import
(
rownum int IDENTITY (1, 1) Primary key NOT NULL,
col_Name nvarchar(250),
col_UPRN nvarchar(250),
col_JoinedOn smalldatetime
)
SET #sql_string = 'insert into #Import (col_Name, col_UPRN, col_JoinedOn) select Name, UPRN, JoinedOn from ' + #JvarTable + ' where ' + #varColumn +' is null'
EXEC (#Sql_string)
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
SELECT #MaxRows=count(*) from #Import
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
-- Next new seed
SELECT #topseed = #topseed + #optInterval
SELECT #RowCnt = 1
WHILE #RowCnt <= #MaxRows
BEGIN
SELECT #col_Name = col_Name from #Import where rownum = #RowCnt
SELECT #col_UPRN = col_UPRN from #Import where rownum = #RowCnt
SELECT #col_JoinedOn = col_JoinedOn from #Import where rownum = #RowCnt
SET #Sql_string = 'update ' + #JvarTable + ' set ' + #varColumn + ' = ''' + CAST (#topseed AS varchar(250)) + ''' where Name = ''' + #col_Name + ''' and UPRN = ''' + #col_UPRN + ''' and JoinedOn = ''' + CAST(#col_JoinedOn AS varchar(250)) + ''' '
EXEC (#Sql_string)
SELECT #topseed = #topseed + #optInterval
SELECT #RowCnt = #RowCnt + 1
END
SELECT #myERROR = ##ERROR, #myRowCOUNT = ##ROWCOUNT
IF #myERROR != 0 GOTO HANDLE_ERROR
HANDLE_ERROR:
RETURN #myERROR
END
GO
I've been doing housekeeping on StackOverflow, and realised I hadn't (or accepted) answered the question I asked a long time ago. I couldn't remember which method/work-around I decided on, but I felt it's important to upload my accepted and working script, although I no longer need it.
Nevertheless, I sincerely hope this code will help the next person who has similar question to mine.
CREATE PROCEDURE [dbo].[OF_ASEQ_EH_BROWNBIN] #JvarTable nvarchar(250), #varColumn nvarchar(250), #optInterval int AS
/*
Procedure OF_ASEQ_EH_BROWNBIN
Created by Joshua White
When 20100902
Purpose To fill up column with new sequence numbers
Arguments JvarTable - Table name
varColumn - Column name
optInterval - Steps in increment in building new sequence (Should be 1 (one))
Example script to begin procedure
EXECUTE [dbo].[OF_ASEQ_EH_BROWNBIN] 'EH_Brownbin_Josh', 'Match', 1
PLEASE NOTE - Typically Stored Procedures are supposed to be flexible to work on
any tables, but due to complications with SQL Server 2000 and problems with
Cursors, we have to use manual scripts and this Stored Procedure will only work
on EH_BrownBin table ONLY.
Any questions about this, please send email to
<email deleted>
*/
declare #Sql_string nvarchar(4000)
declare #myERROR int
declare #myRowCount int
/* Fetching the last number in rows of table in question */
declare #topseed int
declare #stg_topseed varchar(100)
-- Temp table for rows with nulls in specific column
declare #RowCnt int
declare #MaxRows int
declare #rc int
declare #colu_Name nvarchar(250)
declare #colu_UPRN nvarchar(250)
declare #colu_JoinedOn smalldatetime
Begin
set #stg_topseed = 'select top 1 ' + #varColumn + ' from ' + #JvarTable + ' order by convert(int, ' + #varColumn + ') desc'
exec (#stg_topseed)
/* Begin collecting all rows with nulls in specified column */
select #RowCnt = 1
declare #Import table
(
rownum int IDENTITY (1, 1) Primary key NOT NULL ,
colu_Name nvarchar(250),
colu_UPRN nvarchar(250),
colu_JoinedOn smalldatetime
)
set nocount on
select #MaxRows = count(*) from #Import
-- Next new seed
select #stg_topseed = #stg_topseed + #optInterval
select #rc=0
while #RowCnt <= #MaxRows
begin
select #colu_Name = colu_Name from #Import where rownum = #RowCnt
select #colu_UPRN = colu_UPRN from #Import where rownum = #RowCnt
select #colu_JoinedOn = colu_JoinedOn from #Import where rownum = #RowCnt
set #Sql_string = 'update ' + #JvarTable + ' set ' + #varColumn + ' = ' + #stg_topseed + ' where Name = ''' + #colu_Name + ''' and UPRN = ''' + #colu_UPRN + ''' '
exec (#Sql_string)
select #stg_topseed = #stg_topseed + #optInterval
Select #RowCnt = #RowCnt + 1
end
print 'END'
end

Resources