SQL check if record exists - sql

So I spent some time to research what the best way was to check if a record exist was. Ended up with this.
var checkExistance = "SELECT TOP 1 exerVariName FROM exerciseVariants WHERE exerVariName = '" + exerVariName + "'";
However I failed many times to make this work while using it on my page!
var exerVariName = Request.Form["exerVariName"];
var checkExistance = "SELECT TOP 1 exerVariName FROM exerciseVariants WHERE exerVariName = '" + exerVariName + "'";
if (IsPost && Validation.IsValid()) {
if (ModelState.IsValid) {
foreach (var c in db.Query(checkExistance)) {
if (c.exerVariName != exerVariName) {
var insertData = "INSERT INTO exerciseVariants (exerVariName, exerVariNameID) " +
"VALUES (#0, #1)";
db.Execute(insertData, exerVariName, exerciseID);
Response.Redirect("~/insertexervariname");
}
}
}
}
So the variable I put into the SQL line is a request form thing so its a user input that I want to check if it exists in the database, if it already exists I dont want it to be posted. And the above is what i tried with the foreach in the if ispost.
How would one go about to achieve this? (c# razor/cshtml)

Your code has race conditions.
The best way to do what you want is to have the database enforce the constraint, using a unique index/constraint:
create unique index unq_exerciseVariants_exerVariName on exerciseVariants(exerVariName);
If you want to avoid the error on updates, then you can check as you update as well:
INSERT INTO exerciseVariants (exerVariName, exerVariNameID)
SELECT exerVariName, exerVariNameID
FROM (SELECT #0 as exerVariName, #1 as exerVariNameID
) x
WHERE NOT EXISTS (SELECT 1
FROM exerciseVariants
WHERE ev.exerVariName = x.exerVariName
);
Note that this check may not be sufficient due to race conditions, if two different threads attempt to insert the same name at the same time. That is why it is best to have the database enforce the uniqueness.

I am no C# person by any means, but I do see one logical problem with your current code. Currently your EXISTS and INSERT queries are being run separately, separated by several lines of .NET code and perhaps many more actual machine instructions. The net (no pun intended) result of this is that you might end up inserting when the existence check appears true but is no longer true. To avoid this, the existence check should appear in the WHERE clause of the INSERT. Something like this should work:
INSERT INTO exerciseVariants (exerVariName, exerVariNameID)
VALUES (#0, #1)
WHERE EXISTS
(
SELECT * exerVariName
FROM exerciseVariants
WHERE exerVariName = '" + exerVariName + "'";
)
Now the INSERT should happen atomically, meaning your check and the actual insert will all be done at the same time, regardless of what other threads might be doing.

Related

Storing query as a int to check to see if more than one exists

The code is suppose to check my database to see if there are duplicates of activityName existing if that query runs I am suppose to get an error stating that the activity name is taken else if there isn't any activity name in that database with the same name then the activity name would be inserted into the database. Im suppose to execute the query and get the result as an Integer then use the result in the if and else to see if result>0 in the database
var queryCount= 'SELECT COUNT (activityName) FROM dataEntryTb WHERE activityName = "'+an+'" ';
tx.executeSql(queryCount,[]);
if(queryCount > 0){
navigator.notification.alert("Activity Name Taken");
}else{
Not sure what's the issue exactly but it should work fine. You can consider changing it like
var queryCount= "SELECT 1 FROM dataEntryTb WHERE activityName = '" + an + "'";
Again, consider using parameterized query instead of string concatenation to avoid SQL Injection (if an is coming as user input)

Dynamically create sql where condition on textbox entry

I am working on a C# desktop application. I want to create a search functionality. Now the problem is that i am using around 8 textboxes. Different permutations of textboxes could be populated and the resulting 'sql where' condition should only include those textboxes values which are not null. Now one pathetic way is to use a zillion 'if and else' which obviously is laborious. Any other way to do this?
You need just one query with filled WHERE to use all parameters like this
select ...
from ...
WHERE
(firstNameColumn=:firstNameParam or :firstNameParam is null)
AND (lastNameColumn=:lastNameParam or :lastNameParam is null)
AND (...)
I would like to make a point of first checking is the paramtere null, then use it to compare with column values.
Since you are generating query in C#, try old-Chinese approach from Ming period of using default condition where 1=1 just to avoid checking did you already had first condition :)
string query = "select ... from ... join ... on ... where 1=1";
//suposedly you have value of one search box in variable called "item_name"
if(string.IsNullOrWhiteSpace(item_name) == false)
{
query += " and Order_Line.Name ='" + item_name + "'";
}
and so on for other fields.
What you are trying to do in order to avoid ifs is not really a good approach. Look at this:
string query = " select ... where Order_Line.Name = '" + item_name + "'";
What will be the resulting string if item_name is actually null?
EDIT: the resulting query would be
where Order_Line.Name = '' or Order_Line.Name is null
which is not what you want. You want every row if that search field is empty, menaing it shouldn't have anu effect on search. That's why you need condition to see will you include this column in where clause in the first place.

How to delete large amounts of data from Foxpro

The problem
We have a legacy Visual FoxPro reservation system with many tables. I have been asked to do some housekeeping on the tables to reduce their size.
The tables are badly designed with no auto incrementing primary key.
The largest table is 3 million rows.
I am attempting to delete 380,000 rows.
Due to the volume of data in the tables, I am trying to develop a solution which batch deletes.
What I've got so far
I have created a C# application which accesses the database files via the vfpoledb.1 driver. This application uses recno() to batch the deletion. This is an example of the query I'm using:
delete from TableA
where TableA.Key in (
select Key from TableB
where Departure < date(2010,01,01) and Key <> ""
) and recno() between 1 and 10000
Executing this via vfpoledb.1 does not delete anything. Executing a select statement with the same where clause does not return anything.
It seems that the combination of the recno() function and an in() function is causing the issue. Testing the query with each clause in turn returns results.
Questions
Is there another way of batch deleting data from Visual FoxPro?
Why are recno() and in() not compatible?
Is there anything else I'm missing?
Additional information
ANSI is set to TRUE
DELETED is set to TRUE
EXCLUSIVE is set to TRUE
Instead of doing in batch of so many record numbers, why not a simpler approach. You are looking to kill off everything prior to some date (2010-01-01).
Why not try based on starting with 2009-12-31 and keep working backwards to the earliest date on file you are trying to purge off. Also note, I don't know if Departure is a date vs datetime, so I changed it to
TTOD( Departure ) (meaning convert time to just the date component)
DateTime purgeDate = new DateTime(2009, 12, 31);
// the "?" is a parameter place-holder in the query
string SQLtxt = "delete from TableA "
+ " where TableA.Key in ( "
+ " select Key from TableB "
+ " where TTOD( Departure ) < ? and Key <> \"\" )";
OleDbCommand oSQL = new OleDbCommand( SQLtxt, YourOleDbConnectionHandle );
// default the "?" parameter place-holder
oSQL.Parameters.AddWithValue( "parmDate", purgeDate );
int RecordsDeleted = 0;
while( purgeDate > new DateTime(2000,1,1) )
{
// always re-apply the updated purge date for deletion
oSQL.Parameters[0].Value = purgeDate;
RecordsDeleted += oSQL.ExecuteNonQuery();
// keep going back one day at a time...
purgeDate = purgeDate.AddDays(-1);
}
This way, it does not matter what RECNO() you are dealing with, it will only do whatever keys are for that particular day. If you have more than 10,000 entries for a single day, then I might approach differently, but since this is more of a one-time cleanup, I would not be too concerned with doing 1000+ iterations ( 365 days per year for however many years) through the data... Or, you could do it with a date range and do maybe weekly, just change the WHERE clause and adjust the parameters... something like... (The date of 1/1/2000 is just a guess for how far back the data goes). Also, since this is doing entire date range, no need to convert possible TTOD() of the departure field.
DateTime purgeDate = new DateTime(2009, 12, 31);
DateTime lessThanDate = new DateTime( 2010, 1, 1 );
// the "?" is a parameter place-holder in the query
string SQLtxt = "delete from TableA "
+ " where TableA.Key in ( "
+ " select Key from TableB "
+ " where Departure >= ? "
+ " and Departure < ? "
+ " and Key <> \"\" )";
OleDbCommand oSQL = new OleDbCommand( SQLtxt, YourOleDbConnectionHandle );
// default the "?" parameter place-holder
oSQL.Parameters.AddWithValue( "parmDate", purgeDate );
oSQL.Parameters.AddWithValue( "parmLessThanDate", LessThanDate );
int RecordsDeleted = 0;
while( purgeDate > new DateTime(2000,1,1) )
{
// always re-apply the updated purge date for deletion
oSQL.Parameters[0].Value = purgeDate;
oSQL.Parameters[1].Value = lessThanDate;
RecordsDeleted += oSQL.ExecuteNonQuery();
// keep going back one WEEK at a time for both the starting and less than end date of each pass
purgeDate = purgeDate.AddDays(-7);
lessThanDate = lessThanDate.AddDays( -7);
}
I'm interested in the best way to accomplish this too. We use a lot of poorly designed dBaseIII files that are sometimes quite large.
We do this a lot but it's a nasty, manual process:
Import dbf files into a temp database using DTS (management studio import/export wizard for version 2005 + )
Run the cleanup scripts using SSMS
Export the dbf files and replace the original ones (backing them up) with the newly modified files.
It works for us.
It looks like your condition with date isn't working. Try to execute SELECT statement with using of CTOD() function instead of DATE() you've used.
When your condition will work, then you'll be able to run DELETE statement. But remember that as a result of the DELETE execution the rows will only be marked as deleted. To remove them completely you should run PACK statement after DELETE.
As an another way, you can also try our DBF editor - DBF Commander Professional. It allows to execute SQL queries, including command-line (batch) mode. E.g.:
dbfcommander. exe -q "DELETE FROM 'D:\table_name.dbf' WHERE RECNO()<10000"
dbfcommander. exe -q "PACK 'D:\table_name.dbf'"
You can use it for free within 20 days full-featured trial period.

Insert Into Select SQL Server

I am trying to do a kind of insert into select statement. I want to insert one column as standard and the second through a select. However this is not working:
queryString = "INSERT INTO Words (Word, SortedId) VALUES ('" + words[i] + "', (SELECT TOP 1 SortedId FROM SortedWords WHERE SortedWord = '" + sortWord(words[i]) + "'))";
SortedWords is already filled with data. But at the moment i get this error
{"There was an error parsing the query. [ Token line number = 1,Token line offset = 50,Token in error = SELECT ]"}
Note:
not sure if i need the TOP 1 bit or not, get error either way. But I obvs only want to insert one row.
Change your query to
queryString = "INSERT INTO Words (Word, SortedId) SELECT '" + words[i] + "', (SELECT TOP 1 SortedId FROM SortedWords WHERE SortedWord = '" + sortWord(words[i]) + "')";
Also, instead of concatenating strings to get your query, use parameters to avoid SQL injection.
Try next and better practice to use a SqlParameters:
INSERT INTO words
(word,
sortedid)
(SELECT TOP 1 #Word,
sortedid
FROM sortedwords
WHERE sortedword = #SortedWord)
And before execiting query create a parameters(C#)
//Assume you have a SqlCommand object(lets name it command)
command.Parameters.AddWithValue("#Word", words[i]);
command.Parameters.AddWithValue("#SortedWord", sortWord(words[i]));

Converting Sql query (update table set ....) to linq ( var m = ...)

I am trying to write a linq query in my Database.cs file. I find it difficult. Is there any tool to convert sql to linq? I tried linqer but it is no good. Or could you help me in writing the following query in linq.
update table
set field1='R',
field2='" + DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss") + "',
field3 = '" + util.CleanStringInput(value1) + "'
where field1 = 'P'
and field3 = '" + value2 + "'
and field4 = (select max(field5)
from table2
where field6='" + value2 + "')
The easiest way would be to fetch the entities, set the properties and then save changes:
var maxFromTable2 = context.YourTables2.
Where(t2 => t2.field6 == value2).
Max(t2 => t2.field5);
var entitiesToUpdate = context.YourTables.
Where(t => t.field1 == "P" &&
t.field3 == value2 &&
t.field4 == maxFromTable2).
ToList();
foreach (var entityToUpdate in entitiesToUpdate)
{
entityToUpdate.field1 = "R";
entityToUpdate.field2 = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss");
}
context.SaveChanges();
NOTE: It is not clear from your question what table you are updating, so I assume by default that it is a table different from table2. It could help if you indicate whether you are using LINQ to SQL or Entity Framework (LINQ to Entitites). The current syntax is for EF.
LINQ to SQL/EF are intended to hydrate objects and operate on those, saving the changes. It is not intended as a replacement for batch operations. If you use EF/LINQ to SQL in this case, you will be issuing n+1 requests to the database: 1 to select the records you are going to change and a separate request for each row (object) you are updating. With a small data set, this may be managable, but if you have any kind of volume, keeping this in a stored proc using a single Update statement may be a better option.