incrementing by 1 in vb10 connected to sql edited - sql-server

i want to have an student id with last 2 digits of the year and a string of -001 example 13-001 and read the last value in the table example 13-002 is the last value in the table how it can becomes 13-003 when the forms load. i have a value on table 13-001 and i had been try this code but it gives me 14 instead 13-002
Dim dr As SqlDataReader
Dim Cmd As New SqlCommand
con.Open()
With Cmd
.Connection = con
.CommandText = "SELECT * FROM tbl_student ORDER BY Student_no DESC"
End With
dr = Cmd.ExecuteReader
If dr.Read Then
lblstudno.Text = Val(dr.Item(0)) + 1
End If
con.Close()
thanks hope you understand

INSERT INTO
students
( student_id ) VALUES
(
CAST( ( YEAR( GETDATE() ) % 100 ) + 1 AS varchar(2) ) + '-' +
CAST(
SELECT TOP 1
CAST( RIGHT( student_id, 3 ) AS int ) + 1
FROM
students
ORDER BY
student_id DESC
AS varchar(3) )
)
Note that this will fail if you reach 999 students. There is also a potential race condition unless you do a lock of some kind on the table (see transaction isolation).
My post also demonstrates why IDENTITY keys are generally a good idea instead of rolling your own (assuming you want to use this system as your primary key).

Related

In VB.NET, who can Iet all databases that contain a specific table

In VB.NET am trying to return all databases that have a specific table. The code I have been using polls just the databases and that works fine. When I add the CASE statement below to get just the ones with the table I need then it returns nothing.
strQuery = "SELECT [name] FROM sys.databases where create_date > '2016-07-01' and [name] not like '_Config_Options' order by create_date desc"
sqlCon = New SqlConnection(strConn)
Using (sqlCon)
Dim sqlComm As SqlCommand = New SqlCommand(strQuery, sqlCon)
sqlCon.Open()
Dim sqlReader As SqlDataReader = sqlComm.ExecuteReader
If sqlReader.HasRows Then
While (sqlReader.Read())
cmbDatabase.Items.Add(sqlReader.GetString(0))
End While
End If
sqlReader.Close()
End Using
The above code returns the full list of databases.
When I change the strQuery to
strQuery = "SELECT [name] FROM sys.databases WHERE CASE WHEN state_desc = ''ONLINE'' THEN OBJECT_ID(QUOTENAME([name]) + ''.[dbo].[MyTable]'', ''U'') END IS NOT NULL order by create_date desc"
I get nothing back. After executing Dim sqlReader As SqlDataReader = sqlComm.ExecuteReader, the code jumps to the End Using. I don't see an error code.
Joel Coehoom gets the credit for answering. I removed the double single quotes and it works.
strQuery = "SELECT [name] FROM sys.databases WHERE CASE WHEN state_desc = 'ONLINE' THEN OBJECT_ID(QUOTENAME([name]) + '.[dbo].[MyTable]', 'U') END IS NOT NULL order by create_date desc"

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' )
)

Insert multiple rows, count based on another table columns

