I am haveing strange issue comparing string value. I have a value in SQL with type (nchar) this value equals "text". And I set this value to string variable x, after that I compared the string variable x with the word "text" .
The problem is it shows that x doesn't equal the value "text" even that when I add x value to label, it shows the word "text".
Here is my code:
string x;
using (SqlCommand cmd = new SqlCommand(
"select column from text_table where column = 'text'", sqlCon))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
x = reader["column"].ToString();
if (x.Equals("text"))
{
// run code
}
else
{
label1.Text ="x doesn't equal text";
}
when I use the code it always shos the message "x doesn't equal text" but it should run the code as the value of the string x is "text"
You have used the "nchar" column type, which has a constant length. I am not sure, but trimming before comparison may solve your problem.
Try
x = reader["column"].ToString().Trim();
Also there is a Bug, I think: There is no "x" here in (if (stat.Equals("text")).
Demo:
create table text_table (
col1 nchar(10) ); -- fixed length column
insert text_table(col1) values ('text');
Pay attention to col1+'1' expression
select col1, col1+'1'
from text_table
where col1 = 'text'
What is going on? sql-server really ignores trailing spaces e.g.
select 'OK' where 'text' = 'text ';
returns 'OK'.
But c# doesn't ignore trailing spaces and your if is not true.
What to do?
Use Nvarchar in your db or trim db column with String.Trim() before comparison.
Always use the .Equals() method with StringComparison.OrdinalIgnoreCase
Change your code to
if(x.Equals("text",StringComparison.OrdinalIgnoreCase){
//Do something
}
Related
Basically, I have a some code that takes either an (1) alphanumeric or (2) numeric serial number and increments them. Everything works for the numeric serial numbers, but when I try to insert the alphanumeric serial number, it gives me the "invalid column name" error.
I've looked at a lot of the "invalid column name" posts here and none of them seem to answer my question. I've put breakpoints in and ran the code for both cases (numeric and alphanumeric) and I'm getting the same datatypes. Basically everything seems to line up correctly, so I'm at a loss.
The following code shows how I increment for both cases. Note that for the alphanumeric increment, I am calling a method IncrementAlphaNumeric, which takes the variable 'Output', which is the result of a SQL query that sorts the table and gets the last serial number.
// Increment Numeric Serial Numbers
if (isNum)
{
int lastNumber = Int32.Parse(Output);
int[] ints = Enumerable.Range(lastNumber + 1, printQuantity).Select(i => (int)i / 1).ToArray();
increments = ints.Select(x => x.ToString()).ToArray();
output.AppendText("Serial numbers to print: " + string.Join(", ", increments));
}
// Increment AlphaNumeric Serial Numbers
if (!isNum)
{
for (int i = 0; i < printQuantity; i++)
{
increments[i] = IncrementAlphaNumeric(Output);
snList.Add(increments[i]);
Output = increments[i];
}
output.AppendText("Serial numbers to print: " + string.Join(", ", increments));
}
Finally, I use Stringbuilder in order to insert the data into the database as follows:
// (5) Store new SNs in Database
StringBuilder sb = new StringBuilder();
foreach (string newSns in increments)
{
sb.AppendLine("INSERT INTO [Manufacturing].[dbo].[Device.Devices]([SerialNumber],[DeviceTypeID]) VALUES(" + newSns + "," + dType +")");
}
using (SqlCommand insertCommand = new SqlCommand(sb.ToString(), cnn))
{
var executeNonQuery = insertCommand.ExecuteNonQuery();
}
Again, it works for numeric, but not for alphanumeric. When I put my breakpoints in and step through the code, the datatypes (Strings) are the same for each of the cases, numeric and alphanumeric.
The error message I'm getting is, again, "invalid column name". Basically, the expected results should be that the serial number, regardless of if it's numeric or alphanumeric, should be inserted into the correct table of the database, which is based on the device type (dType).
As explained in comments, you should never concatenate strings to build your sql statement.
In your case I assume that you want to insert multiple records in your database using a single statement. This can be done also using parameters and manually building the VALUES part or your query (This syntax is available from Sql Server 2008)
// Sample values, replace them with your code that builds the increments array
string[] increments = new string[] {"VALUE1", "VALUE2","VALUE3", "VALUE4"};
// Invariant part of your query
string baseQuery = "INSERT INTO [Manufacturing].[dbo].[Device.Devices]([SerialNumber],[DeviceTypeID]) VALUES";
// Fixed value for the type
string dType = "42";
List<SqlParameter> prms = new List<SqlParameter>();
List<string> placeHolders = new List<String>();
// Build a list of parameter placeholders and a list of those parameter and their values
for(int x = 0; x < increments.Length; x++)
{
placeHolders.Add($"(#p{x},{dType})");
prms.Add(new SqlParameter { ParameterName = $"#p{x}", SqlDbType = SqlDbType.NVarChar, Value = increments[x]});
}
// Put the text together
string queryText = baseQuery + string.Join(",", placeHolders);
// This should be the final text
// INSERT INTO [Manufacturing].[dbo].[Device.Devices]([SerialNumber],[DeviceTypeID])
// VALUES(#p0,42),(#p1,42),(#p2,42),(#p3,42)
using (SqlCommand insertCommand = new SqlCommand(queryText, cnn))
{
// Add all parameters to the command...
insertCommand.Parameters.AddRange(prms.ToArray());
var executeNonQuery = insertCommand.ExecuteNonQuery();
}
This is my first project in c#. I have a little experience in Access VBA. I would like to move my apps over to be stand alone programs. I'm querying a table that has training types and dates. I would like to compare some of the types of training against each other based on the dates they were performed. The three training types are RWT010, RWP000, and RWT010BP. If RWT010BP exists and is newer it is the only one I need. Otherwise I need RWT010 and RWP000. I have figured out how to load the values into variables, but I need to be able to work with them. I would like the name of the dateTime value to be the trainType for the same row. That way I can compare them and output the right combination.
My old Access logic looked like this:
LABEL_DATE: IIf(IsNull([RWT010]),"RWT010BP: " & _
Format([RWT010BP],"Short Date"),IIf([RWT010BP]>[RWT010],"RWT010BP: " & _
Format([RWT010BP],"Short Date"),"RWT010: " & _
Format([RWT010],"Short Date") & " & " & "RWP000: " & _
Format([RWP000],"Short Date")))
This is how far I've gotten in c#:
Console.Write("Enter ID: ");
int idnum = Convert.ToInt32(Console.ReadLine());
string sql = "SELECT EXPID, TYPE, DATE_LATEST FROM TRAINING_TABLE where expid =" + idnum;
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = sql;
using (DbDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
int expid = reader.GetInt32(0);
string trainType = reader.GetString(1);
DateTime trainDate = reader.GetDateTime(2);
It looks like the original Access logic has one DB row with three date fields, [RWT010], [RWT010BP], and [RWP000]. But in Oracle that's been normalized so you're getting back multiple rows, each of which has a a datetime field named [DATE_LATEST], and then name field called [TYPE] that's equal to "RWT010", "RWT010BP", or "RWP000".
And you were thinking, you want to handle those RWP000 date values by name, just like in Access. You were right, that's the clearest way to do it, and I'll show you how. I misunderstood what you were asking.
One way to do this would be to write an Oracle stored procedure that duplicates the Access logic. That's not the question you asked, but it's a legitimate way to do it. However, it would be more complicated than the Access version due to the change in the database, and anyway I haven't written Oracle SQL in years and I don't have an Oracle server handy to give me arbitrary, cryptic syntax errors about semicolons and whitespace.
So what I'm going to do is write a loop in C# to grab the datetimes from the DB rows and put them in local variables, and then duplicate the Access logic in C# using those variables instead of fields. It'll be a little verbose compared to the Access version, but sometimes that's how it goes.
int idnum = Convert.ToInt32(Console.ReadLine());
string sql = "SELECT EXPID, TYPE, DATE_LATEST FROM TRAINING_TABLE where expid =" + idnum;
// I don't know how you're using this so I'll just declare it here
// and leave that to you.
String dateLabel = "";
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = sql;
using (DbDataReader reader = cmd.ExecuteReader())
{
DateTime? RWT010 = null;
DateTime? RWT010BP = null;
DateTime? RWP000 = null;
// No need to check reader.HasRows. If it has no rows, reader.Read()
// will return false the first time, that's all.
while (reader.Read())
{
// Doesn't look to me like expid is used
//int expid = reader.GetInt32(0);
string trainType = reader.GetString(1);
DateTime trainDate = reader.GetDateTime(2);
switch (trainType) {
case "RWT010":
RWT010 = trainDate;
break;
case "RWT010BP":
RWT010BP = trainDate;
break;
case "RWP000":
RWP000 = trainDate;
break;
}
}
if (RWT010 == null || RWT010BP > RWT010) {
dateLabel = String.Format("RWT010BP: {0:d}", RWT010BP);
} else {
dateLabel = String.Format("RWT010: {0:d} & RWP000: {1:d}", RWT010, RWP000);
}
}
The original logic was this:
If RWT010 isn't null,
Do A
Otherwise, if RWT010BP > RWT010
ALSO do A
But if none of the above,
Do B
The first two branches do the exact same thing, so we can condense them both into one branch.
"Don't Repeat Yourself", as they say. You don't want to return to this code a year from now, wonder if those two lines were required to be the same, and then guess wrong or else not notice that they are the same, and only change one or the other. It's just a mess.
If you're not familiar with String.Format(), there's a lot to it. In the first argument string, {0} means "insert the second argument here"; {1} means "insert the third", and so on. The ":d" inside the curly braces is optional; it means to pass "d" as format information to the value its inserting. DateTime will interpret that "d" to mean "Short Date". You could also do it like this:
dateLabel = String.Format("RWT010BP: {0}", RWT010BP.Value.ToShortDateString());
Or like this:
dateLabel = "RWT010BP: " + RWT010BP.Value.ToShortDateString();
I have to use RWT010BP.Value in that line instead of just RWT010BP because RWT010BP is declared with a ? after it. That makes it a "nullable" value. A regular DateTime can't be null, but we need to accommodate nulls here.
If you're using C#6, you can do it like this, which I prefer. I didn't use it above because I don't know what version of C# you're on. Always prefer the least amount of "noise" cluttering up the code.
dateLabel = $"RWT010BP: {RWT010BP:d}";
That's the same ":d" as in String.Format("{0:d}", ...) above.
One more thing: idnum is an int, but don't ever concatenate a string value into a SQL string. That's a massive security vulnerability and people here will (rightly, I'm afraid) give you a very hard time for even contemplating it.
Use OracleCommand.Parameters instead, as shown in this answer. I would have used that even in this case, personally, just as a conditioned reflex.
i have to increment a string value by 1, like default value will be AEC00001 and second value will be AEC00002 and so on, how can i achieve this by using c# or sql query.
It looks like a bad design somewhere in your application. Probably you should store number and prefix separately.
But anyway, assuming your prefix is always "AEC" and size of number is five decimal places - you can increment your values like (this is c# solution since you haven't specified if you prefer sql solution to c# one):
string s = "AEC00001";
string s1 = "AEC" +
(Convert.ToInt32(s.Replace("AEC", "")) + 1)
.ToString()
.PadLeft(5, '0');
You cant store 0000 before number in INT format, but you can do something like that:
SELECT RIGHT('0000' + CAST(2 AS varchar(5)) , 5)
OR
SELECT '0000' + CAST(2 AS varchar(5))
Here I used computed column which automatically takes other column and con-cats to it
declare #a table ( a as 'AEC'+b, b nvarchar(max))
insert into #a SELECT RIGHT('00000'+CAST(1 AS VARCHAR(5)),5)union select RIGHT('00000'+CAST(2 AS VARCHAR(5)),5) union select RIGHT('00000'+CAST(3 AS VARCHAR(5)),5)
select * from #a
var originalValue = "AEC00002";
// Get the numeric part (00002)
var stringValue = Regex.Match(originalValue, #"\d+").Value;
// Convert to int
var intValue = Int32.Parse(stringValue);
// Increase
intValue++;
// Convert back to string
originalValue = "AEC" + intValue.ToString("D5");
Result: AEC00003
You may use a computed column:
A computed column is a column that expresses the data that can be used by an other column in the same table. This expression can be non-computed columns or any function and constant. It cannot be a sub-query. Here the computed column is marked as Persisted, so that any update made in the referenced column will be automatically synchronized in the computed column.
For more information, see this article: Auto Incremented Column With VARCHAR and NVARCHAR Data Type in SQL
In JavaScript Use the below function
function autoIncrementCustomId(lastRecordId){
let increasedNum = Number(lastRecordId.replace('ABC','')) + 1;
let kmsStr = lastRecordId.substr(0,3);
for(let i=0; i< 6 - increasedNum.toString().length; i++){
kmsStr = kmsStr+'0';
}
kmsStr = kmsStr + increasedNum.toString();
console.log(kmsStr);
}
autoIncrementCustomId('ABC009999')
I use my double in a select statement:
code:
SqlCommand command = new SqlCommand("SELECT min(Score) FROM "+ table +" WHERE [" + sportEvent + "] < (#result);", connect);
command.Parameters.AddWithValue("#result", result);
everything works fine if double result is an integer but not if result is a comma number (example 11,34) --> it should be 11.34 to work (point instead of comma)
How can I change a double 11,34 into 11.34 ?
It appears that your code sets a string parameter as a constraint for a DB value of numeric type, letting the database do the conversion. This is not a good idea, because it takes control away from your program: should DBA decide to reconfigure your backend database to "understand" commas instead of dots, your program will stop working!
Currently, your double is in a locale-specific format. You need to parse it using the locale-specific format provider, and then set the value that you get back from the parser as the parameter of your SQL query. Assuming that the current culture is one that is using commas as decimal separator, you can do this:
command.Parameters.AddWithValue(
"#result"
, double.Parse(s, CultureInfo.CurrentCulture)
);
You can use this
result.ToString(CultureInfo.InvariantCulture)
You could try changing the variable into string:
result.ToString().Replace(',','.');
This will replace the comma with a dot.
If result is Double then:
command.Parameters.Add("#result", SqlDbType.Float).Value = result
If I want to insert into a database column of type char(2) from C#.
What data type would I use in C#?
If using the following code:
private static SqlParameter addParameterValue(string parameterName, ? parameterValue, SqlCommand command)
{
SqlParameter parameter = new SqlParameter(parameterName, SqlDbType.Char);
parameter.Value = parameterValue;
command.Parameters.Add(parameter);
return parameter;
}
What type would I give to parameterValue?
I already have method like this when the parameterValue is of type string, so this could be a problem when telling the difference between SqlDbType.Char and SqlDbType.Varchar
char, varchar, nchar, nvarchar are actually strings
the size helps to determine how long the string is...
by the way
char has a fixed length, so if you want to have "1" in a char(2) the contents will be actual "1 "
varchar(2) will be "1"
the n part stands for unicode, so everything inside those fields will be in Unicode.
normally we use nvarchar to save some space on the data, as if you have a char(250) the database will always save the full length, as an empty varchar(250) will be nothing.
In our programming language we then use padding to do what char does, for example, in C#
"1".PadLeft(2);
"1".PadRight(2);
will output " 1" and "1 " respectively.
string will work fine if it is 2 characters or shorter
try using AddWithValue method and parce it as string,
it is only a one line. no need to have a seperate method.
command.Parameters.AddWithValue(parameterName, parameterValue);