i have an sql insert query in my website,which inserts a few strings and ints, and a datetime in "dd/MM/yyyy HH:mm:ss", and until today it worked great. however, from today, for some odd reason, during the executeNonQuery method of the query, the format of the datetime changes to "MM/dd/yyyy HH:mm:ss". i have no clue as for why this is happening, and it is driving me crazy. can anyone please shed some light on why this happens and how i can prevent this change? any help would be appreciated.
the query:
"INSERT INTO Orders(OrderDate,MemberID,CityID,OrderAdress,CreditCardID,OrderStatus)VALUES(#" + o.OrderDate + "#," + o.MemberID + ","+o.CityID+",'" + o.OrderAdress + "',"+o.CreditCardID+",'Not sent')"
o is an object holding all of the data.
Big problem when trying to build a query when concatenating strings. This is a HUGE thing for exposure to SQL-Injection. The best way to do it is with using PARAMETERIZED queries and you can look all over and find them, you probably were just unaware of them.
Basically in your query, you use a "?" as a place-holder for the parameter you want, then add a parameter object with the actual value / data type and the OleDb querying will put it in its place and have proper data type so you don't have to worry about formatting the string from a date in a specific order.
Also, for names, what if you had a person's name of "O'Conner". You have just pre-terminated your query string and would fail otherwise. You would be severely scratching your head.
Having said all that, lets get back to your query, make it a little more readable, and parameterize it...
You refer to ms-access as the database and OleDb which implies you are writing in either C#, or VB, maybe other. I will demonstrate using C#, you could change as needed to your dev language.
using(OleDbConnection connection1 = new OleDbConnection( WhateverYourConnectionString )
{
connection1.Open();
using(OleDbCommand sqlcmd = new OleDbCommand("", connection1))
{
// simplified query and you can see the "?" place-holders
sqlcmd.CommandText =
#"INSERT INTO Orders
( OrderDate,
MemberID,
CityID,
OrderAdress,
CreditCardID,
OrderStatus )
VALUES
( ?,
?,
?,
?,
?,
'Not sent' )";
// Now, add your parameters in the SAME ORDER as the "?" in the query
sqlcmd.Parameters.AddWithValue("parmForDate", o.OrderDate );
sqlcmd.Parameters.AddWithValue("parmForMember", o.MemberID );
sqlcmd.Parameters.AddWithValue("parmForCity", o.CityID );
sqlcmd.Parameters.AddWithValue("parmForAddress", o.OrderAddress );
sqlcmd.Parameters.AddWithValue("parmForCard", o.CreditCardID );
// since the last parameter is fixed, you can put that in explicitly.
// you can similarly put fixed field of other strings, numbers.
// Now you can execute it
sqlcmd.ExecuteNonQuery();
}
connection1.Close()
}
A DateTime value holds no format, but if you wish to concatenate, do force a format on the string expression for the value:
"INSERT INTO Orders(OrderDate,MemberID,CityID,OrderAdress,CreditCardID,OrderStatus) VALUES(#" + o.OrderDate.ToString("yyyy'/'MM'/'dd") + "#," + o.MemberID + "," + o.CityID + ",'" + o.OrderAdress + "'," + o.CreditCardID + ",'Not sent')"
Still, much simpler to use parameters.
Related
Trying to create a VB.net expression to select rows from a datatable that only have a certain vendor's name (Vendor column), and the event is after a certain date (PurchaseDate column).
My current approach is to use:
datatableVar.Select("Vendor = '" + vendorName.ToString + "' And PurchaseDate < Convert('" + eventDate.ToString + "', DateTime)")
Currently it is saying that DateTime is an invalid Type name, pretty sure this is the syntax for convert though and it takes DateTime as a thing to format to.
The best option depends on exactly what you want to do with the data afterwards but, assuming that you want to stick with that Select method, there's no need to call Convert because you can just use a DateTime literal:
datatableVar.Select($"Vendor = '{vendorName}' AND PurchaseDate < #{eventDate:M/dd/yyyy}#")
Note that I have also used string interpolation rather than concatenation, in order to aid readability. If you're using an earlier version than VB 2015, use String.Format instead:
datatableVar.Select(String.Format("Vendor = '{0}' AND PurchaseDate < #{1:M/dd/yyyy}#",
vendorName,
eventDate)
The reason that your original code didn't work is that you didn't do what the documentation tells you to do when calling Convert. The example in the documentation is this:
myDataColumn.Expression = "Convert(total, 'System.Int32')"
So you can see there that the type is qualified with the namespace and it is wrapped in single quotes. That means that:
"', DateTime)")
should have been:
"', 'System.DateTime')")
ALWAYS read the relevant documentation first.
If you look at the stuff commented out, I can easily get this to work by adding user input directly in to the query, but when I try to parameterize it, none of the values are being added to the parameters...
This code is throwing an error
Must define table variable #formTable
but the issue is none of the values are adding, not just the table variable (verified by replacing table name variable with static text).
I have many insert statements in this project structured exactly like this one which work perfectly. What am I doing wrong here?
string constr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
//string query = "UPDATE " + s.formTable + " SET " + s.column + " = '" + s.cellValue + "' WHERE MasterID = '" + s.id + "'";
string query = "UPDATE #formTable SET #column = #cellValue WHERE MasterID = #id;";
using (SqlCommand cmd = new SqlCommand(query))
{
//SqlParameter param = new SqlParameter("#formTable", s.formTable);
//cmd.Parameters.Add(param);
cmd.Parameters.AddWithValue("#formTable", s.formTable);
cmd.Parameters.AddWithValue("#column", s.column);
cmd.Parameters.AddWithValue("#cellValue", s.cellValue.ToString());
cmd.Parameters.AddWithValue("#id", s.id.ToString());
cmd.Connection = con;
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
Parameters are for values, not object identifiers (tables, columns, etc.), so the only valid parameters you have are #cellValue and #id.
If you want to dynamically set table/column names based on user input, you're likely looking at string concatenation. However, that doesn't necessarily mean SQL injection. All you need to do is validate the user input against a set of known values and use the known value in the concatenation.
For example, suppose you have a List<string> with all of your table names. It can be hard-coded if your tables are never going to change, or you can make it more dynamic by querying some system/schema tables in the database to populate it.
When a user inputs a value for a table name, check if it's in the list. If it is, use that matching value from the list. If it isn't, handle the error condition (such as showing a message to the user). So, even though you're using string concatenation, no actual user input is ever entered into the string. You're just concatenating known good values which is no different than the string literals you have now.
I am working with asp classical.
I am trying to take information from the user and then insert into my database.
the error is "no value given".
on line: myCon.Execute(sql);
I think it is coming from my sql statement.
var myCon, myRec, sql;
myCon = new ActiveXObject ("ADODB.Connection");
myCon.Open ("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\Users\\abc.mdb");
var bodyType = parseInt(Request.Form("cbBodyType"));
var education = parseInt(Request.Form("cbEducation"));
var eyes = parseInt(Request.Form("cbEyes"));
var hairs = parseInt(Request.Form("cbHairs"));
var heights = parseInt(Request.Form("cbHeights"));
var religion = parseInt(Request.Form("cbReligion"));
var memberID = parseInt(Session("MemberID"));
sql = "INSERT INTO Profiles (MemberID, Religion, HairColor, Eye, Education, Height, BodyType) VALUES ("+memberID+", "+religion+", "+hairs+", "+eyes+", "+education+", "+heights+", "+education+")";
myCon.Execute(sql);
myCon.Close();
EDIT: The problem is the logic. I have for example table HairColor that has an ID and a Description. ID is a primary key and its foreign key is in table Profile.
When my user enters the information, i would like to recuperate the combobox value, get the ID and then do an INSERT INTO PROFILES.
Is there an easy way to do it instead of using a lot of "where statement" ?
Try the use the following variant of code
myCon.Execute sql, 0
(without parenthesis)
My guess is that one of the following is happening:
One of the columns you are trying to populate could be a string-valued column. In that case, you need to surround your value argument with single quotes, as in this simplified-for-clarity example below:
sql = "INSERT INTO Profiles (MemberID, Religion) VALUES (" _
+ memberID + ",'" + religion + "');"
Alternatively, if you have a - All - or Please Select option as the top and default option in one of your combo boxes, and you haven't specified a value for that option, you could be returning a blank/empty string as a value. That would lead to this as the resulting (simplified-for-clarity) SQL:
Sql = "INSERT INTO Profiles (MemberID, Religion) VALUES( 235, );"
Note the absence of a value for the second column. I would have expected you to get a syntax error message instead, though, if that's what was happening.
Be aware that by doing your SQL this way, assembling a string from posted values rather than using SQL parameters, you are opening the door for a SQL injection attack. It's not a good idea.
When i am trying to execute the following command i get the following output error.
("INSERT INTO Leaves (EmpID,TotalLeavesRemaining,Year)
SELECT EmpID,TotalLeavesRemaining,'" + year + "'
FROM Leaves
WHERE Year = '" + yearbefore + "' ", con)
Additional information: Conversion from string
INSERT INTO Leaves (EmpID,TotalL" to type 'Double' is not valid.
When i run the command directry through the sql management studio the query does its job !
If you really need to concatenate SQL string then convert your year to string or join using & instead of +
("INSERT INTO Leaves (EmpID,TotalLeavesRemaining,Year)
SELECT EmpID,TotalLeavesRemaining,'" + year.ToString + "'
FROM Leaves
WHERE Year = '" + yearbefore.ToString + "' ", con)
If you put single quotes around your year number it makes it a string. But apparently your year column is of type double. (Why? Shouldn't' it be of type int?). Remove the single quotes!
And also use command parameters. This makes it safer, less error prone and also faster, as the SQL-Server can cache the query and reuse it without having to recompile it and to create an execution plan again.
using (var cmd new SqlCommand(#"INSERT INTO Leaves (EmpID, TotalLeavesRemaining, Year)
SELECT EmpID,TotalLeavesRemaining, #year
FROM Leaves
WHERE Year = #yearbefore", con)) {
cmd.Parameters.AddWithValue("#year", 2015);
cmd.Parameters.AddWithValue("#yearbefore", 2014);
...
}
Note that you don't need any quotes around parameters, even for string parameters. They free you from escaping strings, formatting numbers and dates.
If you want to use multiline strings, use verbatim strings introduced with an #. These string literals can span multiple lines and don't interpret the backslash (\) as an escape character. Single quotes can be escaped by double single quotes.
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.