I have 3 Tables. Item, StockDetail, Branch
I want to INSERT 2 of them at once. The Item and StockDetail table.
Item has 3 columns = ItemID, Title, Price.
StockDetail has 3 columns = ItemID, BranchID, Stock.
Branch has 1 column = BranchID.
In this code below, INSERT into Item works fine, but not for StockDetail table, it doesn't INSERT anything!
Now for the StockDetail if it works, I want to insert it with the condition below:
If you add an item, then it'll add this item with all existed BranchID.
That mean, every Branches will have this item.
e.g:
You add an item, while
Branch has 3 rows of BranchID = BR000, BR001, BR002.
It will insert to StockDetail with 3 rows as well, at once (single Query)
Complete result of StockDetail (single Query):
ItemID | BranchID | Stock
______________________________
IM000 | BR000 | 0
IM000 | BR001 | 0
IM000 | BR002 | 0
The Code:
'Add function'
'Insert to StockDetail'
Dim theCommand As New SqlCommand
Dim theDataAdapter As New SqlDataAdapter
Dim theDataTable As New DataTable
theCommand.Connection = theConnection
theCommand.CommandText = "INSERT INTO StockDetail VALUES(
'" & Me.TextBox_ItemID.Text & "',
SELECT COUNT(BranchID) FROM Branch,
'0'
)"
theDataAdapter.SelectCommand = theCommand
'Insert to Item'
theCommand.Connection = theConnection
theCommand.CommandText = "INSERT INTO Item VALUES('" & Me.TextBox_ItemID.Text & "', '" & Me.TextBox_Title.Text & "', '" & Me.TextBox_Price.Text & "')"
theDataAdapter.SelectCommand = theCommand
theDataAdapter.Fill(theDataTable)
DataGridView_Item.DataSource = theDataTable
theCommand.Dispose()
theDataAdapter.Dispose()
UPDATE:
The code below will tell you the working multiple INSERT, but not with the BranchID INSERT.
'Insert to StockDetail'
theConnection.Open()
Dim theCommand As New SqlCommand
Dim theDataAdapter As New SqlDataAdapter
theCommand.Connection = theConnection
theCommand.Parameters.Add("#ItemID", SqlDbType.VarChar).Value = Me.TextBox_ItemID.Text
theCommand.CommandText = "INSERT INTO StockDetail(ItemID, BranchID, Stock) SELECT #ItemID, COUNT(Branch.BranchID), '0' FROM Branch GROUP BY Branch.BranchID"
theDataAdapter.SelectCommand = theCommand
Using theDataAdapter
theCommand.ExecuteNonQuery()
theCommand.Parameters.Clear()
theCommand.Dispose()
theConnection.Close()
SqlConnection.ClearPool(theConnection)
End Using
What do I want now?
Well instead of inserting 1, 1, . . .
I'd like to INSERT it with BR000, BR001 . . . (Based on all existed BranchID)
Here is how you use a parameter in your first insert statement. I think you still have some very serious logic issues here though. This is going to insert 1 row into StockDetail and the values don't make any sense at all. You would be inserting the count of rows from the Branch table as the BranchID which is probably not what you really want. I suspect what you want is a row in this table for each Branch?
theCommand.CommandText = "INSERT INTO StockDetail(ItemID, BranchID, Price) VALUES(
#ItemID,
(SELECT COUNT(BranchID) FROM Branch),
0
)"
theCommand.Parameters.Add("#ItemID", SqlDbType.Varchar).Value = Me.TextBox_ItemID.Text;
I suspect what you really want is something more like this.
theCommand.CommandText = "INSERT INTO StockDetail(ItemID, BranchID, Price)
select #ItemID
, BranchID
, 0
from Branch";
theCommand.Parameter.Add("#ItemID", SqlDbType.Varchar).Value = Me.TextBox_ItemID.Text;
The SQL command text for the insert into StockDetail doesn't do what you say you want to happen. This code, though syntactically incorrect (if you want to use a SELECT as a value, you need to surround it in parentheses like this:
theCommand.CommandText = "INSERT INTO StockDetail VALUES(
'" & Me.TextBox_ItemID.Text & "',
(SELECT COUNT(BranchID) FROM Branch),
'0'
)"
), would insert your ID, a count of the number of branches you have, and a zero into the table.
For what you say you want to have happen, your code would look more like this:
theCommand.CommandText = "INSERT INTO StockDetail SELECT
'" & Me.TextBox_ItemID.Text & "',
BranchID, '0' FROM Branch
)"

display data using stored procedure vb.net

