sql server返回插入记录的ID(多条记录)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql server返回插入记录的ID(多条记录)相关的知识,希望对你有一定的参考价值。

需要先插入多条数据到表1,然后再将表1中插入的多条记录的ID插入到表2,这种情况要怎么取到多个ID?表1的ID是自动增长的那种
是在SQL Server 2000下
我想要的效果是在存储过程中执行一条insert select语句插入多条数据,然后在每插入一条数据后返回刚插入的这条ID,因为这时需要把ID再插到另一个表中,这种效果能实现吗?
不用触发器可以实现吗?因为我是想只有批量插入时才调用这个存储过程

你的这个需求好象直接再把记录插入到表2就可以,但我估计你不是这个意思。

比较笨的办法,可以定义一个数组用于记录表1的ID值,或者用个临时表来记录表一新增加的记录ID列表。

insert后,query的指针应该还是停留在最新增加的记录上的,因此是可以取得到ID值的。

代码如下,假设表一只有二个字段,一个是ID(自动增量),一个是字段A(字符型),

var
sql:string;
id1:integer;
begin
sql:='insert into 表一 ('''+字段A+''') values ('''+ '内容'+''')';
query1.close;
query1.sql.clear;
query1.sql.add(sql);
query1.Execsql;
id1:=query1.fieldbyname('id').asinteger;
//接下来可以把ID1的值写入临时表或者数组了,如果是需要不同的机器取得ID值,可以用临时表,不过速度会慢些,如果只是本机取得,就用数组好了。
//后面的代码略
...
...

end;

上述代码我没有条件试,应该可以,另外还可以用append的方法追加记录,这样就一定可以用上面的方法取到ID值了。

var
id1:integer;
begin
query1.append;
query1.fieldbyname('字段A').asstring = '内容';
query1.post;
id1:=query1.fieldbyname('ID').asinteger;
//这种方法一定可以取得到ID值。
//后面你自行对取得的ID进行存储就行了,临时表或者数组都可以。代码略
end;
参考技术A 其实触发器是可以实现的,只要在触发器里面加入一个判断插入数据的行数就可以了:
IF object_id('TR_Insert_tableA') is not null
drop trigger TR_Insert_tableA
go
create trigger TR_Insert_tableA
on tableA for insert
as
begin
IF (Select count(*) from inserted)>1
begin
insert into tableB(id) select id from inserted
end
end
如果一定要用存储过程也是有很多办法的,具体可以Hi我本回答被提问者采纳
参考技术B 插入数据如果带有时间字段,可以用查询语句找出来
insert into 表2
select id from 表1 where 时间条件

否则的话,在表1建立一个触发器,每插一次就插入表2

create trigger myt
as
begin
@id integer
select id into @at from inserted
if @id>0 then
insert into 表2
select id from inserted
end if
end

使用 for 循环将多条记录插入 SQL Server 数据库

【中文标题】使用 for 循环将多条记录插入 SQL Server 数据库【英文标题】:Inserting Multiple Records into SQL Server database using for loop 【发布时间】:2016-08-17 09:20:36 【问题描述】:

我正在使用 C# 编写一个 Windows 窗体项目。我正在尝试将多个记录从数组中插入 SQL Server 数据库。

进入第一行后出现异常

@UserID 已被声明。变量名称在查询批处理或存储过程中必须是唯一的。

数据库中的主键没有问题,因为UserID 不是主键。

这就是我想要做的。

public static void featuresentry()

    SqlConnection connection = new SqlConnection(HandVeinPattern.Properties.Settings.Default.HandVeinPatternConnectionString);

    SqlCommand command = new SqlCommand();
    connection.Open();

    try
    
        command = connection.CreateCommand();

        for (int i = 0; i < Details.modelKeyPoints.Size; i++)
        
            command.CommandText = "INSERT INTO FEATURES(UserID, Angle, ClassID, Octave, PointX, PointY, Response, Size) VALUES(@UserID, @Angle, @ClassID, @Octave, @PointX, @PointY, @Response, @Size)";

            command.Parameters.AddWithValue("@UserID", Details.ID);
            command.Parameters.AddWithValue("@Angle", Convert.ToDouble(Details.modelKeyPoints[i].Angle));
            command.Parameters.AddWithValue("@ClassID", Convert.ToDouble(Details.modelKeyPoints[i].ClassId));
            command.Parameters.AddWithValue("@Octave", Convert.ToDouble(Details.modelKeyPoints[i].Octave));
            command.Parameters.AddWithValue("@PointX", Convert.ToDouble(Details.modelKeyPoints[i].Point.X));
            command.Parameters.AddWithValue("@PointY", Convert.ToDouble(Details.modelKeyPoints[i].Point.Y));
            command.Parameters.AddWithValue("@Response", Convert.ToDouble(Details.modelKeyPoints[i].Response));
            command.Parameters.AddWithValue("@Size", Convert.ToDouble(Details.modelKeyPoints[i].Size));

            command.ExecuteNonQuery();
        
    
    catch (Exception)
    
        throw;
    
    finally
    
        if (connection.State == ConnectionState.Open)
        
            connection.Close();
        
    

【问题讨论】:

我认为如果你将command = connection.CreateCommand(); 放在你的 for 循环中,它会起作用。问题是你只循环命令参数,所以它试图向你现有的命令添加更多参数,但它们已经在那里了。所以你需要在每个循环中创建一个新命令。 @UnicornoMarley,是的,这就是问题所在。不错的收获,将其发布为答案。 另一种选择是将所有命令和参数创建移到循环之外,只更新值并在循环内执行。这样您就不会不断地创建新的对象实例。 @Unicorno 。谢谢您的帮助。它奏效了。 【参考方案1】:

您需要在循环外添加 Command 参数或在循环内声明 Command。

在第一种情况下,您需要像这样更新每个参数的值:

oleDbCommand1.Parameters["@UserID"].Value = Details.ID;

并在设置新值后执行命令。

【讨论】:

【参考方案2】:

如果你将command = connection.CreateCommand(); 放在你的 for 循环中,它将起作用。问题是你只循环命令参数,所以它试图向你现有的命令添加更多参数,但它们已经在那里了。所以你需要在每个循环中创建一个新命令。

【讨论】:

【参考方案3】:

您应该正确这样做:

在循环外定义参数一次 在每次迭代的循环内定义参数的 使用using(...) ... 块删除try ... catch ... finallyusing 块将确保在不再需要时正确快速地处理您的课程) 如果您实际上没有处理异常,请停止使用try...catch - 只需重新抛出它们(没有意义)

试试这个代码:

public static void featuresentry()

    string connectionString = HandVeinPattern.Properties.Settings.Default.HandVeinPatternConnectionString;
    string insertQuery = "INSERT INTO FEATURES(UserID, Angle, ClassID, Octave, PointX, PointY, Response, Size) VALUES(@UserID, @Angle, @ClassID, @Octave, @PointX, @PointY, @Response, @Size)";

    using (SqlConnection connection = new SqlConnection(connectionString))
    using (SqlCommand command = new SqlCommand(insertQuery, connection))
    
        // define your parameters ONCE outside the loop, and use EXPLICIT typing
        command.Parameters.Add("@UserID", SqlDbType.Int);
        command.Parameters.Add("@Angle", SqlDbType.Double);
        command.Parameters.Add("@ClassID", SqlDbType.Double);
        command.Parameters.Add("@Octave", SqlDbType.Double);
        command.Parameters.Add("@PointX", SqlDbType.Double);
        command.Parameters.Add("@PointY", SqlDbType.Double);
        command.Parameters.Add("@Response", SqlDbType.Double);
        command.Parameters.Add("@Size", SqlDbType.Double);

        connection.Open();

        for (int i = 0; i < Details.modelKeyPoints.Size; i++)
        
            // now just SET the values
            command.Parameters["@UserID"].Value = Details.ID;
            command.Parameters["@Angle"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Angle);
            command.Parameters["@ClassID"].Value = Convert.ToDouble(Details.modelKeyPoints[i].ClassId);
            command.Parameters["@Octave"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Octave);
            command.Parameters["@PointX"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Point.X);
            command.Parameters["@PointY"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Point.Y);
            command.Parameters["@Response"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Response);
            command.Parameters["@Size"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Size);

            command.ExecuteNonQuery();
        
    

【讨论】:

或者更好的是,使用表值参数并只执行一条语句... @ZoharPeled 很遗憾你没有按照这些思路提供答案!【参考方案4】:

为了获得最大的性能,您可以考虑使用BulkInsert。这可以确保您的插入尽可能快地完成,因为任何发出的查询都有一些开销(大查询通常比许多小查询执行得更快)。它应该如下所示:

1) 从here定义AsDataTable扩展方法:

   public static DataTable AsDataTable<T>(this IEnumerable<T> data)
   
       PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
       var table = new DataTable();
       foreach (PropertyDescriptor prop in properties)
           table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
       foreach (T item in data)
       
           DataRow row = table.NewRow();
           foreach (PropertyDescriptor prop in properties)
               row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
           table.Rows.Add(row);
       
       return table;
   

2) 像这样执行实际的 BulkInsert(未测试):

using (SqlConnection connection = new SqlConnection(connectionString))

     connection.Open();
     SqlTransaction transaction = connection.BeginTransaction();

     using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
     
        bulkCopy.BatchSize = 100;
        bulkCopy.DestinationTableName = "dbo.FEATURES";
        try
        
            // define mappings for columns, as property names / generated data table column names
            // is different from destination table column name
            bulkCopy.ColumnMappings.Add("ID","UserID");
            bulkCopy.ColumnMappings.Add("Angle","Angle");
            // the other mappings come here

            bulkCopy.WriteToServer(Details.modelKeyPoints.AsDataTable());
        
        catch (Exception)
        
            transaction.Rollback();
            connection.Close();
        
      

      transaction.Commit();

当然,如果使用convention over configuration(对象属性名称将与目标表列名称完全匹配),则不需要映射。

【讨论】:

【参考方案5】:

您可以通过将数据作为 xml 字符串发送并在 sql 中的存储过程中转换为表来完成此操作。例如: 假设我要发送多行以在 sql 表中添加/更新,那么步骤如下:

    使用以下方法将您的类或类列表转换为 xml 字符串:

    public static string SerializeObjectToXmlString(object value)
    
              
              var emptyNamepsaces = new XmlSerializerNamespaces(new[]  
                                        XmlQualifiedName.Empty );
    
        var serializer = new XmlSerializer(value.GetType());
        var settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.OmitXmlDeclaration = true;
    
        using (var stream = new StringWriter())
        using (var writer = XmlWriter.Create(stream, settings))
        
            serializer.Serialize(writer, value, emptyNamepsaces);
            return stream.ToString();
        
    
    

    现在在向数据库发送数据时将您的类对象转换为 xml 字符串(这里我在我的代码中使用实体框架,你也可以不使用它):

    bool AddUpdateData(List<MyClass> data)
    
        bool returnResult = false;
        string datatXml = Helper.SerializeObjectToXmlString(data);
        var sqlparam = new List<SqlParameter>()
                     
       new SqlParameter()  ParameterName = "dataXml", Value = datatXml
    
                     ;
        var result = this.myEntity.Repository<SQL_StoredProc_ComplexType>().ExecuteStoredProc("SQL_StoredProc", sqlparam);
        if (result != null && result.Count() > 0)
        
            returnResult = result[0].Status == 1 ? true : false;
        
        return returnResult;
    
    

    现在你的 SQL 代码:

3.1 声明一个表变量:

DECLARE @tableVariableName TABLE
(
    ID INT, Name VARCHAR(20)
)

3.2 将您的 xml 字符串插入到表变量中

INSERT INTO @tableVariableName
SELECT 
    Finaldata.R.value ('(ID/text())[1]', 'INT') AS ID, 
    Finaldata.R.value ('(Name/text())[1]', 'VARCHAR(20)') AS Name
FROM @MyInputXmlString.nodes ('//ArrayMyClass/MyClass') AS Finaldata (R)

3.3 最后将这个表值插入到你的sql表中

INSERT INTO MyTable (ID, Name)                  
SELECT ID, Name          
FROM @tableVariableName

这将节省您使用 for 循环一次又一次地访问数据库的工作。

希望对你有帮助

【讨论】:

以上是关于sql server返回插入记录的ID(多条记录)的主要内容,如果未能解决你的问题,请参考以下文章

从 SQL Server 中具有公共 ID 的多条记录中选择数据

在 SQL Server 中,您可以根据计算插入多条记录吗?

使用 for 循环将多条记录插入 SQL Server 数据库

sql 多条记录插入

如何使用 SQL Server 在一行中检索特定 id 的多条记录

将多条记录插入 SQL 表时,它不遵循顺序