Get the exact SessionID generated in another Table - c#

I am new to sql. In my Chat application, I am storing the messages with the help of following Database Tables.
SessionTable --> SessionID (PK) Username1 Username2 Time
MessagesTable --> SessionID (FK) Username Message StartTime
The First Database Table SessionTable is used to generate a SessionID (IDENTITY(1,1)) by the help of which the users(limited to two) can have conversation. Whenever a user sends message to the other user, the message data will be stored in MessagesTable of column Message with the respective user's name in the column Username and the Time when the user sends the message. But the problem here I am facing is that how to get the exact sessionID to be stored along with the message in MessagesTable which was generated in SessionTable ?
My another question is that, As I am storing the messages in a single database Table will it arise performance issues in future? (The project which I am creating will be used among atmost 30 members) and also please suggest whether the way I have designed the Database tables is better way of approach or not.

After you insert the row into SessionTable you can use the Scope_Identity() function to get the SessionID assigned to the new row.
As for performance, there are too many factors to provide a useful answer.

In short: It seems like you have one-to-many relationship between Session table and Message table. Thus, you are attempting to join the tables throw common SessionID column.
Depending on the messaging application load, you need to think about the indexing strategy as well. In another words, tables with high intensity of read & write are usually getting performance hit.
Solutiob #1: You'll definitely need to use SCOPE_IDENTITY().
DECLARE #SessionID INT;
INSERT INTO dbo.SessionTable (Username1, Username2, Time)
SELECT 'User1', 'User2', GETDATE();
SELECT #SessionID = SCOPE_IDENTITY();
After this creation of session, you would need to use #SessionID to add message detail in MessagesTable. Like the following code sample:
INSERT INTO dbo.MessagesTable (SessionID, Username, Message, StartTime)
SELECT #SessionID, 'User1', 'The sample text of the message' GETDATE();
GO
In conclusion: the overall principle is described in the code sample which is posted above. However, i did not check al the syntax, thus you may expect some syntax corrections in this code :)

Related

Validate Sql Column Names

