Passing a variable from Access2010 to stored procedure - sql-server-2005

I have created an SSIS package that runs from the following stored procedure:
DECLARE #SQLQuery ASVARCHAR(2000)
DECLARE #ServerName VARCHAR(200)
SET #ServerName ='myServerName'
SET #SQLQuery ='DTExec /F ^"\\...\...\My_Package.dtsx^" '
EXEC master..xp_cmdshell #SQLQuery
I then have an Access2010 application with a few buttons that run 3 procedures all set up the same way running the package using the following code:
Dim conn As New ADODB.Connection
Dim cmd As New ADODB.Command
Dim sConnString As String
sConnString = "Provider=sqloledb; Server=MyServerName; Database=MyDB; Trusted_Connection=True; Integrated Security=SSPI;"
conn.Open sConnString
With cmd
.ActiveConnection = conn
.CommandType = adCmdText
.CommandText = "EXEC my_sproc;"
Now I need to add text boxes to two of the buttons that trigger the procedures where a user will enter a file name. The button needs to pass that file name to the stored procedure and the stored procedure needs to then use it in the package.
Any suggestions are greatly appreciated. This is my first time doing something like this and I am a little lost.
Thanks,
Scott
UPDATE:
I altered my procedure and it works with the temporary value in the procedure for #FileName. I am not sure now how to get the value from Access into the #FileName variable though.
DECLARE #cmd VARCHAR(1000)
DECLARE #SSISPath VARCHAR(1000)
DECLARE #FilePath VARCHAR(1000)
DECLARE #FileName VARCHAR(1000)
SET #SSISPath = '\\Server\...\...\...\...\Package.dtsx'
SET #FilePath = '\Server\...\...\...\'
SET #FileName = 'myImportFile.txt' --temp value - need to get value from Access form text box
SELECT #cmd = 'dtexec /f "' + #SSISPath + '"'
SELECT #cmd = #cmd + ' /SET \Package.Variables[User::FileName].Properties[Value];"' + #FilePath + #FileName + '"'
EXEC master..xp_cmdshell #cmd

You need to make #FileName an input parameter ...
ALTER PROCEDURE my_sproc
-- input parameter:
#FileName VARCHAR(1000)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cmd VARCHAR(1000)
DECLARE #SSISPath VARCHAR(1000)
DECLARE #FilePath VARCHAR(1000)
SET #SSISPath = '\\Server\...\...\...\...\Package.dtsx'
-- and so on
... and then call the stored procedure with a parameter, along the lines of the following
With cmd
.ActiveConnection = conn
.CommandType = adCmdStoredProc
.CommandText = "my_sproc"
.Parameters.Append cmd.CreateParameter("#FileName", adVarChar, adParamInput, 1000, Me.SomeTextBox.Value)
.Execute
End With

Related

Why is my stored procedure working fine when executed manually, but not when called from another SP?

