What is wrong with my CREATE TABLE MySQL syntax? - c#

I am having some trouble with the CREATE IF NOT EXISTS clause.
I am using a C# application to create a MySQL table, the connection to DB has been established so it's not a problem.
The error I am getting is an exception when I try to execute the query, I get the message:
MySql.Data.MySqlClient.MySqlException (0x80004005): You have an error
in your SQL syntax; check the manual that corresponds to your MySQL
server version for the right syntax to use near 'IF NOT EXISTS(price
VARCHAR, time VARCHAR)' at line 1
In debug mode, the immediate window shows my command string as:
CREATE TABLE ticks_14_11_2016 IF NOT EXISTS(price VARCHAR, time
VARCHAR)
From the examples I have seen, this should be the proper syntax. I am not worried about constraints and keys for the time being, I just need the query to execute...
Also, here is the C# code which I use to build the string and execute query:
string tableName = "ticks_" + getTodayString();
if (databaseClient.IsConnect()) {
string tableString = "CREATE TABLE " + tableName +
" IF NOT EXISTS" +
"(price VARCHAR, " +
"time VARCHAR)";
try
{
var command = databaseClient.Connection.CreateCommand();
command.CommandText = tableString;
command.ExecuteNonQuery();
} catch (Exception e)
{
Console.WriteLine(e);
}
}
The variable databaseClient has a member that is the MySQLConnection object
Also, my server version is: 5.6.28-76.1

You have the if not exists in the wrong place, and also, the varchar type needs a mandatory length argument.
A corrected version should be:
CREATE TABLE IF NOT EXISTS ticks_XXXXX (price VARCHAR(10), time VARCHAR(10));
Change the length to whatever is appropriate for you.
For more information see the reference manual.

You have other ways also to check whether table exists in database or not.
IF OBJECT_ID(N'dbo.ticks_14_11_2016', N'U') IS NOT NULL
BEGIN
------Exists
END
IF EXISTS(SELECT 1 FROM sys.Objects WHERE Object_id =
OBJECT_ID(N'dbo.ticks_14_11_2016') AND Type = N'U')
BEGIN
------Exists
END
IF EXISTS(SELECT 1 FROM sys.Tables WHERE Name = N'ticks_14_11_2016 ' AND Type = N'U')
BEGIN
----Exists
END
IF OBJECT_ID('ticks_14_11_2016') IS NOT NULL
BEGIN
-----Exists
END
Use your logic accordingly

Related

IF NOT EXISTS INSERT sql statement not working c#