I have 4-5 tables in one database (not SQL Server).
In my UI, users can enter some SQL conditions together with column names in a textbox. I need to verify if the SQL is correct and if these columns exist, and show any errors accordingly. I am using C# for server side.
I have a SQL Server database where our UI stores all the UI related information.
One approach is to create all these tables (just the table structure) in my SQL Server as well and then query a simple select on each table and show the errors or success message(s) accordingly.
So basically I would have the where clause as below or more conditions:
where a = b and c in(1,2)
As mentioned above I would execute the above where clause against each table I created in SQL Server which would return error if column does not exist.
Is there a better way to approach this? I was thinking in case there is some other way to work without creating so many tables on my SQL Server.
I don't want to hard code these as the structure might change in near future. So looking for some maintainable solution. May be create a single table and store all this information in it.
Any suggestions are appreciated.
In SQL server you can query the system object :
information_schema.columns.
That contains a list of all columns for all tables and views.
However, I agree with previous comments - the design you describe is bad bad bad.
Ignoring the SQL injection troubles for a second, if the users have control over only the WHERE clause of the query, then you could try and run something like
select top 0 * from <tables> where <user-entered-where-clause>
and then gracefully handle any errors that are returned.
use dmv function in MS sql server to validate the query string.
assign user string to the variable #Str_query
declare #Str_query as nvarchar(max);
set #Str_query ='SELECT [role_code],[role_description] FROM [dbname].[dbo].[Roles]'
SELECT error_message FROM sys.dm_exec_describe_first_result_set(#Str_query, NULL, 0) WHERE column_ordinal = 0
if there is an error message then query string is not valid for execution.

Avoid duplicates in SQL server due the latency

I have a POS like system in C#, and for long time it not present any problem (it was just one POS). But in this days are 4 POS using the system, and connected to the same database and all the sales of one POS go to the same Audit (table) where all of the others sales go.
So in this system this is the procedure
Function to get the last Ticket number (with simple SELECT)
Add 1 to that number (next tickt no).
Generates a ID Code injecting this Ticket number (with the terminal, date, and employee code) into the algorithm
Insert record of the sale into database with all the necesary information (Date, Client, Employee, IDCode, etc.) (with simple INSERT INTO)
But having 4 POS I realize that some sales where having the same Ticket number, fortunately the Ticket ID code are not the same because the terminal and the employee are different, but how can avoid this?
Edit 1:
Every POS system have dual function, in one mode the POS sales are centralized, and every POS in this mode generates consecutive tickets (like they all where one POS), in the other mode every POS have their own Ticket numertion, for that reason I can't use the identity.
Just use a sequence to generate the next ticket number.
CREATE SEQUENCE Tickets
START WITH 1
INCREMENT BY 1;
Then each POS just do
SELECT NEXT VALUE FOR Tickets;
The sequence is guaranteed to never return the same number twice.
As has been mentioned, if the TicketNumber is sequential and unique, it sounds like an IDENTITY field would be the way to go. BUT, if for some reason there is something preventing that, or if that requires too many changes as this time, you could constrain the process itself to be single-threaded by creating a lock on the ID Code generation process itself through the use of Application Locks (see sp_getapplock and sp_releaseapplock). Application Locks let you create locks around arbitrary concepts. Meaning, you can define the #Resource as "generate_id_code" which will force each caller to wait their turn. It would follow this structure:
BEGIN TRANSACTION;
EXEC sp_getapplock #Resource = 'generate_id_code', #LockMode = 'Exclusive';
...current 4 steps to generate the ID Code...
EXEC sp_releaseapplock #Resource = 'generate_id_code';
COMMIT TRANSACTION;
You need to manage errors / ROLLBACK yourself (as stated in the linked MSDN documentation) so put in the usual TRY / CATCH. But, this does allow you to manage the situation.
Please note: sp_getapplock / sp_releaseapplock should be used sparingly; Application Locks can definitely be very handy (such as in cases like this one) but they should only be used when absolutely necessary.
You need to do this in an atomic action. So you can wrap everything in a transaction and lock the table. See here for a good discussion on locking etc.
Locking will slow down everything else since everything will start waiting for the table to free up for it to complete and that may not be something you can live with.
Or you can should use an identity on the column which will be managed by the database and maintain unique incrementing numbers.
You could also create your primary key (hope you have one) to be a combination of a few things. And then you could keeping a running number for each POS endpoint to see more data about how they are performing. But that gets more into analytics which isn't in scope here.
I would strongly suggest moving away from the current approach if you can and changing to a GUID PK.
However, I realize that in some cases a redesign is not possible (we have the exact same scenario that you describe in a legacy database).
In this case, you can get the maximum value safely using the UPDLOCK table hint in combination with the insert command and use the OUTPUT INSERTED functionality to retrieve the new primary key value into a local variable if needed:
DECLARE
#PK Table (PK INT NOT NULL)
INSERT
INTO Audit (
TicketNumber,
Terminal,
Date,
EmployeeCode,
Client,
IDCode,
... other fields )
/* Record the new PK in the tablevariable */
OUTPUT INSERTED.TicketNumber INTO #PK
SELECT IsNull(MAX(TicketNumber), 0) + 1,
#Terminal,
#Date,
#EmployeeCode,
#Client,
#IDCode,
... other values
FROM Audit WITH (UPDLOCK)
DECLARE #TicketNumber INT
/* Move the new PK from the local tablevariable into a local variable for subsequent use */
SELECT #TicketNumber = PK
FROM #PK

How do I show balance log in a gridview

I have a system in which allows the user to apply for taking leaves. The system also credits leaves to each user's account, twice a year.
Now, the administrator has full authority over this whole system and, can cancel the and grant leaves.
To analyze whether a user has not exceeded all privileges extended to him, it is required that the admin should be shown a record of the credit and debit of leaves taking place in each user account, like a log.
Something like this:
Now, I have made a table as below, to house this data:
My query now is that how do i achieve this? I mean, what should be my sql query and how should i display it?
Should I create a Sql Server Agent job and display the data in a gridview? If yes, then how should I specify the steps for that.
My database has an employee table which stores the updated balance for each type of leave for every user. And the leave table houses the details of the requests made by the users. Basically, it stores all the details filled out in the leave application form.
I am confused as to how do I fetch the operations and changes occurring on these tables, for that is what is required to be displayed to the admin.
As per my understanding of your query, I have been shared my suggestion below :
1.My point of view ,you can get your expected output by using stored procedure in Database.
2.Because Hopefully You stored the values of employee information, leave type ,leave details are into separate table with the help of primary & foreign key constraints.
3.In the stored procedure, you can perform the following steps:
(1)Pass Input parameter : EmployeeId, FromDate, ToDate, HandledById (AdminId)
(2)Join all corresponding table with the help of Primary & foreign key Id.
(3)Select the appropriate column, Use aggregate function to find the leave.
(4)Use sub query in case of necessary as per your logic & table structure.
4.Then You can bind & display the data in gridview easily.
Do let me know if you need anything else.!
there is not much you need to do in sql for that. You can fetch the data that is to be displayed, but how you want it to display can be control on server side/Client side coding.
So its better you fetch data and user the ItemDataBoud event to control the representational part of the application.

How to pull a SQL Table entry based on highest IDENTITY entry and update two columns

I'm not well versed in SQL operations, and would like some help with a task I need to complete in code. I have written a cloud based app that accesses a SQL table containing test results - device ID's, serial numbers, test results etc.
There is a use-case where someone in the field would activate a menu where an update to this table occurs. When the device test result table is updated, I want to store the OLD information in a device test history table. This way, we can go back and see what was changed over time.
So I need to pull all the columns from the TestedDevice table, insert them into TestedDeviceHistory table, and include some additional information; the current date and the operator's id. (these are two new columns found only in TestedDeviceHistory)
At first, I'm using a SELECT INTO command, as follows:
SELECT *
INTO dbo.TestedDevicesHistory
FROM dbo.TestedDevices
WHERE CertificateID = #cert
Then I'm attempting this (obviously broken) SQL command:
UPDATE dbo.TestedDeviceHistory
SET Caller = #caller,
RecordDate = #date
WHERE DeviceHistoryID = MAX(DeviceHistoryID)
Notes:
DeviceHistoryID is an IDENTITY integer column, so it's unique for each entry made in the history table.
CertificateID is unique in the TestedDevices table. It is expected NOT to be unique in the history table.
The code is written in C# 4.5
Maybe this is a case for a stored procedure, which I have never attempted to create or use. Or, perhaps the use of a cursor? Don't know! This is why I'm humbly asking for the more experienced with SQL to help :)
Not clear on if you only want to assign the Caller and RecordDate to the most recent record, or if it could be assigned to all the history records.
For all records, I believe you can do something like
SELECT *, #caller AS Caller, #date AS RecordDate INTO dbo.TestedDevicesHistory
FROM dbo.TestedDevices WHERE CertificateID=#cert

