Passing multiple params to stored procedure - sql-server

I trigger stored procedure and pass parameters from Visual Studio to SQL Server stored procedure.
Here is code:
var cId = new SqlParameter("#clientId", clientId);
var result = _context.Database.SqlQuery<DamageEventsDTL>("SPDamageEventsDTL #clientId", cId );
But I need to pass multiple parameters (int, DateTime and list of integers).
Here how I do it:
int clientId = 5;
DateTime date = new DateTime("2016-07-01");
List<int> list= new List<int>(new int[] { 2, 3, 5 });
var cId = new SqlParameter("#clientId", clientId);
var dateEvents = new SqlParameter("#date", date);
var freqEvents = new SqlParameter("#list ", list );
var result = _context.Database.SqlQuery<DamageEventsDTL>("SPDamageEventsDTL #cId, #date, #list ", cId, dateEvents, list);
But it seems to be wrong way.
Any idea what I do wrong here?

you can also use an XML to send parameters to SQL, like this:
USE tempdb
GO
DECLARE #Element XML;
SET #Element='
<SavedOrderElement>
<Data>
<Age>5</Age>
<Nit>46546546546</Nit>
<Name>Jeff</Name>
<LastName>Thalliens</LastName>
<Email>VerizonBoughtYahoo#yahoo.com</Email>
<PokemonGo>Nothing</PokemonGo>
</Data>
</SavedOrderElement>' ;
;WITH ElementSavedOrders
AS
(
SELECT
CAST(c.query('data(Age)') AS VARCHAR(50)) as Age
,CAST(c.query('data(Nit)') AS VARCHAR(50)) as Nit
,CAST(c.query('data(Name)') AS VARCHAR(50)) as Name
,CAST(c.query('data(LastName)') AS VARCHAR(50)) as LastName
,CAST(c.query('data(Email)') AS VARCHAR(100)) as Email
,CAST(c.query('data(PokemonGo)') AS VARCHAR(100)) as PokemonGo
FROM #Element.nodes('SavedOrderElement/*') as T(c)
)
SELECT * FROM ElementSavedOrders

Related

How to check if a list of comma separated string values match an integer?

