In my database, I have 2 schemas: [dbo] and [rch] ([rch] was selected as the name for our "archived" data so that those tables would not appear before the [dbo] tables).
I created a user for this table called rchuser in SQL Server Management Studio (SSMS):
Notice above that the user is added with rch listed as the Default Schema.
Notice above that this new user owns both db_owner and rch.
Let's say I have this SQL insert:
public static int AddRecord(object value, string sqlConnection)
{
int result = 0;
using (var conn = new System.Data.SqlClient.SqlConnection(sqlConnection))
{
conn.Open();
var sqlCmd =
"INSERT INTO Table1 ([Value], [Stamp]) " +
"VALUES (#Value, GETDATE()); ";
using (var cmd = new System.Data.SqlClient.SqlCommand(sqlCmd, conn))
{
cmd.Parameters.AddWithValue("#Value", value);
result = cmd.ExecuteNonQuery();
}
}
return result;
}
I passed that method a connection string using my rchuser credentials.
var conn = "Data Source=localhost;Initial Catalog=DatabaseN;User Id=rchuser;Password=password;"
There is no error, result is 1, but the new record is NOT in the corresponding table for my [rch] schema.
It is like the database is completely ignoring the fact that this user defaults to the [rch] schema.
I even tried logging into the SSMS database with rchuser to execute the command by hand. Again, no errors. The data went into [dbo].
How do I direct all database input to go to another schema?
If you have multiple schemas in a database, then my recommendation is to always explicitly specify which one you want. Aaron Bertrand has a good article on why you should do it, even if you only have one schema.
So modify your sql statement to be
INSERT INTO [rch].Table1...
and you will be all good.
I do note that this doesn't answer your title, but it does answer your question.
As to why your query isn't defaulting to the [rch] schema, I don't know. I replicated your setup in SQL Server 2008 R2, and when I run your original query then the inserts do go into the rch table as expected.
EDIT:
I did some Googling, and I suspect that your problem is caused by granting the sysadmin server role to the rchuser login. I modified mine to be an sa
, and now the inserts go into the [dbo] schema by default, even though rchuser has a default schema of [rch].
So, if you remove the sysadmin server role, it should start working as expected.
Have You tried to specifiy schema for table in Your query?
var sqlCmd =
"INSERT INTO rch.Table1 ([Value], [Stamp]) " +
"VALUES (#Value, GETDATE()); ";
Related
I'm using Signalr with SqlDependency. My code works and it shows me realtime results like I wanted. But the issue is it is working my newly created database. If I change the database to old one the SqlDependency stops work and not getting the change detection on my database table.
Below is my code:
#region SignalRMethods
[System.Web.Script.Services.ScriptMethod()]
[System.Web.Services.WebMethod(EnableSession = true)]
public GlobalApplicationError[] GetErrorsList()
{
var cs = "Data Source=.;Initial Catalog=NotifyDB;Integrated Security=True";
using (var connection = new SqlConnection(cs))
{
connection.Open();
SqlDependency.Start(cs);
using (SqlCommand command = new SqlCommand(#"SELECT [Form_Name],[Message],[Prepared_By_Date] FROM [GlobalApplicationError]", connection))
{
// Make sure the command object does not already have
// a notification object associated with it.
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
using (var reader = command.ExecuteReader())
return reader.Cast<IDataRecord>()
.Select(x => new GlobalApplicationError()
{
Form_Name = x["Form_Name"].ToString(),
Message = x["Message"].ToString(),
Prepared_By_Date = Convert.ToDateTime(x["Prepared_By_Date"])
}).ToList().ToArray();
}
}
}
private static void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
MyHub.Show();
}
#endregion
Above code perfectly works on database NotifyDB but not on my existing one which is eprocure if I change the database in my connection string. As I'm using the asmx web service so I always update the reference of my web service. Plus I've enable_broker set to true on both databases.
Database screen shots:
NotifyDB
eprocure
output
Kindly let me know what I'm doing wrong in my code. Thanks in advance.
Let windup this. After some brainstorming on internet I successfully found my answer.
I've Checked my database sys.transmission_queue using below query:
select * from sys.transmission_queue
As most likely our notification(s) will be there, retained because they cannot be delivered. The transmission_status have an explanation why is this happening.
I found that there is below error:
Error: 15517, State: 1. Cannot execute as the database principal because the principal "dbo" does not exist
Google it and found the below useful link:
Troubleshooting SQL Server Error 15517
after that I run the below query which is briefly defined in above link
EXEC sp_MSForEachDB
'SELECT ''?'' AS ''DBName'', sp.name AS ''dbo_login'', o.name AS ''sysdb_login''
FROM ?.sys.database_principals dp
LEFT JOIN master.sys.server_principals sp
ON dp.sid = sp.sid
LEFT JOIN master.sys.databases d
ON DB_ID(''?'') = d.database_id
LEFT JOIN master.sys.server_principals o
ON d.owner_sid = o.sid
WHERE dp.name = ''dbo'';';
By doing this, I found several databases that sys.databases said had an owner. However, when I checked it from the database's sys.database_principals, the SID didn't match up for dbo. The column I had for dbo_login came back NULL. That was a clear sign of the issue. There is also the possibility you will see a mismatch between dbo_login and sysdb_login. It appears that as long as dbo_login matches a legitimate login, the error is not generated. I found that on some DBs on one of my servers. While it's not causing a problem now, I'll be looking to correct the mismatch.
Correcting the Error:
The easiest way to correct the error is to use ALTER AUTHORIZATION on the databases which have the NULL login match for dbo. It's as simple as:
ALTER AUTHORIZATION ON DATABASE::eprocure TO sa;
So finally. I got what I want and my SQL Dependency is working fine. This is all from my end. Thanks you help me on this post. I appreciate for your precious time. Happy Coding.
Please make sure Query Notifications & Service broker are enabled and permissions for the IIS identify are granted.
Steps to enable : https://techbrij.com/database-change-notifications-asp-net-signalr-sqldependency
To check service broker is enabled execute the below statement
SELECT name, is_broker_enabled FROM sys.databases
To enable service broker
ALTER DATABASE <<DatabaseName>> SET ENABLE_BROKER
To grant permission to a user
GRANT SUBSCRIBE QUERY NOTIFICATIONS TO “<<USERIDENTITY>”
I defined a linked server to a remote server in my local SQL Server.
I run a query in join of local and remote servers as below:
SELECT *
FROM [RemteServer].[RemoteDB].[dbo].[Links]
WHERE Id NOT IN
(
SELECT ExternalId
FROM [dbo].[Links]
)
When I run this query on SQL Server Management Studio, It executes during 2 minutes, but when I run it on a C# program on my local machine connected to local SQL Server it produces timeout error.
I set connect timeout on C# connection string to 600. also I set Connection timeout and Query timeout on Linked Server properties to 600.
How can I prevent timeout error?
P.S: SQL server version is 2008. I use Visual Studio 2015 and use ADO connection on VS.
My recommendation would be to migrate the bulk of this query onto the SQL Server, and use a stored procedure to do the work.
SQL Server
CREATE PROCEDURE dbo.lsp_GetRemoteLinks
AS
BEGIN
IF OBJECT_ID('tempdb..#RemoteLinks') IS NOT NULL DROP TABLE #RemoteLinks
SELECT *
INTO #RemoteLinks
FROM [RemteServer].[RemoteDB].[dbo].[Links]
SELECT *
FROM #RemoteLinks
WHERE (Id NOT IN (SELECT ExternalId FROM [dbo].[Links] ))
DROP TABLE #RemoteLinks
END
GO
C#
DataTable RemoteLinks = new DataTable();
using (SqlConnection conn = new SqlConnection(strConn)) {
conn.Open();
using (SqlCommand cmd = new SqlCommand("lsp_GetRemoteLinks", conn)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 120;
RemoteLinks.Load(cmd.ExecuteReader());
}
conn.Close();
}
This should cut your times down, but I did put increase the CommandTimeout value.
If this data did not need to be "live" with it's freshness I would consider making a permanent local table and use SQL Agent to re-populate it at regular intervals, and then you would be able to use Indexes on the table to improve efficiency further.
Your performance on this query is not ideal because you are essentially trying to read every record from the Linked server onto your Local server where the query is being executed. If you can filter the results by adding a WHERE clause that will be executed on the remote server, your performance will significantly improve.
DECLARE #ExtLinks TABLE (Id INT)
INSERT INTO #ExtLinks (Id)
SELECT ID
FROM [RemteServer].[RemoteDB].[dbo].[Links]
--WHERE Princess = 'Zelda'
SELECT * FROM #ExtLinks
WHERE Id NOT IN
(
SELECT ExternalId
FROM [dbo].[Links]
)
I am currently writing my first .Net & C# application with Visual Studio, and have a need to write generated values to MySQL from the application.
At present, I can write values fine - but I need to be able to check to see if a value exists and display that line if it does exist, otherwise insert new line to table. My connection string is defined at the top of the form.
I have the following defined already, and it writes to the database successfully if no duplicate values exist in the LicenseKey column. If a duplicate exists, it throws an unhandled exception.
private void SaveDetails()
{
// MySQL 'insert' command
string InsertNewLicense = "insert into BCOM.LicenseDetails(LicenseeName,ComputerName,ContactName,ContactEmail,LicenseKey,CreationDate) values('" +this.textBoxLicenseeName.Text+ "','" +this.textBoxComputerName.Text+ "','" +this.textBoxContactName.Text+ "','" +this.textBoxContactEmail.Text+ "','" +this.textBoxLicenseKey.Text+ "','" +this.textBoxCreationDate.Text+ "');";
//MySQL instance details
MySqlConnection InsertLicenseDetails = new MySqlConnection(LicenseDatabaseConnection);
//MySQL command execution
MySqlCommand InsertCommand = new MySqlCommand(InsertNewLicense, InsertLicenseDetails);
// Handles command outputs.
MySqlDataReader InsertReader;
//Opens connection to run query on database
InsertLicenseDetails.Open();
// Here our query will be executed and data saved into the database.
MessageBox.Show("License Details Saved. Please ensure you have emailed the license to the customer.");
while (InsertReader.Read())
{
}
InsertLicenseDetails.Close();
}
What I want to happen is for a check to be run on the LicenseKey column to see if the value exists, before different actions are taken.
If the value does not exist, I would like to insert the new line to the table (like my existing command does).
If, however, the value does exist, I would like to pop up a form showing the values from the line that the duplicate appears in as a form.
Where would I put in an event handler to read MySQLException values? What exception would I have to respond to for a duplicate value or no database response?
I agree with what the others have said in their comments, you could change the SQL Query to do the check instead of having 2.
IF(SELECT ... WHERE A = B)
RETURN THAT THE VALUE ALREADY EXISTS
ELSE
INSERT NEW VALUE
Also there was a good comment about SQL Injection and parameterized queries. The query string should look a bit more like
INSERT into BCOM.LicenseDetails(LicenseeName,ComputerName,ContactName,ContactEmail,LicenseKey,CreationDate) values(#LicenseeName, #ComputerName, #ContactName ...);
and your SqlCommand be parameterized
InsertCommand.Paramaters.AddWithValue("#LicenseeName", this.textBoxLicenseeName.Text);
InsertCommand.Paramaters.AddWithValue("#ComputerName", this.textBoxComputerName.Text);
...
That should be a good start to get you going.
After looking at the queries for a while I decided to try a different tack - instead of using a direct check if it's there, I opted to use a count(*) query. When I click the save button on the form, the buttonClick_event calls SaveDetails(), which runs the following:
private void SaveDetails()
{
string InsertNewLicense = "INSERT into BCOM.LicenseDetails(LicenseeName,ComputerName,ContactName,ContactEmail,LicenseKey,CreationDate) values(#LicenseeName, #ComputerName, #ContactName, #ContactEmail, #LicenseKey, #CreationDate)";
string LicenseExistence = "SELECT COUNT(*) FROM BCOM.LicenseDetails WHERE LicenseKey LIKE #LicenseKey";
MySqlConnection LicenseDetails = new MySqlConnection(LicenseDatabaseConnection);
MySqlCommand InsertCommand = new MySqlCommand(InsertNewLicense, LicenseDetails);
InsertCommand.Parameters.AddWithValue("#LicenseeName", this.textBoxLicenseeName.Text);
InsertCommand.Parameters.AddWithValue("#ComputerName", this.textBoxComputerName.Text);
InsertCommand.Parameters.AddWithValue("#ContactName", this.textBoxContactName.Text);
InsertCommand.Parameters.AddWithValue("#ContactEmail", this.textBoxContactEmail.Text);
InsertCommand.Parameters.AddWithValue("#LicenseKey", this.textBoxLicenseKey.Text);
InsertCommand.Parameters.AddWithValue("#CreationDate", this.textBoxCreationDate.Text);
MySqlCommand QueryCommand = new MySqlCommand(LicenseExistence, LicenseDetails);
QueryCommand.Parameters.AddWithValue("#LicenseKey", this.textBoxLicenseKey.Text);
MySqlDataReader InsertReader;
LicenseDetails.Open();
if ((int)(long)QueryCommand.ExecuteScalar() >0)
{
MessageBox.Show("This license already exists in the database.");
}
else
{
InsertReader = InsertCommand.ExecuteReader();
MessageBox.Show("License Details Saved. Please ensure you have emailed the license to the customer.");
while (InsertReader.Read())
{
}
}
LicenseDetails.Close();
So, if the query against the license keys returns with any results at all (more than 0 rows returned), a messagebox pops up showing that the key already exists. If the resultant number of rows is 0, the insert command gets run.
This was figured out with a look through MySQL command notes, testing with phpMyAdmin, matching against existing projects online, and support from the following:
The SELECT query was figured out with great support from #Seige.
The query was parameterized with help from Seige, following on from the advice of Sani Huttunen. Many thanks to them both.
Changing to the count method was done on the advice of a fellow coder in another community online - a good friend and brilliant coder.
How do I insert data into a .dbf format database using SQL in Visual c#?
Is it same as when using MS Access?
OleDbConnection dbConn = new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\wz\Desktop\UBS\onetimecapture\onetimecapture\onetimecapture\bin\Debug\;Extended Properties=dBase IV;");
try
{
// Open connection.
dbConn.Open();
//string queryCutting = "INSERT INTO cuttingstatus.dbf ([Status]) VALUES(adddate)";
string queryCutting = "INSERT INTO cuttingstatus.dbf VALUES(adddate)";
OleDbCommand command_cutting = new OleDbCommand(queryCutting, dbConn);
command_cutting.Parameters.AddWithValue("adddate", "123");
command_cutting.ExecuteNonQuery();
dbConn.Close();
}
catch
{
MessageBox.Show("Error", "SCADA system", MessageBoxButtons.OK);
}
but it return an error say that
The Microsoft Jet database engine could not find the object
'cuttings'.
Make sure the object exists and that you spell its name and the path name correctly.
The database is called cuttingstatus.dbf, and it consist of only a single column Status.
Thanks for the help =)
What is the name of the table in the cuttingstatus.dbf?
The statement should be something like:
INSERT INTO TABLE_NAME
VALUES(adddate)
as the value of the variable queryCutting.
When making an OleDbConnection to use Database files, you want your connection source to point to the logical PATH WHERE the table is... not the actual table.
Connection dbConn = new OleDbConnection(#"Data ource=C:\SomePath\WhereAreAllTables;Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties=dBase IV;");
Then, your insert query does not reference the .dbf extension... it is implied by the connection. Also, even though it may be a single column, it would be better to explicitly show the column and values such as :
string queryCutting = "INSERT INTO cuttingstatus ( YourColumnName ) VALUES ( #adddate )";
Next... Is it really a DBase IV system? FoxPro table? Clipper? I would ensure proper provider. If the data is actually from Foxpro origin, I would go to Microsoft and download the Visual Foxpro OleDb provider.
One final thought... is that the error is referring to a truncated table name of up to 8 characters "cuttings" which implies old DOS 8.3 file naming convensions. Don't know if that is what you are also running into for your problem.
I want to write a code that transfers data from on server to my SQL Server. Before I put the data in, I want to delete the current data. Then put the data from one to the other. How do I do that. This is snippets from the code I have so far.
string SQL = ConfigurationManager.ConnectionStrings["SQLServer"].ToString();
string OLD = ConfigurationManager.ConnectionStrings["Server"].ToString();
SqlConnection SQLconn = new SqlConnection(SQL);
string SQLstatement = "DELETE * FROM Data";
SqlCommand SQLcomm = new SqlCommand(SQLstatement, SQLconn);
SQLconn.Open();
OdbcConnection conn = new OdbcConnection(OLD);
string statement = "SELECT * FROM BILL.TRANSACTIONS ";
statement += "WHERE (TRANSACTION='NEW') ";
OdbcCommand comm = new OdbcCommand(statement, conn);
comm.CommandTimeout = 0;
conn.Open();
SqlDataReader myDataReader = SQLcomm.ExecuteReader();
while (myDataReader.Read())
{
//...
}
SQLconn.Close();
SQLconn.Dispose();
Depending on which version of SQL Server you are using, the standard solution here is to use either DTS (2000 and before) or SSIS (2005 and on). You can turn it into an executable if you need to, schedule it straight from SQL Server, or run it manually. Both tools are fairly robust (although SSIS much more so) with methods to clear existing data, rollback in case of errors, transform data if necessary, write out exceptions, etc.
If at all possible I'd try and do it all in SQL Server. You can create a linked server to your other database server. Then simply use T-SQL to copy the data across - it would look something like...
INSERT INTO new_server_table (field1, field2)
SELECT x, y
FROM mylinkedserver.myolddatabase.myoldtable
If you need to do this on a regular basis or clear out the data first you can do this as part of a scheduled task using the SQL Agent.
If you only need to import the data once, and you have a lot of data, why not use the "BULK INSERT" command? Link
T-SQl allows you to insert data from a select query. It would look something like this:
insert into Foo
select * from Bar;
As long as the field types align this will work - otherwise you will have to massage the data from Bar to fit the fields from Foo.
When you need to do this once, take a look at the database publishing wizard (just google) and generate a script which does everything.