I have a stored procedure which performs following steps: it updates a default values table for the software, and just runs a powershell cmdlet which is reload tradeloader defaults
The stored procedure takes a parameter like DefaultValue=ABC, where DefaultValue is the field that needs to be changed, and ABC be the value updated.
Now, this runs perfectly fine, when executed manually, but when I pass it from another stored procedure which does a lot of functions including running some other powershell commands, it fails; in fact, just locks the database and keeps running.
I am new to SQL, so I haven't tried much other than try catch and begin tran, commit tran etc.. but none work
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Procedure [dbo].[changeDefaultSettings]
(#DefaultChange NVARCHAR(MAX))
AS
BEGIN;
BEGIN TRAN;
SET NOCOUNT ON;
DECLARE #DefaultField NVARCHAR(300)
DECLARE #DefaultValue NVARCHAR(1000)
DECLARE #PSString NVARCHAR(4000)
DECLARE #IPAdd NVARCHAR(50)
DECLARE #Port NVARCHAR(20)
DECLARE #FilePath NVARCHAR(1000)
DECLARE #FileName NVARCHAR(1000)
DECLARE #Hostname NVARCHAR(50)
DECLARE #SQL_Powershell NVARCHAR(4000)
DECLARE #CurrentDerivationRelease NVARCHAR(100)
SET #DefaultField = (SELECT [Item]
FROM Automation.config.fnsplit(#DefaultChange, '=')
WHERE [ID] = 1)
SET #DefaultValue = (SELECT [Item]
FROM Automation.config.fnsplit(#DefaultChange,'=')
WHERE [ID] = 2)
SET #DefaultValue = CONVERT(INT, #DefaultValue)
IF (#DefaultChange = 'Reset')
BEGIN
UPDATE Derivation_Automation.dbo.TradeLoaderSetting
SET iValue = -1
WHERE vc40Name NOT IN ('DefaultTrader', 'DifferentAccountPerAssetClass')
UPDATE Derivation_Automation.dbo.TradeLoaderSetting
SET iValue = (SELECT idsystemuser
FROM Derivation_Automation.dbo.systemuser
WHERE vc30Name = 'Admin')
WHERE vc40Name = 'DefaultTrader'
UPDATE Derivation_Automation.dbo.TradeLoaderSetting
SET iValue = 0
WHERE vc40Name = 'DifferentAccountPerAssetClass'
END
ELSE
BEGIN
UPDATE Derivation_Automation.dbo.TradeLoaderSetting
SET iValue = #DefaultValue
WHERE vc40Name = #DefaultField
End
Set #Hostname = (Select HOST_NAME())
Set #IPAdd = (Select GlobalVariables.VariableValue from Automation.dbo.GlobalVariables where GlobalVariables.VariableName = 'PowerShellIP')
If (#Hostname = 'MU1QA01')
Begin
Set #Port = (Select GlobalVariables.VariableValue from Automation.dbo.GlobalVariables where GlobalVariables.VariableName = 'PowerShellPort1')
End
Else IF (#Hostname = 'MU1QA02')
Begin
Set #Port = (Select GlobalVariables.VariableValue from Automation.dbo.GlobalVariables where GlobalVariables.VariableName = 'PowerShellPort2')
End
Set #FilePath = (Select GlobalVariables.VariableValue from Automation.dbo.GlobalVariables where GlobalVariables.VariableName = 'PowerShellFilePath')
Set #FileName = (Select GlobalVariables.VariableValue from Automation.dbo.GlobalVariables where GlobalVariables.VariableName = 'DefaultChangepowerShellFile')
Set #CurrentDerivationRelease = (Select GlobalVariables.VariableValue from Automation.dbo.GlobalVariables where GlobalVariables.VariableName = 'DerivationRelease')
Set #FilePath = '\\'+#Hostname+'\'+#FilePath
Set #PSString = 'import-module "C:\PROGRA~1\' + #CurrentDerivationRelease + '\DerivationPowershellModuleTradeLoader\Core.PowershellModule.TradeLoader.dll" -Verbose'
+ char(13) + char(10) +'Invoke-ReloadTradeLoaderDefaults -IPAddress ' + #IPAdd + ' -Port ' + #Port
Exec [dbo].[spWriteStringToFile] #PSString,#FilePath,#FileName
Set #FilePath = ''''+#FilePath + '\' + #FileName+''''
Set #SQL_Powershell = 'c:\PROGRA~1\PowerShell\6\pwsh.exe -Command Invoke-Command -ComputerName '+#hostname+ ' -ScriptBlock { c:\PROGRA~1\PowerShell\6\pwsh.exe -File '+#FilePath+ ' }'
Print(#SQL_Powershell)
EXEC master..xp_cmdshell #SQL_Powershell,no_output
WAITFOR DELAY '00:00:2'
SET nocount off;
Commit Tran;
End;

Error When Running Stored Procedure From VBA

I am using VBA to pull information from SQL Server. To not make things complicated read this:
"I have a Stored Procedure in SQL that receiving a Date (#NeededDate as Date) & a comma delimited text (#DelimitedAssets as NVARCHAR(MAX) returns the required results.
When I run my code in VBA, IT WORKS when the text I'm passing (#DelimitedAssets) is not longer than 7000 characters (that's not the exact number but is close). So, rephrasing this: the code works as expected if the string is not big.
But the text I'm passing to the Stored Procedure from VBA adds up to 12000 characters. NVARCHAR should be able to handle that but is not doing it when I pass it from VBA.
IMPORTANT: if I run the same chunk of data (12000 characters) from SQL Server Management Studio, it works perfectly. No errors and the data is ok.
ERROR OCCURS IN LINE:
Set oRecordSet = .Execute
VBA CODE*
Private Function RunMonthlyPricesSP(ByVal strDate As String, ByRef strAssetsDelimted As String, ByRef cnAccounting As Object, ByRef rDestination As Range) As Variant
Dim oCmd As ADODB.Command
Dim oRecordSet As ADODB.Recordset
Dim ActivityParam As ADODB.Parameter
Dim varPrices As Variant
Dim strAction As String
Set oCmd = New ADODB.Command
Set oRecordSet = New ADODB.Recordset
With oCmd
.ActiveConnection = cnAccounting
.CommandType = adCmdStoredProc
.CommandText = "Usp_bondselectionprices"
.Parameters("#NeededDate").Value = strDate
.Parameters("#DelimitedAssets").Value = strAssetsDelimted
Set oRecordSet = .Execute
End With
' Return Array.
' Pending.
End Function
SQL STORED PROCEDURE*
GO
/****** Object: StoredProcedure [dbo].[Usp_bondselectionprices] Script Date: 4/13/2018 5:41:57 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Usp_bondselectionprices] #NeededDate DATE,
#DelimitedAssets VARCHAR(max)
AS
BEGIN
DECLARE #TblBuysSelectionBond BUYSSELECTIONBONDS
INSERT INTO #TblBuysSelectionBond
SELECT *
FROM dbo.Splittext(#DelimitedAssets)
SELECT CASE
WHEN Prices.Price * CurrencyPrices.Price IS NULL THEN Prices.Price
ELSE Prices.Price * CurrencyPrices.Price
END AS Price,
Assets.AssetName
FROM Prices
INNER JOIN Assets
ON Prices.AssetID = Assets.AssetID
INNER JOIN Assets AS Currencies
ON Assets.CurrencyID = Currencies.AssetID
LEFT OUTER JOIN Prices AS CurrencyPrices
ON Currencies.AssetID = CurrencyPrices.AssetID
AND Prices.PriceDate = CurrencyPrices.PriceDate
WHERE prices.PriceDate = #NeededDate
AND assets.InstrumentTypeID = 4
AND Assets.AssetName IN (SELECT *
FROM #TblBuysSelectionBond)
END
FUNCTION CALLED FROM STORED PROCEDURE TO CONVERT TEXT DELIMITED INTO A TABLE*
GO
/****** Object: UserDefinedFunction [dbo].[Splittext] Script Date: 4/13/2018 6:10:02 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[Splittext] (#input AS VARCHAR(max))
RETURNS #Result TABLE(
Value VARCHAR(max))
AS
BEGIN
DECLARE #str VARCHAR(max)
DECLARE #ind bigint
IF( #input IS NOT NULL )
BEGIN
SET #ind = Charindex(',', #input)
WHILE #ind > 0
BEGIN
SET #str = Substring(#input, 1, #ind - 1)
SET #input = Substring(#input, #ind + 1, Len(#input) - #ind)
INSERT INTO #Result
VALUES (#str)
SET #ind = Charindex(',', #input)
END
SET #str = #input
INSERT INTO #Result
VALUES (#str)
END
RETURN
END
Remember, this works for for small string delimited text. So we know that my connection and other arguments are OK.
Thanks,
Ok. I found the solution and it's very, very easy. This is why is so important to check the Watch windows to understand what your Objects (oCMD in this case) has inside.
By default it was taking the parameter #DelimitedAssets as adVarChar. You need to specify that it's not a adVarChar but an adLongVarChar.
.Parameters("#DelimitedAssets").Value = strAssetsDelimted
.Parameters("#DelimitedAssets").Type = adLongVarChar
Once I changed this, everything worked as expected.
Hope this helps.
have you tried to specify type&size?
param.SqlDbType = SqlDbType.VarChar;
param.Size = -1;

SQL Server dynamic procedure 2

USE KronosNET22
GO
Create procedure eventossucursales4
#id nvarchar(max),
#dia nvarchar(max)
as
begin
declare #sqlstring nvarchar(max)
set #sqlstring = 'Select Code From ' + #dia + ' WHERE idObject = ''' + #id + ''' AND (CODE = ''TFHi2'' OR CODE = ''E603'')'
EXEC sp_executesql #sqlstring, #id,#dia
end
GO
Execute eventossucursales4 'E4211537-09CD-45F2-BB5F-F20F642DE676','ObjectSignal_2016_05_23 '
Error:
Mens. 102, Nivel 15, Estado 1, LĂ­nea 1
Sintaxis incorrecta cerca de 'E4211537'.
Can someone help me to figure it out why its showing a mistake in the declaration of the variable?
You could eliminate passing the parameters as someone commented. If you want to make it work as is, you need to add the parameter list. I was able to get it working this way.
alter procedure eventossucursales4
#id nvarchar(max),
#dia nvarchar(max)
as begin
declare #sqlstring nvarchar(max)
declare #ParmDefinition nvarchar(500) = '#dia nvarchar(max), #id nvarchar(max)'
set #sqlstring = 'Select Code From ' + #dia + ' WHERE idObject = ''' + #id + ''' AND (CODE = ''TFHi2'' OR CODE = ''E603'')'
exec sp_executesql #sqlstring, #ParmDefinition, #id = #id, #dia = #dia
end
GO
Execute eventossucursales4 'E4211537-09CD-45F2-BB5F-F20F642DE676','ObjectSignal_2016_05_23 '

Alter Database in Stored Procedure

I'm trying to create a new stored procedure to execute an Alter Database command to modify the database Service Tiers.
So, I've tried to create the stored procedure but It doesn't work and it returns an error
Incorrect syntax near '('.
Could someone tell me how can I do this? Or where is the syntax error?
I've run this one out of any stored procedure and it worked.
Thanks in advance.
create procedure spChangeTiersDB
#MaxSize varchar(8),
#Edition varchar(20),
#Service varchar(5)
as
begin
ALTER DATABASE DB_Name
MODIFY (
MAXSIZE = #MaxSize,
EDITION = #Edition,
SERVICE_OBJECTIVE = #Service)
end
You cannot parameterize ALTER DATABASE statements
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/578d87fa-9939-4cb0-bb72-e37cee8abf25/can-i-pass-parameter-to-an-alter-database-command
As suggested on the MSDN forum link, use Dynamic SQL instead
CREATE PROCEDURE spChangeDBtier
#MaxSize VARCHAR(10),#Edition VARCHAR(10),#Service VARCHAR(10) AS BEGIN
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = CONCAT('ALTER DATABASE dbname MODIFY ( MAXSIZE =',#MaxSize,'GB, Edition = ''',#Edition,''',SERVICE_OBJECTIVE = ''',#Service,''')')
EXEC(#SQL)
END
Sample execution:
spChangeDBtier '500','PREMIUM','P1'
It seems we can't do those changes with something unattended like stored procedures, functions, etc. So, I've made something in C# to change from the server. That's my answer at the moment. If someone else has the same problem here is the code to help.
public static bool ChangeDBTier(string DbName, string MaxSize, string Edition, string Service)
{
try
{
using (SqlConnection con = new SqlConnection(ConnectionString))
{
con.Open();
String sqlCommandText = #"ALTER DATABASE " + DbName + " MODIFY (MAXSIZE = " + MaxSize + ", EDITION = '" + Edition + "', SERVICE_OBJECTIVE = '" + Service + "')";
SqlCommand sqlCommand = new SqlCommand(sqlCommandText, con);
sqlCommand.ExecuteNonQuery();
}
return true;
}
catch
{
return false;
}
}
CREATE PROCEDURE #spChangeDBtier
#MaxSize VARCHAR(10),#Edition VARCHAR(10),#Service VARCHAR(10) AS BEGIN
DECLARE #SQL NVARCHAR(MAX)
set #sql = 'alter database test modify(maxsize = '+ #MaxSize + ', edition = ''' + #MaxSize + ''' , service_objective = ''' + #MaxSize + ''')'
EXEC #SQL
END
You can always specify max size but I don't think that is needed as size won't impact billing significantly

Parametrize query in t-sql

SELECT TOP #columnCount #columnName
FROM #tableName
I get the following error
Incorrect syntax near '#columnCount'.
What could be wrong?
If I change to
SELECT TOP (#columnCount) #columnName
FROM #tableName
I get the following error
Must declare the table variable "#tableName".
I run it from C#
A safe and secure way would be
DECLARE #columnCount INT = 100
DECLARE #columnName NVARCHAR(128) = 'YourColumnName'
DECLARE #tableName NVARCHAR(128) = 'YourTableName'
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'SELECT TOP (#columnCount) ' + QUOTENAME(#columnName) + N'
FROM ' + QUOTENAME(#tableName)
EXECUTE sp_executesql #Sql
,N'#columnCount INT'
,#columnCount
You need dynamic SQL to accomplish what you're trying to do.
DECLARE #sql VARCHAR(max);
SET #sql = 'SELECT TOP ' + #columnCount + ' ' + #columnName + ' FROM ' + #tableName;
EXEC(#sql);
The variables used need to be converted appropriately.
Read more in the documentation
Column lists and Table names cannot be parameters. However, since you are running this from C# you are technically already using Dynamic SQL (unless you are calling a stored procedure with those params but there is no mention here of stored procedures being used so for now I will assume not). When building the SQL in C#, you need to concatenate the Column List and Table Name into the query but you can still use a parameter for the value used by the TOP() operator:
SqlConnection _Connection = new SqlConnection("connection string");
SqlCommand _Command = new SqlCommand();
SqlDataReader _Reader = null;
string _Query;
string _TableName = "dbo.MyTable";
string _ColumnList = "Field1, Field2 AS [AliasedName], Field3";
int _NumberOfRows = 12;
_Query = String.Concat("SELECT TOP (#NumberOfRows) ",
_ColumnList, " FROM ", _TableName);
SqlParameter _NumRows = new SqlParameter("#NumberOfRows", SqlDbType.Int);
_NumRows.Value = _NumberOfRows;
try
{
_Connection.Open();
_Reader = _Command.ExecuteReader();
// do stuff
}
finally
{
_Reader.Close();
_Connection.Close();
}
Of course, you could also just concatenate the #NumberOfRows value directly into the query as well, but keeping it as a parameter will allow for Query Plan re-use if running this query multiple times with the same values for ColumnList and TableName but changing the #NumberOfRows value.