【问题标题】:INSERT INTO table with foreign key contraints带有外键约束的 INSERT INTO 表
【发布时间】:2015-07-23 20:47:21
【问题描述】:

我已经阅读了一些关于此的内容并提出了以下代码。我正在使用 Access 数据库,并通过 Visual Studio 在 C# 中进行编码。

我在此遇到语法错误。我试图在 Access 中创建一个查询来测试它,但很难在其中创建它。

谁能帮我弄清楚为什么这不起作用?

using(OleDbConnection conn1 = new OleDbConnection(global::InsulationProjectTracker.Properties.Settings.Default.InsulationDB))
{
    using(OleDbCommand command1 = conn1.CreateCommand())
    {
        conn.Open();

        command.CommandText = "INSERT INTO Jobsites (CustomerID, JobsiteName) VALUES ((SELECT Customers.CustomerID FROM Customers WHERE Customers.CustomerName = @cname1 AND Customers.BranchNumber = @bNumber1), @jName1)";
        command.Parameters.Add(new OleDbParameter("@cName1", cboCustomerName.Text));
        command.Parameters.Add(new OleDbParameter("@bNumber1", cboBranch.Text));
        command.Parameters.Add(new OleDbParameter("@jName1", txtJobsiteName.Text));

        command.ExecuteNonQuery();

        conn.Close();
        command.Parameters.Clear();

    }
}

表格设置

分支机构

PK 分支编号
分行名称

客户

PK 客户 ID
客户名称
FK 分行号

工作地点

PK JobsiteID
工作地点名称
FK 客户 ID

编辑***

下面的命令不会产生错误,但也不会将数据插入数据库

command.CommandText = "INSERT INTO Jobsites (CustomerID, JobsiteName) SELECT @jName1, c.CustomerID FROM Customers c WHERE c.CustomerName = @cname1 AND c.BranchNumber = @bNumber1";

