How to select output scalar values in sql server? - 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' ...

Related

Finding NULL column names in SQL Server

In SQL Server, is there any quick way to find out null column names for a particular record other than using CASE expression?
For eg:
I have one record whose values are like:
id|FName|LName|Dept
1 |NULL |Smith|NULL
Expected result is: FName, Dept
So, every time I will have only one record and I need to find the list of NULL columns for it.
if it's just a result set then you can't do it in sql-server.
but you can use other language making a query tool to do it like below C# code :
void Main(){
var nullColumnsName = GetNullColumnsName("select 1 id,null FName,'Smith' LName ,null Dept");
Console.WriteLine(nullColumnsName); //result : FName,Dept
}
IEnumerable<string> GetNullColumnsName(string sql)
{
using (var cnn = Connection)
{
if(cnn.State == ConnectionState.Closed) cnn.Open();
using(var cmd = cnn.CreateCommand()){
cmd.CommandText = sql;
using(var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess|CommandBehavior.SingleResult|CommandBehavior.SingleRow))
{
if(reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
var value = reader.GetValue(i);
if(value is DBNull)
yield return reader.GetName(i);
}
}
while (reader.Read()) {};
}
}
}
}
As per your this statement: "every time I will have only one record and I need to find the list of NULL columns for it"
You can store these values like follows:
Column | Values
FName | Null
LName | Smith
Dept | Null
and I assume that id is the primary key so as per your requirement if you want to store that then you can or if not, it's your choice.
SELECT Column FROM table
WHERE Values IS NULL;
You can use the following script. The script:
opens a cursor over all columns in the table definition
then, for each column, it queries all values in the column
if there is no non-null value in the column, it prints the name of the column
create table tmpTable (id int, FName varchar(32), LName varchar(32), Dept varchar(32))
insert into tmpTable values(1, null, 'Smith', null)
go
declare #column varchar(128)
declare #sql varchar(max)
declare c cursor for
select c.name from sys.tables t join sys.columns c on t.object_id = c.object_id
where t.name = 'tmpTable'
open c
fetch next from c into #column
while ##fetch_status = 0
begin
select #sql = 'if not exists (select * from tmpTable where ' + #column + ' is not null) begin print + ''' + #column + ''' end'
exec(#sql)
fetch next from c into #column
end
close c
deallocate c
go
drop table tmpTable
For your test case, this is the output of the script:
FName
Dept
Note: This script will work regardless how many rows you have in the table.
Edit:
I had written my answer before the following clarification was added "It is a result set". My solution works with a table (as I am querying the system catalogs) and will not cover the clarified scenario (using a result set).

Best practice to pass a list as input in SQL query using vb.net [duplicate]

This question already has answers here:
Pass table valued parameter using ADO.NET
(5 answers)
Pass Array Parameter in SqlCommand
(11 answers)
Closed 5 years ago.
I am using vb.net with a SQL Server 2012 database.
I want to check the status of a list of files in the databases. The query is simple and something like this.
DECLARE #Filename NVARCHAR(100)
SET #Filename = 'MyFileName.doc'
SELECT DISTINCT
Docs.Filename,
Status.Name as 'Status'
FROM
[Documents] AS Docs
INNER JOIN
[Status] AS Status ON Status.StatusID = Docs.CurrentStatusID
WHERE
Docs.Filename LIKE #Filename
It works fine for one filename and I can launch it easily in vb.net using a sql connection as in this example.
Dim conn As New SqlConnection
If conn.State = ConnectionState.Closed Then
conn.ConnectionString = PDMConnectionString
End If
Try
conn.Open()
Dim sqlquery As String =
"DECLARE #Filename NVARCHAR(100)
SELECT DISTINCT
Docs.Filename,
Status.Name as 'Status'
FROM [Documents] AS Docs
INNER JOIN [Status] AS Status
ON Status.StatusID = Docs.CurrentStatusID
WHERE Docs.Filename LIKE #Filename "
Dim data As SqlDataReader
Dim adapter As New SqlDataAdapter
Dim parameter As New SqlParameter
Dim command As SqlCommand = New SqlCommand(sqlquery, conn)
With command.Parameters
.Add(New SqlParameter("#filename", "MyFileName.doc"))
End With
command.Connection = conn
adapter.SelectCommand = command
data = command.ExecuteReader()
While data.Read
'do something'
End While
Catch ex As Exception
End Try
The problem is that I need to find the status of a lot of files and I would like to do it with only one query.
I can do it directly in the query by by changing the last line like this, removing the parameter in vb.net and sending directly the query:
WHERE
Docs.Filename IN ('MyFileName.doc', 'MyOtherFileName.doc')
But it implies a lot of string concatenation and I don't really like how the code looks like with that solution.
What is the best practice to use in that type of situation in order to use less string concatenation and to make a code that is easier to manage?
You could use a function to take a comma separated string and return a table...
CREATE FUNCTION [dbo].[FileNames]( #FilenameValues nvarchar(max) )
RETURNS #Result TABLE( FileName nvarchar(max) )
AS
BEGIN
-- convert to an xml string
DECLARE #xml XML
SELECT #xml = CAST( '<A>' + REPLACE( #FilenameValues, ',', '</A><A>' ) + '</A>' AS XML )
-- select rows out of the xml string
INSERT INTO #Result
SELECT DISTINCT LTRIM( RTRIM( t.value( '.', 'nvarchar(max)' ) ) ) AS [FileName]
FROM #xml.nodes( '/A ') AS x(t)
RETURN
END
Then in your SQL either JOIN to it ...
JOIN (
SELECT * FROM dbo.FileNames( 'MyFileName.doc, MyOtherFileName.doc' )
) FileNames ON FileNames.FileName = Docs.Filename
OR use in a WHERE ...
WHERE Docs.Filename IN(
SELECT * FROM dbo.FileNames( 'MyFileName.doc, MyOtherFileName.doc' )
)

Passing multiple params to stored procedure

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

How i put multiple values in procedure while in? vb.net [duplicate]

This question already has answers here:
Parameterize an SQL IN clause
(41 answers)
Closed 7 years ago.
I have code in vb.net with #values like this:
Dim con As New SqlConnection
Dim cmd As New SqlCommand
con = FunctionConnection()
cmd.Connection = con
cmd.CommandText = "GetVerification"
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#Value", "1,2,3,4")
Dim Header_DataReader As SqlDataReader = Nothing
con.Open()
Header_DataReader = cmd.ExecuteReader
And my procedure like that:
ALTER PROCEDURE GetVerification (#Value varchar(255))
as
BEGIN
SELECT id, ControlPlanID, ParagraphID, ParagraphOrder, Specification, SpecificationParagraph, Dimension, Description, Samples, Frequency, ActivityResource,
ActivityName, Observation, RequrementNom, RequrementPlus, RequrementMinus, Units
FROM CP_Sequence
WHERE (ParagraphOrder IN (#Value))
End
How put multilple values in my procedure, i want to put in #values 1,2,3,4 for 4 different rows for database
if i put in Sql code like this work but not for my procedure:
SELECT id, ControlPlanID, ParagraphID, ParagraphOrder, Specification, SpecificationParagraph, Dimension, Description, Samples, Frequency, ActivityResource,
ActivityName, Observation, RequrementNom, RequrementPlus, RequrementMinus, Units
FROM CP_Sequence
WHERE (ParagraphOrder IN (1, 2, 3, 4))
Thanks a lot
ALTER PROCEDURE dbo.GetVerification (#Value VARCHAR(255))
AS
BEGIN
SET NOCOUNT ON
DECLARE #a TABLE (ID INT PRIMARY KEY WITH (IGNORE_DUP_KEY=ON))
INSERT INTO #a
SELECT t.c.value('.', 'INT')
FROM (SELECT x = CAST('<t>' + REPLACE(#Value, ',', '</t><t>') + '</t>' AS XML)) r
CROSS APPLY r.x.nodes('/t') t(c)
SELECT *
FROM dbo.CP_Sequence
WHERE ParagraphOrder IN (SELECT * FROM #a)
OPTION(RECOMPILE)
END

better way to assign stored procedures output values from a table select

Due to programming language restraints, my ERP system does not allow me to make advanced select queries, that´s why I need to rely on making a stored procedure on SQL Server, calling it from the ERP system and getting the result through an array.
The code belows works ok, but I think it´s not the correct way to assign the values to the output variables... I wanted to assign the output variables directly from the select, without need to make a #temp table... is it possible? or did I make it right?
If the code can be enhanced, I would gracefully accept any suggestions. The objective of the code is call a stored procedure with a RFID tag (read by a RFID card reader) and then get some employee info from another database, from another ERP, on another server (linked through SQL "linked servers")
ALTER procedure [dbo].[KSBValTag]
(
#rfid varchar(20),
#OUT_NUMCAD varchar(10) OUTPUT,
#OUT_NOMFUN varchar(50) OUTPUT,
#OUT_SIT varchar(2) OUTPUT,
#OUT_CODCCU varchar(5) OUTPUT,
#OUT_NOMCCU varchar(30) OUTPUT
) as
Begin
set #rfid = SUBSTRING(#rfid, PATINDEX('%[^0]%', #rfid+'.'), LEN(#rfid))
select fun.numcad as Numcad,
fun.nomfun as Nomefun,
fun.sitafa as Situacao,
fun.codccu as CodCCU,
ccu.nomccu as NomeCCU
into #temp
from [vetorh].vetorh.r034fun as FUN
inner join
[vetorh].vetorh.r018ccu CCU
on fun.codccu = ccu.codccu
where numcad = (select num_cartao from [ksb-app01].topacesso.dbo.Cartoes where CodigoDeBarras = #rfid)
and tipcol = '1'
set #OUT_NUMCAD = (select Numcad from #temp)
set #OUT_NOMFUN = (select Nomefun from #temp)
set #OUT_SIT = (select Situacao from #temp)
set #OUT_CODCCU = (select CodCCU from #temp)
set #OUT_NOMCCU = (select NomeCCU from #temp)
End
select
#OUT_NUMCAD = fun.numcad,
#OUT_NOMFUN = fun.nomfun,
#OUT_SIT = fun.sitafa,
#OUT_CODCCU = fun.codccu,
#OUT_NOMCCU = ccu.nomccu
from [vetorh].vetorh.r034fun as FUN
inner join
[vetorh].vetorh.r018ccu CCU
on fun.codccu = ccu.codccu
where numcad = (select num_cartao from [ksb-app01].topacesso.dbo.Cartoes where CodigoDeBarras = #rfid)
and tipcol = '1'

Resources