【问题标题】:How to access Ambiguous Column in SQL Query with SELECT *如何使用 SELECT * 访问 SQL 查询中的歧义列
【发布时间】:2011-05-10 21:07:52
【问题描述】:

当我执行存储过程时

SELECT * FROM Users 
INNER JOIN BloodBankUser ON Users.UserID = BloodBankUser.UserID

结果很好。

但现在在 .net 端

dt.Rows[0]["Address"].ToString();

这给了我表的地址 BloodBankUser

dt.Rows[0]["Users.Address"].ToString();

当我调试这个语句时它执行错误

列“Users.Address”不 属于表。

如何获取 Users.Address 的值

【问题讨论】:

  • 永远不要使用 select * 特别是如果你有一个连接。这是浪费处理时间的不良做法。
  • 我已经知道删除 Select *.如果我想要 SELECT * 的解决方案怎么办
  • 我们为什么要给你一个解决方案,让你可以继续使用不好的做法?
  • :) 它不是实践的家伙它的要求。

标签: sql-server datatable sql


【解决方案1】:

虽然第一个答案是更改您的 SQL 查询以为每个字段指定一个不同的名称,但仍然可以检索与您的字段关联的表名。

在此示例中,我没有使用DataAdapter 填充DataTable,而是使用SqlDataReader

请注意,如果您因任何原因无法检索数据库架构,这可能会失败

SqlCommand 上调用ExecuteReader 时,有一个允许您指定CommandBehavior 的重载。在我们的例子中,我们想要的行为是CommandBehavior.KeyInfo

var reader = command.ExecuteReader(CommandBehavior.KeyInfo);

现在,在阅读器上,您可以调用GetSchemaTable 方法。它返回一个包含查询结构的DataTable

var schema = reader.GetSchemaTable();

你可以read about that table on MSDN

我们现在的目标是将字段和表格与其在列列表中的序号位置相匹配。架构表中的三个字段与您的兴趣相关:

  • 列名
  • 基表名称
  • 列序号

然后您可以创建一个扩展方法来执行该读取:

public static T Field<T>(this SqlDataReader reader, DataTable schema, string table, string field)
{
    // Search for the ordinal that match the table and field name
    var row = schema.AsEnumerable().FirstOrDefault(r => r.Field<string>("BaseTableName") == table && r.Field<string>("ColumnName") == field);
    var ordinal = row.Field<int>("ColumnOrdinal");

    return (T)reader.GetValue(ordinal);
}

然后您可以调用该扩展方法

using (SqlConnection connection = new SqlConnection("your connection string"))
{
    connection.Open();

    using (SqlCommand command = new SqlCommand("SELECT * FROM Users INNER JOIN BloodBankUser ON Users.UserID = BloodBankUser.UserID;", connection))
    using (var reader = command.ExecuteReader(CommandBehavior.KeyInfo))
    {
        var schema = reader.GetSchemaTable();

        while (reader.Read())
        {
            Console.WriteLine(reader.Field<string>(schema, "Users", "Address"));
        }
    }
}

【讨论】:

  • -1 用于不良做法的不必要解决方法。如果序数位置发生变化怎么办?如果调用者没有查看定义怎么办? stoerd proc 旨在隐藏基表
  • 这就是为什么我像我一样介绍了答案,然后是粗体警告。关于序数位置,这正是这段代码所做的:找到它。此外,这就是 OP 的要求:阅读他在问题中的最后一条评论。
【解决方案2】:

重命名输出中的 FIELD(选择 FIELDNAME 作为 NEWNAME)

【讨论】:

  • 是的,如果他已经指定了要开始的列并在两个表中重命名了任何具有相同名称的列,那么这将不是问题。
  • 我已经知道删除 Select *.如果我想要 SELECT * 的解决方案怎么办
【解决方案3】:

您指定列名而不是使用SELECT * FROM 然后您将能够执行以下操作

Select User.Username,
       User.Address as 'UserAddress',
       BloodBankUser.Address as 'BloodbankAddress'

FROM Users 
INNER JOIN BloodBankUser ON Users.UserID = BloodBankUser.UserID 

【讨论】:

  • 我已经知道删除 Select * 的解决方案。如果我想要 SELECT * 的解决方案怎么办
【解决方案4】:

避免在SELECT 查询中使用*。只选择您需要的列并明确命名它们以避免歧义,

【讨论】:

  • 我已经知道删除 Select *.如果我想要 SELECT * 的解决方案怎么办
【解决方案5】:

SELECT *... 的 Insead 明确指定您想要的列,并为可能重复的列设置别名

SELECT Users.Address as UsersAddress

【讨论】:

    猜你喜欢
    • 2018-12-09
    • 1970-01-01
    • 2019-05-09
    • 2021-05-08
    • 2018-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多