【问题讨论】:

  • 请清理你的代码缩进。
  • 您能否包括您的语法错误以及 Jobsites、Customers 的架构?谢谢
  • 参数名称区分大小写。
  • I am getting a syntax error... 尝试在INSERT INTO Jobsites 之后和(j.Custome.....) 之前删除j
  • @SamAxe 不,在 OleDB 中,它们不是。实际上,它们都被替换为 ?在幕后。 OleDB 在分配参数值时使用索引优先级。所以用户可以在每个参数行中使用new OleDbParameter("?",

标签: c# database ms-access foreign-key-relationship sql-insert


【解决方案1】:

Access SQL 不接受目标表的别名。

例如,这些语句中的任何一个都会触发 “INSERT INTO 语句中的语法错误。” ...

INSERT INTO Jobsites j (j.CustomerID, j.JobsiteName) VALUES (1, 'foo');
INSERT INTO Jobsites AS j (j.CustomerID, j.JobsiteName) VALUES (1, 'foo');

没有别名,这个执行没有错误...

INSERT INTO Jobsites (CustomerID, JobsiteName) VALUES (1, 'foo');

为了获得 Access 将接受的查询,我认为您可能需要切换到 INSERT ... SELECT 而不是 INSERT ... VALUES ...

command.CommandText = "INSERT INTO Jobsites (CustomerID, JobsiteName) SELECT c.CustomerID, @jName1 FROM Customers AS C WHERE c.CustomerName = @cname1 AND c.BranchNumber = @bNumber1";

所以基本上是 @ConradFrix 之前建议的,但没有 Jobsites 表的别名。

【讨论】:

  • 我没有检查 Values (SELECT Col From Table, ?) 是否有效?
  • 让我试试这个...但是,我在这段代码的前面使用了 SQL,使用 Alias 没有错误。
  • 别名可用于其他类型的 Access SQL 语句,但不能用于 INSERT 中的目标表。如果您能找到方法,请向我们展示一个经过测试的工作示例。
  • @ConradFrix 我不知道。我以前从未使用过它,但我是从我在搜索中找到的一个问题中读到的。
  • 不用担心混乱。我不确定Values (SELECT Col From Table, ?) 会不会有问题。一些数据库支持它,尽管在我看来它很危险。我取消了我的答案,因为它讨论了如何处理返回的多行,否则我就让它成为现实
【解决方案2】:

嗯,参数名称需要 @ 字符,就像在您的查询中一样

"INSERT INTO Jobsites j (j.CustomerID, j.JobsiteName) VALUES ((SELECT c.CustomerID FROM Customers c WHERE c.CustomerName = @cname1 AND c.BranchNumber = @bNumber1), @jName1)"

所以你需要改变

command.Parameters.Add(new OleDbParameter("cName1", cboCustomerName.Text));
                                    command.Parameters.Add(new OleDbParameter("bNumber1", cboBranch.Text));
                                    command.Parameters.Add(new OleDbParameter("jName1", txtJobsiteName.Text));

command.Parameters.Add(new OleDbParameter("@cName1", cboCustomerName.Text));
                                    command.Parameters.Add(new OleDbParameter("@bNumber1", cboBranch.Text));
                                    command.Parameters.Add(new OleDbParameter("@jName1", txtJobsiteName.Text));

【讨论】:

  • OleDB 实际上并不使用参数名称,但它们的顺序必须正确。你可以只使用“?”所有这些参数。
  • 我正在检查 msdn 文档,他们在命令中使用 @ 字符。Parameters.Add string queryString = "SELECT * FROM Table1 WHERE Field1 LIKE ?"; OleDbCommand command = new OleDbCommand(queryString, connection); command.Parameters.Add("@p1", OleDbType.Char, 3).Value = "a"; OleDbDataReader reader = command.ExecuteReader(); link
  • 我了解 OleDb 不使用 @ 符号并且它是按顺序排列的,我只是出于习惯这样做。我的意思是把@ 放在参数标识之前,只是忘记了。无论如何,它并没有解决错误。我也在其他数据查询上使用这种格式,没有问题。所以我不认为使用 @ 符号是问题。
【解决方案3】:

KM 在评论中建议的答案是正确的。不可能(也没有理由)为INSERT INTO 查询的目标设置别名。相反,它应该是

command.CommandText = "INSERT INTO Jobsites (CustomerID, JobsiteName) VALUES ((SELECT c.CustomerID FROM Customers c WHERE c.CustomerName = @cname1 AND c.BranchNumber = @bNumber1), @jName1)";

【讨论】:

  • 我知道了。我认为他的意思是删除所有别名,而不仅仅是实际的插入表。有道理....谢谢
【解决方案4】:

感谢大家帮助解决这个问题。我根据您提供的输入更正了几件事。

工作代码如下:

using(OleDbCommand command1 = conn1.CreateCommand())
{
    conn.Open();

    command.CommandText = "INSERT INTO Jobsites (JobsiteName, CustomerID) SELECT @jName1, c.CustomerID FROM Customers c WHERE c.CustomerName = @cname1 AND c.BranchNumber = @bNumber1";
    command.Parameters.Add(new OleDbParameter("@jName1", txtJobsiteName.Text));
    command.Parameters.Add(new OleDbParameter("@cName1", cboCustomerName.Text));
    command.Parameters.Add(new OleDbParameter("@bNumber1", cboBranch.Text));

    command.ExecuteNonQuery();

    conn.Close();
    command.Parameters.Clear();


}

主要问题是我需要使用 INSERT SELECT 与 INSERT VALUES。一旦我改变了这个,我所要做的就是重新定位参数并确保它们是有序的并且代码运行完美。

我还删除了 INSERT INTO 表上的别名名称,如此处所述。

非常感谢你们的帮助!

-约瑟夫

【讨论】:

    【解决方案5】:

    这部分VALUES ((SELECT c.CustomerID FROM Customers c WHERE c.Customer.. 是可疑的,因为使用 SELECT 作为单个值来获取 customerID 可能会很棘手,因为可能会有多个 CustomerID 符合您的条件。

    解决这个问题的一种方法是将查询重写为

    command.CommandText =@"
        INSERT INTO Jobsites j 
          (j.CustomerID, j.JobsiteName) 
        SELECT c.CustomerID ,  @jName1 as Jobsitename 
        FROM Customers c 
        WHERE c.CustomerName = @cname1 AND c.BranchNumber = @bNumber1";
    

    这使用一个参数作为 Jobsitename 的常量,但这确实意味着如果返回多条记录,您将插入多行。

    您可以通过添加 TOP 1 来防止返回多个记录的可能性

    您还可以在数据库中查询客户 ID 并在更新之前检查行数,如果您确实获得了多条记录,则会引发异常。这将需要两次访问数据库,但可能更正确(当然,除非您对客户名称有唯一索引)

    【讨论】:

      猜你喜欢
      • 2023-03-27
      • 2014-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多