Below I've added the SQL query.
I wanted retrieve the list of records that match a condition. I pass integer values into #ClassID and #SectionID parameters, The problem is ce.Class_ID and ce.Section_ID are lists of comma-separated string values.
SELECT ce.ID AS CircularEntryCount
FROM dbo.CircularEntry ce
WHERE ce.AcademicYearID = 1
AND (ce.Circular_Date = #CurrentDate OR CAST(ce.Created_Date AS date) = #CurrentDate)
AND (ce.CircularApplicableForID = 1 OR ce.CircularApplicableForID = 3)
AND (ce.Class_ID = #ClassID OR ce.Class_ID = '0')
AND (ce.Section_ID = #SectionID OR ce.Section_ID = '0')
PS: I used split string function to split the values into individual columns and compared the same with the parameters, but it shows.
Error converting data type nvarchar to bigint
(
#List nvarchar(2000),
#SplitOn nvarchar(1)
)
RETURNS #RtnValue table (
Id int identity(1,1),
Value nvarchar(100)
)
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select
Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
EN
The correct solution is to fix the problem - which means changing the structure of the database to not store delimited strings at all, but instead normalize the data and use foreign keys.
For more information, read Is storing a delimited list in a database column really that bad?, and not only the accepted answer by Bill Karwin, but other answers as well.
In case you can't change the database structure, you can use a workaround using like:
SELECT ce.ID AS CircularEntryCount
FROM dbo.CircularEntry ce
WHERE ce.AcademicYearID = 1
AND (ce.Circular_Date = #CurrentDate OR CAST(ce.Created_Date AS date) = #CurrentDate)
AND (ce.CircularApplicableForID = 1 OR ce.CircularApplicableForID = 3)
AND (','+ ce.Class_ID +',' LIKE '%,'+ CAST(#ClassID as varchar(20)) +'%,' OR ce.Class_ID = '0')
AND (','+ ce.Section_ID +',' LIKE '%,'+ CAST(#SectionID as varchar(20)) +'%,' OR ce.Section_ID = '0')
Note the cast to varchar(20) - bigint's min value contains a minus sign and 19 digits. If the data type of #ClassID or #SectionID is int, you can cast to varchar(11) instead.

Syntax issue using ON in a MERGE INTO statement

Intellisense error:
Msg 156, Level 15, State 1, Procedure Location_CVT_Insert, Line 19 [Batch Start Line 2]
Incorrect syntax near the keyword 'ON'.
Stored procedure code:
DROP PROCEDURE IF EXISTS [dbo].[Location_CVT_Insert]
GO
CREATE PROCEDURE [dbo].[Location_CVT_Insert]
(#Location_NotificationJson NVARCHAR(MAX))
AS
BEGIN
MERGE INTO Location_CVT AS C
USING (SELECT
deviceID, lastSeen, locationMapHierarchy, locationCoordinateX,
locationCoordinateY, locationCoordinateUnit, geoCoordinateLat,
geoCoordinateLong, geoCoordinateUnit
FROM
OPENJSON(#Location_NotificationJson)
WITH
(deviceId nchar(17),
lastSeen varchar(128),
locationMapHierarchy nvarchar(256),
locationCoordinateX float,
locationCoordinateY float,
locationCoordinateUnit nvarchar(64),
geoCoordinateLat float,
geoCoordinateLong float,
geoCoordinateUnit nvarchar(64)) AS InputJSON) ON (C.deviceId = InputJSON.deviceId)
WHEN MATCHED THEN
UPDATE
SET C.deviceId = InputJSON.deviceId,
C.lastSeen = InputJSON.lastSeen,
C.locationMapHierarchy = InputJSON.locationMapHierarchy,
C.locationCoordinateX = InputJSON.locationCoordinateX,
C.locationCoordinateY = InputJSON.locationCoordinateY,
C.locationCoordinateUnit = InputJSON.locationCoordinateUnit,
C.geoCoordinateLat = InputJSON.geoCoordinateLat,
C.geoCoordinateLong = InputJSON.geoCoordinateLong,
C.geoCoordinateUnit = InputJSON.geoCoordinateUnit
WHEN NOT MATCHED THEN
INSERT (deviceId, lastSeen, locationMapHierarchy,
locationCoordinateX, locationCoordinateY,
locationCoordinateUnit, geoCoordinateLat,
geoCoordinateLong, geoCoordinateUnit)
VALUES (InputJSON.deviceId, InputJSON.lastSeen, InputJSON.locationMapHierarchy,
InputJSON.locationCoordinateX, InputJSON.locationCoordinateY,
InputJSON.locationCoordinateUnit, InputJSON.geoCoordinateLat,
InputJSON.geoCoordinateLong, InputJSON.geoCoordinateUnit);
END
It seems that the ON statement is the problem. I'd like to select from a JSON object (SQL Server 2016) and if there is a match in my Location_CVT table on Device ID, update this entry, else insert a new record.
I am attempting to do something similar to the following example.
MERGE INTO Person AS P
USING (
SELECT *
FROM OPENJSON(#json)
WITH (id int, firstName nvarchar(50), lastName nvarchar(50),
age int, dateOfBirth datetime2) InputJSON
ON (P.id = InputJSON.id)
WHEN MATCHED THEN
UPDATE SET P.firstName = InputJSON.firstName,
P.lastName = InputJSON.lastName,
P.age = InputJSON.age,
P.dateOfBirth = InputJSON.dateOfBirth
WHEN NOT MATCHED THEN
INSERT (firstName, lastName, age, dateOfBirth)
VALUES (InputJSON.firstName, InputJSON.lastName, InputJSON.age,
InputJSON.dateOfBirth);
Source: https://www.codeproject.com/Articles/1087995/Inserting-JSON-Text-into-SQL-Server-Table
If, when you have parentheses that span multiple lines, you ensure that your open and close parentheses have consistent indentation, the issue becomes more clear (at least it does to me).
MERGE INTO Location_CVT AS C
USING
( SELECT
deviceID, lastSeen, locationMapHierarchy, locationCoordinateX,
locationCoordinateY, locationCoordinateUnit, geoCoordinateLat,
geoCoordinateLong, geoCoordinateUnit
FROM
OPENJSON(#Location_NotificationJson)
WITH
( deviceId nchar(17),
lastSeen varchar(128),
locationMapHierarchy nvarchar(256),
locationCoordinateX float,
locationCoordinateY float,
locationCoordinateUnit nvarchar(64),
geoCoordinateLat float,
geoCoordinateLong float,
geoCoordinateUnit nvarchar(64)
) AS InputJSON
) ------------------------------------------------- ISSUE IS HERE
ON (C.deviceId = InputJSON.deviceId)
WHEN MATCHED THEN
UPDATE
SET C.deviceId = InputJSON.deviceId,
C.lastSeen = InputJSON.lastSeen,
C.locationMapHierarchy = InputJSON.locationMapHierarchy,
C.locationCoordinateX = InputJSON.locationCoordinateX,
C.locationCoordinateY = InputJSON.locationCoordinateY,
C.locationCoordinateUnit = InputJSON.locationCoordinateUnit,
C.geoCoordinateLat = InputJSON.geoCoordinateLat,
C.geoCoordinateLong = InputJSON.geoCoordinateLong,
C.geoCoordinateUnit = InputJSON.geoCoordinateUnit
As you may now be able to see, your subquery that you are using for the source has no alias. It should be:
MERGE INTO Location_CVT AS C
USING
( SELECT
deviceID, lastSeen, locationMapHierarchy, locationCoordinateX,
locationCoordinateY, locationCoordinateUnit, geoCoordinateLat,
geoCoordinateLong, geoCoordinateUnit
FROM
OPENJSON(#Location_NotificationJson)
WITH
( deviceId nchar(17),
lastSeen varchar(128),
locationMapHierarchy nvarchar(256),
locationCoordinateX float,
locationCoordinateY float,
locationCoordinateUnit nvarchar(64),
geoCoordinateLat float,
geoCoordinateLong float,
geoCoordinateUnit nvarchar(64)
) AS InputJSON
) AS InputJSON -- ALIAS ADDED HERE
ON (C.deviceId = InputJSON.deviceId)
WHEN MATCHED THEN
UPDATE
SET C.deviceId = InputJSON.deviceId,
C.lastSeen = InputJSON.lastSeen,
C.locationMapHierarchy = InputJSON.locationMapHierarchy,
C.locationCoordinateX = InputJSON.locationCoordinateX,
C.locationCoordinateY = InputJSON.locationCoordinateY,
C.locationCoordinateUnit = InputJSON.locationCoordinateUnit,
C.geoCoordinateLat = InputJSON.geoCoordinateLat,
C.geoCoordinateLong = InputJSON.geoCoordinateLong,
C.geoCoordinateUnit = InputJSON.geoCoordinateUnit

Returning Output Parameters with Dapper for .NET Core

I'm struggling with how to properly map output parameters back to an object using Dapper, when I create DynamicParamters from a template object.
var parameters = new DynamicParameters(entity);
parameters.Add("#Id", dbType: DbType.Int32, direction: ParameterDirection.Output);
parameters.Output(entity, x => x.Id);
await conn.ExecuteAsync(
"TodoItemInsert", entity,
commandType: CommandType.StoredProcedure);
My hope was that the above code would map the resulting ID back into the entity that I created the parameters from in the first place. No matter what I try I am unable to get the parameter to return from the stored procedure. Calling parameters.Get<int>("#Id") throws a KeyNotFoundException. parameters.Get<int?>("#Id") returns null.
My SQL is a very basic insert sproc
ALTER PROCEDURE [dbo].[TodoItemInsert]
#Name VARCHAR(255)
, #Description VARCHAR(512)
, #DueDate DATETIME = NULL
, #IsComplete BIT = 0
, #Id INT OUTPUT
AS
INSERT INTO
[TodoItems]
(
Name
, Description
, DueDate
, IsComplete
)
VALUES
(
#Name
, #Description
, #DueDate
, #IsComplete
)
SET #Id = SCOPE_IDENTITY()
What is the correct way to get an output parameter back from Dapper when trying to use an object template for my DynamicParameters?
Figured this out, didn't properly update my code when I moved from template to parameters. I was passing entity into my query, not parameters. Once I replaced that I could even get rid of the explicit addition of the Id output parameter. This is much nicer!
var parameters = new DynamicParameters(entity);
parameters.Output(entity, x => x.Id);
await conn.ExecuteAsync(
"TodoItemInsert", parameters,
commandType: CommandType.StoredProcedure);

Stored procedure returns int value when the TSQL have full text search property

I have to use CONTAINS (full text search) in my stored procedure's query. So when I bind this stored procedure into my application through Entity Framework it returns an int value instead of a list of object.
EX:
Stored procedure:
ALTER PROCEDURE [dbo].[GetTableData]
(#UserId UNIQUEIDENTIFIER)
AS
BEGIN
SET NOCOUNT ON;
SELECT Column1, Column2
FROM TABLE1
WHERE Id = #UserId AND CONTAINS(Column1,'test')
END
Actual result:
public virtual int GetTableData(Nullable<System.Guid> userId)
{
var userIdParameter = userId.HasValue ?
new ObjectParameter("UserId", userId) :
new ObjectParameter("UserId", typeof(System.Guid));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<GetTableData_Result>("GetTableData", userIdParameter );
}
Expected result:
public virtual ObjectResult<GetTableData_Result> GetTableData(Nullable<System.Guid> userId)
{
var userIdParameter = userId.HasValue ?
new ObjectParameter("UserId", userId) :
new ObjectParameter("UserId", typeof(System.Guid));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<GetTableData_Result>("GetTableData", userIdParameter );
}
If I remove AND CONTAINS(Column1,'test') condition, it's working perfectly and gives the expected result.
I also tried with SET FMTONLY OFF options. That also not working.
How can I solve this problem?
Need to add any property or any other things in stored procedure?
Can anyone help me to solve this problem?
you need to create fulltext catalog on your table column.
here is reference.
https://msdn.microsoft.com/en-us/library/ms187787%28v=sql.110%29.aspx
Try this in your stored procedure:
SELECT Column1, Column2
FROM TABLE1 AS t1
WHERE Id = #UserId
AND EXISTS (SELECT
1 AS c1
FROM TABLE1 AS t2
WHERE (contains(t2.Column1,'test')) AND (t1.Id = t2.Id)
)

How to select output scalar values in sql server?

Hi I'm still new in TSQL. How can I output Scalar variables so that my vb code can access it?
in VB I use the rs method. In this case I will have to create 3 rs to be be able to access the data below. I would like to have a stored proc that can give me the 4 values I need without using multiple rs.
Create PROCEDURE [dbo].[sp_tblTransaction_GET_All_Totals]
#TransID bigint
AS
Declare #MyTotalCharges as money
Declare #MyTotalDiscounts as money
Declare #MyTotalPayments as money
Declare #TotalCharges as money
Declare #TotalDiscounts as money
Declare #TotalPayments as money
Declare #Balance as money
SELECT #MyTotalCharges = SUM(Amount)
FROM tblTransactionDetails
WHERE (TransID = #TransID)
SELECT #MyTotalDiscounts = SUM(Amount)
FROM tblTransaction_DP
WHERE (TransID = #TransID)
SELECT #MyTotalPayments = SUM(Amount)
FROM tblPayments
WHERE (TransID = #TransID)
--Below are the scalar values I need to be ouputed and accessed by my vb app.
--How can I output the values below?
#TotalCharges = #MyTotalCharges
#TotalDiscounts = #MyTotalDiscounts
#TotalPayments = #MyTotalPayments
#Balance = (#MyTotalCharges - #MyTotalDiscounts - #MyTotalPayments)
You need to return the values from the stored procedure as a table. Add this to your procedure.
SELECT
#TotalCharges as [Total Charges],
#TotalDiscounts as [Total Discounts],
#TotalPayments as [TotalPayments],
#Balance as [Balance]
Then you can execute the stored procedure from your VB app and load the table into a DataTable.
int transactionID = 0;
DataTable table = new DataTable();
using (var connection = new SqlConnection("connectionString")
using (var command = new SqlCommand("sp_tblTransaction_GET_All_Totals", connection)
{
connection.Open();
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#TransID", transactionID);
using (var adapter = new SqlDataAdapter(command))
{
adapter.Fill(table);
}
}
calling a stored procedure from C# using SqlDataAdapter
Here's the documentation on SqlDataAdapter, which will include examples in both C# and VB.
MSDN - SqlDataAdapter Class (System.Data.SqlClient)
Have you tried?
SELECT #Balance AS 'Balance', #TotalCharges AS 'TotalCharges' ...

Resources