Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ionic-framework/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为任何给定的SQL Server表选择除第一列以外的所有列_C#_Sql Server_Sqlbulkcopy - Fatal编程技术网

C# 为任何给定的SQL Server表选择除第一列以外的所有列

C# 为任何给定的SQL Server表选择除第一列以外的所有列,c#,sql-server,sqlbulkcopy,C#,Sql Server,Sqlbulkcopy,我用C语言编写了这段代码,但我需要它选择表的第一列(identity列)以外的所有列,这样当我将数据插入到不同数据库中的相同表中时,目标数据库会分配自己的identity列值: SqlCommand commandSourceData = new SqlCommand($"SELECT * FROM dbo.{tableName};", sourceConnection); SqlDataReader reader = commandSourceData.ExecuteReader(); 有什

我用C语言编写了这段代码,但我需要它选择表的第一列(identity列)以外的所有列,这样当我将数据插入到不同数据库中的相同表中时,目标数据库会分配自己的identity列值:

SqlCommand commandSourceData = new SqlCommand($"SELECT * FROM dbo.{tableName};", sourceConnection);
SqlDataReader reader = commandSourceData.ExecuteReader();

有什么方法可以做到这一点吗?

如果您想要为数据库中的每一列提供通用解决方案,可以使用这种代码

public string GetColumnsWithoutIdentity(string tableName, SqlConnection con)
{
    SqlDataAdapter da = new SqlDataAdapter($"SELECT * FROM dbo.{tableName} where 1=0", con);
    DataTable dt = new DataTable();
    da.FillSchema(dt, SchemaType.Source);
    var cols = dt.Columns.Cast<DataColumn>().Where(x => !x.AutoIncrement).Select(x => x.ColumnName);
    return string.Join(",", cols);
}
现在,您可以使用返回的字符串构建一个Sql语句,而不必使用autoincrement列。 请注意,此代码易受Sql注入攻击。您应该绝对确保用于生成第一个查询的tableName参数不是由用户直接键入的。让它从预定义表的白名单只读列表中进行选择,这也不是100%安全的


另一个缺点是需要对数据库进行两次访问。一次用于获取包含有关AutoIncrement列的信息的模式,另一次用于填充datatable

如果希望数据库中的每一列都有一个通用的解决方案,可以使用这种代码

public string GetColumnsWithoutIdentity(string tableName, SqlConnection con)
{
    SqlDataAdapter da = new SqlDataAdapter($"SELECT * FROM dbo.{tableName} where 1=0", con);
    DataTable dt = new DataTable();
    da.FillSchema(dt, SchemaType.Source);
    var cols = dt.Columns.Cast<DataColumn>().Where(x => !x.AutoIncrement).Select(x => x.ColumnName);
    return string.Join(",", cols);
}
现在,您可以使用返回的字符串构建一个Sql语句,而不必使用autoincrement列。 请注意,此代码易受Sql注入攻击。您应该绝对确保用于生成第一个查询的tableName参数不是由用户直接键入的。让它从预定义表的白名单只读列表中进行选择,这也不是100%安全的


另一个缺点是需要对数据库进行两次访问。一次用于获取包含有关AutoIncrement列的信息的模式,另一次用于填充datatable

是的,在查询中,您可以指定所需列的名称,而不是使用*通配符,如select col1、col2、col3……但它需要是动态的,以便我可以传递任何表名,它将为该表执行此操作。当您的标识列不是第一列时会发生什么?您确实应该显式地管理数据。但是,如果您在这样一个通用的catch-all-insert上处于死机状态,那么您必须使用动态sql,只选择那些非标识列和非计算列的列。这真的非常危险,因为不仅您的标识列不能像Sean所说的那样排在第一位,而且您还可以有没有标识列的表、加密列、,您还可以使用其他列直接填充审核列、newsequentialid、时态表、行版本、计算列等。您能解释一下为什么需要更改这些标识值吗?您可能会破坏这些表之间存在的所有关系。是的,在查询中,您可以指定所需列的名称,而不是使用*通配符,如select col1、col2、,col3…它需要是动态的,这样我就可以给它传递任何表名,它将为该表执行此操作。当您的标识列不是第一个时会发生什么?您确实应该显式地管理数据。但是,如果您在这样一个通用的catch-all-insert上处于死机状态,那么您必须使用动态sql,只选择那些非标识列和非计算列的列。这真的非常危险,因为不仅您的标识列不能像Sean所说的那样排在第一位,而且您还可以有没有标识列的表、加密列、,您还可以使用其他列直接填充审核列、newsequentialid、时态表、行版本、计算列等。您能解释一下为什么需要更改这些标识值吗?可能您会破坏这些表之间存在的所有关系。如果您将表名包装在QUOTENAME中,这将使其不受sql注入的影响,但白名单在这里仍然是非常合适的。有没有一种方法也可以排除这样的计算列?所谓计算列,是指表达式属性不为null或空的列吗?我想是的。我不知道这在网络方面是如何运作的。还有一些其他的潜在问题,比如加密列等,这些都是安全工作所必需的……但是OP似乎并不太担心这是一个非常灵活的解决方案。好吧,只是将标识值更改为其他值的想法有点可疑。我们真的应该试着去理解他需求背后的真正原因是什么。如果你用QUOTENAME包装这个表名,这将使它不受sql注入的影响,但是白名单在这里仍然是一个非常合适的东西。有没有一种方法也可以排除这样的计算列?所谓计算列,是指表达式属性不为null或空的列吗?我想是的。我不知道这在网络方面是如何运作的。还有一些其他的潜在问题,比如加密列等,这些都是安全工作所必需的……但是OP似乎并不太担心这是一个非常灵活的解决方案。好吧,只是想把身份值改成其他东西 有点可疑。我们应该真正了解他提出要求的真正原因。