I am trying to carry out an 'insert if not exists' statement, i am not receiving any errors and the row does not exist in the db, however it still will not add it. Executing a normal 'insert' works but not when the 'if not exists' is added.
I have also tried including BEGIN & END and it doesnt work.
Where am i going wrong??
string getStudentModuleId = "SELECT ModuleId FROM StudentModuleMarks WHERE Mark < 40";
SqlCommand myCommand = new SqlCommand(getStudentModuleId, MyConnection3);
try
{
moduleid = (int)myCommand.ExecuteScalar();
string addRepeat = "IF NOT EXISTS (SELECT * FROM StudentModules WHERE ModuleId = #moduleid AND SchoolYear = '2018') INSERT INTO StudentModules(StudentDegreeId, ModuleId, Repeat, SchoolYear, EnrolledStatus) VALUES (1,#moduleid,1,'2018','Active')";
SqlCommand command = new SqlCommand(addRepeat, MyConnection3);
command.Parameters.AddWithValue("#moduleid", moduleid);
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
It seems you are using sql server, For MySQL, you can follow this technique to insert record if it doesn't exist :
INSERT INTO StudentModules(StudentDegreeId, ModuleId, Repeat, SchoolYear, EnrolledStatus)
select 1,#moduleid, 1, '2018', 'Active' from dual
where NOT EXISTS (SELECT * FROM StudentModules WHERE ModuleId = #moduleid AND SchoolYear = '2018')
Please note that, in MySQL, you don't really need to have a table called dual to exist: it is a special table-name that can be used to select anything from it. And it will output a single record always with a SELECT query like above.

Dapper reporting invalid syntax near parameter name when attempting to pass null in a DynamicParameter

I'm attempting to get all records from a table where a certain field is not a blank string or null. Due to the way I'm building the queries, ISNULL and COALESCE are not options here. Changing the schema of the database is not an option either.
This is the code I'm running to try to retrieve the records.
using System;
using System.Data.SqlClient;
using System.Linq;
using Dapper;
namespace DapperMCVE
{
internal class UserFinder
{
public static void Main(string[] args)
{
using (var connection = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;Integrated Security=True"))
{
connection.Execute(#"IF NOT EXISTS(SELECT * FROM sys.tables WHERE name = 'Users')
CREATE TABLE Users(NullableUserId varchar(50) NULL) ON [PRIMARY]");
connection.Execute(#"DELETE Users");
connection.Execute(#"INSERT INTO Users(NullableUserId)
VALUES(''), (NULL), ('SteveSmith#fake.com'), ('Morgan#totallyreal.org')");
var parameters = new DynamicParameters();
parameters.Add("UserIdNull", (string)null);
parameters.Add("UserIdBlank", "");
try
{
var users = connection.Query(#"SELECT *
FROM Users
WHERE NullableUserId IS NOT #UserIdNull
AND NullableUserId != #UserIdBlank", parameters);
Console.WriteLine(users.ToList());
}
catch (SqlException e)
{
Console.WriteLine(e);
}
Console.ReadKey();
}
}
}
}
The error thrown is System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near '#UserIdNull'.
My assumption is that the above code should replicate this query:
SELECT *
FROM Users
WHERE NullableUserId IS NOT NULL
AND NullableUserId != ''
but it seems to be doing something closer to
SELECT *
FROM Users
WHERE NullableUserId IS NOT 'NULL'
AND NullableUserId != ''
If I change the query to
SELECT *
FROM Users
WHERE ISNULL(NullableUserId, '') != ISNULL(#UserIdNull, '')
it works fine. Unfortunately, I cannot use ISNULL in this case.
I've replicated this in SQL Server 2014 and 2016. We're using 2016 in our production environment.
The profiler reports that the following command is being run:
exec sp_executesql N'SELECT *
FROM Users
WHERE NullableUserId IS NOT #UserIdNull
AND NullableUserId != #UserIdBlank',N'#UserIdNull nvarchar(4000),#UserIdBlank nvarchar(4000)',#UserIdNull=NULL,#UserIdBlank=N''
Which makes me suspect this may be an issue with SQL Server itself?
Things I've tried (to no avail):
Casting the parameter to various nullable types
Using DBNull.Value
You can not use IS NOT and variable. You can hardcode NullableUserId IS NOT NULL if you always expect null.
Or create query text using some string concatenation
IS NOT #UserIdNull genuinely isn't valid SQL syntax.... IS NOT NULL is fine. This isn't a dapper issue - this is simply an SQL feature: you need to write legal SQL.
My assumption is that the above code should replicate this query:
Nope. It uses parameters. The syntax is retained. Dapper does not inject literals. This is very deliberate and correct. I wrote about this yesterday, as it happens.
You cannot use IS NOT and parameter in sp_executesql or anywhere else.
Look at this example.
This query returns 4 records from my table :
exec sp_executesql
N'SELECT * FROM tblUser WHERE gsm IS NOT null AND gsm != '''''
So now I try it with parameters for both values, and now I get an error
exec sp_executesql
N'SELECT * FROM tblUser WHERE gsm IS NOT #UserIdNull AND gsm <> #UserIdBlank',
N'#UserIdNull nvarchar(100),#UserIdBlank nvarchar(100)',
#UserIdNull=NULL,#UserIdBlank=N''
but now I get the error
Incorrect syntax near '#UserIdNull'
It will give the same error when you do it without sp_executesql
declare #UserIdNull nvarchar(100) = null
declare #UserIdBlank nvarchar(100) = ''
SELECT * FROM tblUser WHERE gsm IS NOT #UserIdNull AND gsm <> #UserIdBlank
This produces the same error
So the only option you have is to build your query without a parameter for the IS NOT value or use ISNULL()
In the query you build in your question, you known when to write IS NOT and then followed by a parameter.
I suggest to simply write IS NOT NULL in stead of using a parameter there

SQL Exception Error C# ASP.Net

It's been awhile since I've messed with anything SQL, and I'm trying to build a little Todo app to learn some ASP.Net with C#. I'm using Visual Studio 2013 with whatever version of SQL Express it comes packaged with, all locally.
I have the following table todo_list, made with the following script, through Visual Studio:
CREATE TABLE [dbo].[todo_list] (
[id] INT NOT NULL,
[task] TEXT NOT NULL,
[complete] BIT NOT NULL,
[date] DATE NOT NULL,
PRIMARY KEY CLUSTERED ([id] ASC)
);
When the web application starts, I'm trying to get all of the records where complete is false. I'm assuming I can read/write to the complete column as true/false because of it being of type bit.
I get an exception thrown when the following code goes to execute...
private void Get_Tasks()
{
//Get the connection string
SqlConnection connection = new SqlConnection();
connection.ConnectionString = System.Configuration.ConfigurationManager.
ConnectionStrings["Database1ConnectionString"].ConnectionString;
//Build SQL query
string query = "SELECT * FROM todo_list WHERE complete=False";
System.Diagnostics.Debug.WriteLine(query);
//Build SQL Command Object
SqlCommand command = new SqlCommand(query, connection);
//Grab all uncompleted tasks from database
SqlDataReader cursor;
try
{
using(connection)
{
//Open and execute SQL stuffz...
connection.Open();
cursor = command.ExecuteReader();
//Get all the tasks
while (cursor.Read())
{
//Build the task from record set
Todo task = new Todo(
(int)cursor["id"], (string)cursor["task"],
(bool)cursor["complete"], (DateTime)cursor["date"]);
//Append to DOM
Page.ClientScript.RegisterStartupScript(this.GetType(), "alert" + UniqueID, "alert('About to append to DOM!');", true);
tasklist.InnerHtml = task.toHtml();
}
//Close connection
connection.Close();
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.ToString());
connection.Close();
}
//TODO - Grab all completed tasks from database
}
The Exception that is thrown when cursor = command.ExecuteReader(); executes -
A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll'
System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'False'.
I have no idea why it is taking False as a column name?
Thanks in advance for any help!
You can change the False for 0 or for 'False'
Example
Your SQL query is invalid. Did you read the error message?
Have you tried running in in SQL Server Management Studio (assuming your using SQL Server...if not, the interactive tools of choice)?
Your query
select *
from todo_list
where complete = False
is [trying to, anyway] selecting all the rows from the table todo_list where the table's two columns complete and False are equal. Since your table has no column named False, SQL Server's query compiler gives you the obvious error::
Invalid column name 'False'
SQL Server's bit datatype is not a boolean in the C# sense. It's fundamentally a 1-bit integer whose domain is {0,1}. You need to rephrase your query like this:
select *
from todo_list
where complete = 0
The CLR bidirectionally maps SQL Server's bit to a CLR System.Boolean. If the bit column is nullable, any SQL Server null values will be mapped to the sole instance of System.DbNull.

Call procedure on another database with user defined table type

I have a connection to a database with right to another. I want to call a procedure on the other database which has a user table data type parameter. But the user table data type isn't found whatever I try.
I tried using database name in front of [dbo].[myType] but it's not a valid syntax.
I tried creating the same type in the current database
I tried creating the same type in the model database
I tried appending "USE MyOtherDatabase" at the top of my SqlCommand.Text
Everything failed (I'm really abashed the "USE ..." approach failed).
How can I do that?
Sample of code:
// While connected to MyOtherDatabase
CREATE TYPE dbo.typeClubMembersVersion AS TABLE (
ID INT
, UNIQUE(ID)
, [version] INT
)
GO
CREATE PROCEDURE dbo.spCheckCMembersMods (
#pVersions AS dbo.typeClubMembersVersion READONLY
, #pWhoID AS BIGINT
)
AS
BEGIN
[...]
END
SqlCommand com = new SqlConnection(functions.ConnectionString).CreateCommand();
com.CommandText = #"
// While connected to CurrentDatabase
USE MyOtherDatabase
DECLARE #tbl AS dbo.typeClubMembersVersion
BEGIN TRANSACTION
UPDATE dbo.tClubMembers
SET
Title = #Title
OUTPUT inserted.ID, deleted.[version] INTO #tbl (ID, [version])
WHERE IdMember = #IdMember
EXEC dbo.spCheckCMembersMods #tbl, #whoID
COMMIT
";
com.Parameters.Add("#Title", SqlDbType.NVarChar, 20).Value = this.Title;
com.Parameters.Add("#IdMember", SqlDbType.BigInt).Value = this.Id;
com.Parameters.Add("#whoID", SqlDbType.BigInt).Value = (object)whoID ?? DBNull.Value;
com.Connection.Open();
try
{
com.ExecuteNonQuery();
}
catch (Exception exe)
{
throw exe;
}
finally
{
com.Connection.Close();
}
First, what you are calling "Schemas" are actually "Databases" in SQL Server. The "dbo." in your object names is a "Schema" in SQL Server. The "USE.." command only works on Databases.
Secondly, you cannot reference or use Types from another database, it has to be defined in the same database(s) that it is used in. Types can be in other SQL Server schemas, but not in other Databases, which is what you are actually trying to do here.
OK, as you noted, your Type is defined in [myOtherDatbase] so why doesn't it work? Probably because the USE.. and SQL command strings do not work the way you might think. Whenever you pass a string like this to SQL Server and try to execute it:
com.CommandText = #"
// While connected to CurrentDatabase
USE MyOtherDatabase
DECLARE #tbl AS dbo.typeClubMembersVersion
BEGIN TRANSACTION
UPDATE dbo.tClubMembers
SET
Title = #Title
OUTPUT inserted.ID, deleted.[version] INTO #tbl (ID, [version])
WHERE IdMember = #IdMember
EXEC dbo.spCheckCMembersMods #tbl, #whoID
COMMIT
";
SQL Server will first compile the entire string and then try to execute it. This means that all of the commands are compiled first before any of them are executed. And that means that your DECLARE #tbl and UPDATE.. commands are compiled before the USE command is executed. So when they are compiled you are still in the previous database where the Type has not been defined. This is what leads to your syntax errors (which are coming from the compiler, not from their execution).
There are three possible solutions:
Define the Type in currentDatabase also (I am pretty sure that this works, but not 100%).
Reconnect with a connection string that specifies "Initial Catalog=MyOtherDatabase".
Re-execute everything after your USE command with Dynamic SQL.
Of these I would recommend #2.
Silly me, I just realized that there is another option:
First execute just the USE command by itself,
then, execute the rest of the SQL commands on the same connection.
Of course this will leave you in [MyOtherDatabase], so you may want to end this by executing another USE command back to your original database.
It's been such a very long time since I had to use SqlConnection.ChangeDatabase I fergot about it. Until now I've always been able to use "fully named objects" to make my databases interract with each other.
Since I'm currently stuck I'll use it but I hope somebody tells me a way that don't force me to let go the current database connection.
SqlCommand com = new SqlConnection(functions.ConnectionString).CreateCommand();
com.CommandText = #"
DECLARE #tbl AS dbo.typeClubMembersVersion
BEGIN TRANSACTION
UPDATE dbo.tClubMembers
SET
Title = #Title
OUTPUT inserted.ID, deleted.[version] INTO #tbl (ID, [version])
WHERE IdMember = #IdMember
EXEC dbo.spCheckCMembersMods #tbl, #whoID
COMMIT
";
com.Parameters.Add("#Title", SqlDbType.NVarChar, 20).Value = this.Title;
com.Parameters.Add("#IdMember", SqlDbType.BigInt).Value = this.Id;
com.Parameters.Add("#whoID", SqlDbType.BigInt).Value = (object)whoID ?? DBNull.Value;
com.Connection.Open();
try
{
com.Connection.ChangeDatabase("MyOtherDatabase");
com.ExecuteNonQuery();
}
catch (Exception exe)
{
throw exe;
}
finally
{
com.Connection.Close();
}

Can you use a SQLParameter in the SQL FROM statement?

I am trying to create a parameterized query in C# against a SQL server database.
Code:
query = new StringBuilder( "SELECT #fields FROM #tables");
using(SqlConnection connection = new SqlConnection(connection))
{
SqlCommand command = new SqlCommand(query.ToString(), connection);
command.Parameters.AddWithValue("#fields", fields.ToString());
command.Parameters.AddWithValue("#tables", tables.ToString());
try
{
connection.Open();
Int32 rowsAffected = command.ExecuteNonQuery();
Console.WriteLine("RowsAffected: {0}", rowsAffected);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
The strange part is this fails with the message "Must declare the table variable \"#tables\". However as you can see, it's clearly been defined.
So my question is:
Can you pass a parameter to define
the table list in the FROM
statement?
If you can, why isn't
this working?
SQL doesn't support the FROM clause to be parameterized. So you have to use either dynamic SQL, or create/concatenate the query string prior to submitting it to the database.
No unfortunately you cant use a parameter in the FROM clause.
I think this is not the way SQL command and its parameters should look like. It should look like
SELECT fieldName1, fieldName2
FROM TableName
WHERE fieldName = #paramName
You cannot use parameters as definition of fields to be selected or the target table. If you need to define fields to be selected, simply compose the command string in StringBuilder before you call it - as you need. Parameters are used for filtering purposes. In your case you don't need any paramters, just build your command and execute.
If you're confident that your table and column names are ok, then you can do some safety checks in the database before building your dynamic SQL.
This is just for illustration - for real life, obviously you'd need to make it a lot cleaner:
declare #TABLE_NAME nvarchar(128)
set #TABLE_NAME = 'Robert'');DROP TABLE Students;--' -- This line will raise an error
set #TABLE_NAME = 'BOOK' -- This line will go through properly
declare #sql varchar(max)
set #sql = 'SELECT * FROM '
if exists (select 1 from sys.objects where type = 'U' and name = #TABLE_NAME)
begin
set #sql = #sql + #TABLE_NAME
exec (#sql)
end
else
begin
raiserror ('ERROR ERROR ERROR', 0, 0)
return
end

Categories