I have some legacy code that I need to update, and I need to add a feature that uses the value returned from a table valued function. The issue I am having is that the function returns a table variable. The function is something like follows:
CREATE FUNCTION [dbo].[SomeFunction](#intKey INT)
RETURNS #t TABLE (strValue VARCHAR(20))
BEGIN
(....SOME CODE.....)
INSERT INTO #t (strValue) SELECT #SomeValue
RETURN
END
The code I call the function from VB is as follows:
Dim objRS As New ADODB.Recordset
Dim objCmd As New ADODB.Command
Set objRS = New ADODB.Recordset
With objCmd
.ActiveConnection = objConnection.CurrentConnection
.CommandType = adCmdText
.CommandText = "SELECT * FROM [dbo].[SomeFunction](?)"
.CommandTimeout = 0
End With
objCmd.Parameters.Append objCmd.CreateParameter("#intKey", adInteger, adParamInput)
objCmd("#intMatterID") = someObject.Key
Set objRs = objCmd.Execute
If (objRs.RecordCount > 0) Then
someString = objRs.Fields("strValue")
End If
The problem seems to be that last block of code, and I have confirmed that the Recordset is not empty. The Fields value seems to always be a NULL.
So I assume that I am doing this incorrectly and was wondering if it was possible to retrieve the value of "strValue".
It seems the issue I was experiencing was related to how I was accessing "strValue". I implemented the following and it ended up working.
If (objRs.RecordCount > 0) Then
objRs.MoveFirst
someString = Cstr(objRs("strValue"))
End If
Related
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
.ActiveConnection = db
.CommandText = "SELECT #date = '2019-01-01'"
.Parameters.Append(.CreateParameter("#date", adDBDate, adParamOutput))
.Execute
End With
Gives...
Must declare the scalar variable "#date".
Why can't I access the output parameter in the query text?
Named parameters work as expected on both sides (Server: SQL Server, Client: ADODB & VBScript for your case) only if the provider supports it. For SQL Server providers it is supported only with commands configured to call a stored procedure with named parameters (where cmd.CommandType set adCmdStoredProc and cmd.NamedParameters set True).
For an ordinary command like yours, named parameters are not recognized by the server, only the ? placeholders recognized as parameters in the query.
So you should try something like the following.
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
.ActiveConnection = db
.CommandText = "SELECT ? = '2019-01-01'"
.Parameters.Append(.CreateParameter("#dummyForServerNotForClient", adDBDate, adParamOutput))
.Execute
' must print: 2019-01-01
Response.Write .Parameters("#dummyForServerNotForClient").Value
End With
Since the parameter names ignored by servers, you can write the same code by omitting the parameter name, and access the parameter's value by using its ordinal position in the collection. IMHO, with the lack of explicitly named parameters the code becomes more logical and readable.
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
.ActiveConnection = db
.CommandText = "SELECT ? = '2019-01-01'"
.Parameters.Append(.CreateParameter(, adDBDate, adParamOutput))
.Execute
' also must print: 2019-01-01
Response.Write .Parameters(0).Value
End With
I hope this helps you to understand the concept.
The error comes from T-SQL because the variable #date hasn't been declared.
Adjust the T-SQL string you are passing into the ADODB.Command to declare the variable;
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
.ActiveConnection = db
.CommandText = "DECLARE #date AS DATETIME; SELECT #date = '2019-01-01';"
.Parameters.Append(.CreateParameter("#date", adDBDate, adParamOutput))
.Execute
End With
A simple way to debug these types of issues is to use the SQL Server Management Studio to run the query raw.
SELECT #date = '2019-01-01'
If you had tried to run the query without the declaration you would have got the same error with a bit more detail.
Msg 137, Level 15, State 1, Line 1
Must declare the scalar variable "#date".
I am trying to set a generator with a value that is in some table, I have already seen this question How to set initial generator value? and did what they suggested but I don't know where am I going wrong here.
set term #
execute block
as
declare i int = 0;
begin
i = (select max(some_col) from Table);
gen_id(some_gen,-(gen_id(some_gen,0))); ---set some_gen to 0
gen_id(some_gen,:i); --- set to i
end #
set term ;#
The problem with your code is that you can't execute gen_id in isolation; the parser expects gen_id (or more precisely: a function call) only in a place where you can have a value (eg in a statement or an assignment). You need to assign its return value to a parameter, for example:
set term #;
execute block
as
declare i int = 0;
declare temp int = 0;
begin
i = (select max(id) from items);
temp = gen_id(GEN_ITEMS_ID, -(gen_id(GEN_ITEMS_ID, 0))); ---set some_gen to 0
temp = gen_id(GEN_ITEMS_ID, :i); --- set to i
end #
set term ;#
Please be aware that changing sequences like this is 'risky': if there are any interleaving actions using this same sequence, you might not actually get the result you expected (the sequence might end up at a different value than i and you might get duplicate key errors when another transaction uses the sequence after you subtract the current value (set to 0) and before you add i.
As also noted in the comments, you can also replace your code with:
set term #;
execute block
as
declare i int = 0;
declare temp int = 0;
begin
i = (select max(id) from items);
temp = gen_id(GEN_ITEMS_ID, :i - gen_id(GEN_ITEMS_ID, 0));
end #
set term ;#
Doing it in one statement will reduce the risk of interleaving operations (although it will not remove it entirely).
If you want to use "execute block", you may use something like :
execute block
as
declare i int = 0;
begin
i = (select max(some_col) from some_table);
execute statement ('set generator MY_GENERATOR to ' || :i);
end
I have 2 access file, their names are A and B.
I've designed a form in access A for receiving data from users, and I want to insert or save data to another table in access B.
I know how insert record to access A tables, but I need to insert to another access file in another place.
Also I'm using this code for insert record to table:
Dim SER As Recordset
Set SER = CurrentDb.OpenRecordset("Tbl_A")
With SER
.AddNew
.Fields("Roz") = Me.Combo_Roz.Value
.Fields("Tarikh") = Me.Text_Tarikh.Value
.Fields("User") = Me.Text_User.Value
.Fields("Saat_Harekat") = Me.Text_Start.Value
.Fields("Saat_Residan") = Me.Text_End.Value
.Fields("Saat_Bargasht") = Me.Text_Bargasht.Value
.Fields("Moshkel") = Me.Text_Moshkel.Value
.Fields("Tozihat") = Me.Text_Reason.Value
.Update
Use this answer if you want a permanent connection to this table.
Have a Database Object open a connection to AccessB, and create the Recordset based on Tbl_B of this Data Base:
Dim SER As Recordset
Dim Dbs as DAO.Database
'Open a recordset to AccessB, and insert the data:
Set Dbs = OpenDatabase("C:\Path\accessB.accdb")
Set SER = Dbs.OpenRecordset("Tbl_B")
With SER
.AddNew
.Fields("Roz") = Me.Combo_Roz.Value
.Fields("Tarikh") = Me.Text_Tarikh.Value
.Fields("User") = Me.Text_User.Value
.Fields("Saat_Harekat") = Me.Text_Start.Value
.Fields("Saat_Residan") = Me.Text_End.Value
.Fields("Saat_Bargasht") = Me.Text_Bargasht.Value
.Fields("Moshkel") = Me.Text_Moshkel.Value
.Fields("Tozihat") = Me.Text_Reason.Value
.Update
End With
Use this answer for a more easily disposed connection to this table.
Create a Linked table to table B in AccessB, and insert data to it as if it was a table in you databas:
Dim SER As Recordset
'Create the liked table by VBA code:
DoCmd.TransferDatabase acLink, "Microsoft Access", "C:\Path\accessB.accdb", acTable, "Tbl_B", "Tbl_B"
'Open a recordset based on linked table, and insert the data:
Set SER = CurrentDb.OpenRecordset("Tbl_B")
With SER
.AddNew
.Fields("Roz") = Me.Combo_Roz.Value
.Fields("Tarikh") = Me.Text_Tarikh.Value
.Fields("User") = Me.Text_User.Value
.Fields("Saat_Harekat") = Me.Text_Start.Value
.Fields("Saat_Residan") = Me.Text_End.Value
.Fields("Saat_Bargasht") = Me.Text_Bargasht.Value
.Fields("Moshkel") = Me.Text_Moshkel.Value
.Fields("Tozihat") = Me.Text_Reason.Value
.Update
End With
Below is the example of Data.
ss-tt(1/21/2014 9:47:12 AM)->bb-tt-uu(02/07/14 11:09:59)
Above data is store in a column of a table. Now what I want to do ,to split "date" which is followed by "ss-tt" and paste it in another column but in same row.
For that i want to create a function in Sql server. It is quite easy in excel(VBA) to create a function using array but in Sql server i don't understand how to use the array concept.
Below is the function which i had created in excel(VBA) for the same calculation.
Sub readExcell1()
Dim arr() As Variant
Dim token As Variant
Dim innertoken As Variant
Dim first As String
Dim second As String
Dim ind As Integer
arr = Range("D2:D849")
Dim R As Long
Dim C As Long
rownum = 1
colnum = 1
For R = 1 To UBound(arr, 1) ' First array dimension is rows.
'MsgBox "processing row " & R
'MsgBox arr(R, 1)
token = Split(arr(R, 1), "->")
For i = LBound(token) To UBound(token)
'MsgBox token(i)
innertoken = Split(token(i), "(")
first = innertoken(0)
first = Trim(first)
second = innertoken(1)
If first = "payroll-apac" Then
ind = 1 + R
second = Replace(Trim(second), ")", "")
Application.Range("H" & ind).Value = second
GoTo Label1
End If
Next i
Label1:
Next R
End Sub
This should do what you want. Obviously you could handle the prefix and separator separately rather than use columns.
declare #table table (
[value] [nvarchar](max)
, [prefix] [sysname]
, [separator] [sysname]
, [calculated] as substring([value]
, len([prefix]) + 1
, charindex([separator]
, [value]) - len([prefix]) - 1));
--
insert into #table
([value]
, [prefix]
, [separator])
values (N'ss-tt(1/21/2014 9:47:12 AM)->bb-tt-uu(02/07/14 11:09:59)'
, N'ss-tt('
, N')');
--
select [value]
, [calculated]
from #table;
I require to create through ADO.NET a temp table, perform a BulkCopy and then a Merge on the server between the temp and the actual table.
Problem is creating the temp table dynamic using pure ADO.NET.
The schema should be the same as the existing table, but this table is created using an ORM (NHibernate or Entity Framework, we're not sure yet). This also means that the schema can change in the future.
Is there any way to create a table in the database using plain ADO.NET objects? Such as a DataTable containing the schema of the original table?
Any information pointing me in the right direction is appreciated.
You can create a temporary table using select into #somename.
connection_ = New SqlClient.SqlConnection(connection_string_)
connection_.Open()
If connection_.State = ConnectionState.Open Then
command_.Connection = connection_
command_.CommandType = CommandType.Text
command_.CommandText = "select * into #some_table from some_table where some_id = 0"
command_.ExecuteNonQuery()
Dim line_index_ As Integer = 0
Dim data_table_ As DataTable = New DataTable()
Using parser_ As FileIO.TextFieldParser = New FileIO.TextFieldParser(path_)
parser_.SetDelimiters(delimiter_)
parser_.HasFieldsEnclosedInQuotes = False
While Not parser_.EndOfData
If line_index_ = 0 Then
Dim headers_ As String() = parser_.ReadFields()
For Each header_ In headers_
data_table_.Columns.Add(header_)
Next
Else
Dim row_ As DataRow = data_table_.NewRow()
row_.ItemArray = parser_.ReadFields()
data_table_.Rows.Add(row_)
End If
line_index_ += 1
End While
End Using
Using bulkCopy_ As SqlBulkCopy = New SqlBulkCopy(connection_)
bulkCopy_.DestinationTableName = "#some_table"
bulkCopy_.WriteToServer(data_table_)
End Using
' proof
command_.CommandText = "select * from #some_table"
Dim reader_ As SqlDataReader = Nothing
reader_ = command_.ExecuteReader
line_index_ = 0
While reader_.Read
line_index_ += 0
End While
End If
I managed to create a temp table based on an existing schema.
Blogged the solution on my site.