How to get the primary key from a table without making a second trip?

How would I get the primary key ID number from a Table without making a second trip to the database in LINQ To SQL?
Right now, I submit the data to a table, and make another trip to figure out what id was assigned to the new field (in an auto increment id field). I want to do this in LINQ To SQL and not in Raw SQL (I no longer use Raw SQL).
Also, second part of my question is: I am always careful to know the ID of a user that's online because I'd rather call their information in various tables using their ID as opposed to using a GUID or a username, which are all long strings. I do this because I think that SQL Server doing a numeric compare is much (?) more efficient than doing a username (string) or even a guid (very long string) compare. My questions is, am I more concerned than I should be? Is the difference worth always keeping the userid (int32) in say, session state?
#RedFilter provided some interesting/promising leads for the first question, because I am at this stage unable to try them, if anyone knows or can confirm these changes that he recommended in the comments section of his answer?
If you have a reference to the object, you can just use that reference and call the primary key after you call db.SubmitChanges(). The LINQ object will automatically update its (Identifier) primary key field to reflect the new one assigned to it via SQL Server.
Example (vb.net):
Dim db As New NorthwindDataContext
Dim prod As New Product
prod.ProductName = "cheese!"
db.Products.InsertOnSubmit(prod)
db.SubmitChanges()
MessageBox.Show(prod.ProductID)
You could probably include the above code in a function and return the ProductID (or equivalent primary key) and use it somewhere else.
EDIT: If you are not doing atomic updates, you could add each new product to a separate Collection and iterate through it after you call SubmitChanges. I wish LINQ provided a 'database sneak peek' like a dataset would.
Unless you are doing something out of the ordinary, you should not need to do anything extra to retrieve the primary key that is generated.
When you call SubmitChanges on your Linq-to-SQL datacontext, it automatically updates the primary key values for your objects.
Regarding your second question - there may be a small performance improvement by doing a scan on a numeric field as opposed to something like varchar() but you will see much better performance either way by ensuring that you have the correct columns in your database indexed. And, with SQL Server if you create a primary key using an identity column, it will by default have a clustered index over it.
Linq to SQL automatically sets the identity value of your class with the ID generated when you insert a new record. Just access the property. I don't know if it uses a separate query for this or not, having never used it, but it is not unusual for ORMs to require another query to get back the last inserted ID.
Two ways you can do this independent of Linq To SQL (that may work with it):
1) If you are using SQL Server 2005 or higher, you can use the OUTPUT clause:
Returns information from, or
expressions based on, each row
affected by an INSERT, UPDATE, or
DELETE statement. These results can be
returned to the processing application
for use in such things as confirmation
messages, archiving, and other such
application requirements.
Alternatively, results can be inserted
into a table or table variable.
2) Alternately, you can construct a batch INSERT statement like this:
insert into MyTable
(field1)
values
('xxx');
select scope_identity();
which works at least as far back as SQL Server 2000.
In T-SQL, you could use the OUTPUT clause, saying:
INSERT table (columns...)
OUTPUT inserted.ID
SELECT columns...
So if you can configure LINQ to use that construct for doing inserts, then you can probably get it back easily. But whether LINQ can get a value back from an insert, I'll let someone else answer that.
Calling a stored procedure from LINQ that returns the ID as an output parameter is probably the easiest approach.

Categories