if i click the search button, i keep on receiving an error at the value of IDNo, incorrect syntax near '11111' can someone help me?
With acc
IDNo = .IDNo
StartDate = DateTime.Parse(.StartDate).ToString("M/d/yyyy")
EndDate = DateTime.Parse(.EndDate).ToString("M/d/yyyy")
ProjectName = .ProjectName
ReferenceNo = .ReferenceNo
TaskCode = .TaskCode
FileName = .Filename
End With
dgAccomplishment.DataSource = Nothing
dgAccomplishmentPT.DataSource = Nothing
da = New SqlDataAdapter("dbo.process_time #User='" & IDNo & "' ,#From='" & StartDate & "',#To='" & EndDate & " 11:59:59 PM'", DB.GetConnection)
dt = New DataTable
da.Fill(dt)
dgAccomplishment.DataSource = dt
dgAccomplishment.Columns("ID").Visible = False
dgAccomplishment.Columns("TimeSave").Visible = False
da.Dispose()
dt.Dispose()
this is my stored procedure
SELECT a.ID, RTRIM(a.Last_User) [ID No.],
RTRIM(Users.FIRSTNAME + ' ' + Users.INITIAL + '. ' + Users.LASTNAME) [Name],
RTRIM(a.ProjectName) [Project Name],
a.ProjectNo, a.ProjectCode,
RTRIM(a.Filename) [Filename],
RTRIM(a.Filesize) [Filesize],
RTRIM(a.filesizeunit) [FileSizeUnit],
a.TimeSave [TimeSave]
from DBase.dbo.Acc a
INNER JOIN dbo.Users ON a.Last_User = Users.IDNo
WHERE a.Last_User in (#user)
and CONVERT(VARCHAR(10),timesave,101) BETWEEN #From AND #To
ORDER BY RTRIM(a.SubGroup), RTRIM(a.Last_User)
but when i try to run the procedure in a query it works well.
Because you are using string concatenation, you have the age old single quote problem: If IDNo value contains a single quote, then your query will fail.
What's worse, your code is susceptible to sql injection attacks.
You have to escape ALL parameters for single quotes, replacing them by 2 single quotes.
Best solution here: use parametrized sql

Naming DataSet.table after performing SQLCommand (Select) Query

In stored procedure MS SQL My query is:
SELECT *
FROM ContentReportRequests a,UserPreferences d
WHERE a.UserID = d.UserID and a.ID =#ID
I want to give the result table some name.
How can I do this ?
I want to pull it to ADO.Net DataSet.tables["NAME"]
I can imagine a few things you might be meaning.
If you want to persist this result set, for consumption in multiple later queries, you might be looking for SELECT INTO:
SELECT * into NewTableName
FROM ContentReportRequests a,UserPreferences d
WHERE a.UserID = d.UserID and a.ID =#ID
Where NewTableName is a new name, and a new (permanent) table will be created. If you want that table to go away when you're finished, prefix the name with a #, to make it a temp table.
Alternatively, you might just be wanting to absorb it into a single larger query, in which case you'd be looking at making it a subselect:
SELECT *
FROM (SELECT *
FROM ContentReportRequests a,UserPreferences d
WHERE a.UserID = d.UserID and a.ID =#ID
) NewTableName
WHERE NewTableName.ColumnValue = 'abc'
or a CTE:
WITH NewTableName AS (
SELECT *
FROM ContentReportRequests a,UserPreferences d
WHERE a.UserID = d.UserID and a.ID =#ID
)
SELECT * from NewTableName
Finally, you might be talking about pulling the result set into e.g. an ADO.Net DataTable, and you want the name to be set automatically. I'm not sure that that is feasible.
You can use a variable of type table. Read more here: Table Variables In T-SQL
in stored procedure:
select CH.PrimaryKey, CH.Name,
NULL "CustomerHeader"
from CustomerHeader "CH";
--
select CD.PrimaryKey, CD.ShipTo,
NULL "CustomerDetail"
from CustomerDetail "CD";
--
select *, NULL "Orders"
from OrderTable;
in Vb.Net code:
Dim ds As DataSet = Nothing
ds = SqlExecute();
Dim dtCustHeader As DataTable = Nothing
Dim dtCustDetail As DataTable = Nothing
Dim dtOrders As DataTable = Nothing
For Each dt As DataTable In ds.tables
Select Case True
Case dt.Columns.Contains("CustomerHeader")
dtCustHeader = dt
Case dt.Columns.Contains("CustomerDetail")
dtCustDetail = dt
Case dt.Columns.Contains("Orders")
dtOrders = dt
End Select
Next
Kinda SILLY (OR STUPID) that you cannot name tables in a result set.
But this gets you there without a HUGE byte count repeating the table name within each row.
There is still overhead passing the NULL value back for each row. Perhaps passing a BIT value would be smaller yet...
And an alternative is to always use column(0):
in SQL:
select NULL "CustomerDetail", CustName,Addr1,Addr2... from CustomerDetail;
in vb.net:
Dim ds As DataSet = Nothing
ds = SqlExecute();
Dim dtCustHeader As DataTable = Nothing
Dim dtCustDetail As DataTable = Nothing
Dim dtOrders As DataTable = Nothing
For Each dt As DataTable In ds.Tables
Dim tblName As String = dt.Columns(0).ColumnName
Select Case tblName.ToUpper
Case "CUSTOMERDETAIL" : dtCustHeader = dt
Case "CUSTOMERDETAIL" : dtCustDetail = dt
Case "ORDERS" : dtOrders = dt
End Select
Next
These methods get your table-names even if the query returns zero rows.
but the best for last... a way to actually name the tables in the dataset automatically, every time FROM SQL STORED PROCEDURE (with help from your code):
Dim ds As DataSet = Nothing
ds = SqlExecute();
For Each dt As DataTable In ds.Tables
dt.TableName = dt.Columns(0).ColumnName
Next
After this, you may access your tables with the name YOU control within the stored procedure... as it should have been from day-one!
EDIT: selective implementation:
Name the first column in the pattern "TN:Customer".
Your legacy stored procedures work normally, only impacting the stored procedures you wish to modify.
For Each dt As DataTable In mo_LastDataset.Tables
Dim tblName() As String = dt.Columns(0).ColumnName.Split(":")
If tblName.Length >= 2 AndAlso tblName(0).ToUpper = "TN" Then
dt.TableName = tblName(1)
End If
Next
... david ...
SELECT * AS MyTableName
FROM ContentReportRequests a, UserPreferences d
WHERE a.UserID = d.UserID and a.ID =#ID

Resources