C# SQL 在左连接中选择右表只返回唯一值,而不是每个值的一个实例

Posted

技术标签:

【中文标题】C# SQL 在左连接中选择右表只返回唯一值,而不是每个值的一个实例【英文标题】:C# SQL Select Right Table in a Left Join to only return UNIQUE values, not one instance of each 【发布时间】:2013-03-04 10:38:31 【问题描述】:

使用以下内容:

string strSelectSql = "SELECT Table1.ID, Table1.Status,  
    Table1.CustomerName,Table1.Date, Table1.LocationID, 
    Table2.LocationID As [LocationID 2] FROM Table1 LEFT JOIN 
    Table2 ON Table1.ID = Table2.ID 
    WHERE (Date Is Null AND ID= @SearchForString AND 
    Status != 'Archived') OR 
    ((Date Between @FromDate AND @ToDate) 
     AND ID= @SearchForString AND Status != 'Archived')";

        SqlConnection SqlConn = new SqlConnection(cstrDatabaseConnection);
        SqlDataAdapter SqlAdpt = new SqlDataAdapter();
        SqlCommand SqlCom = new SqlCommand(strSelectSql,SqlConn);
        SqlCom.Parameters.AddWithValue("@SearchForString",strSearchString);
        SqlCom.Parameters.AddWithValue("@FromDate",strFromDate);
        SqlCom.Parameters.AddWithValue("@ToDate",strToDate );

        SqlAdpt.SelectCommand = SqlCom;
        try
        
            DataSet TempDS = new DataSet();
            SqlConn.Open();
            SqlAdpt.Fill(TempDS);
            SqlConn.Close();
            SqlConn.Dispose();
            if (Convert.ToInt32(TempDS.Tables[0].Rows.Count) > 0)
            
                dgvQueryResult.DataSource = TempDS.Tables[0];
                dgvQueryResult.Refresh();
                dgvQueryResult.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
                TempDS.Dispose();
            

        
        catch (SqlException sqlE)
        
            MessageBox.Show(sqlE.Message);
            SqlConn.Close();
            SqlConn.Dispose();
        
        catch (Exception UnknownE)
        
            MessageBox.Show(string.Format("Unknown Exception: 0",UnknownE.Message);
            SqlConn.Close();
            SqlConn.Dispose();
        
        finally
        
            if (SqlConn != null) SqlConn.Dispose();
        

现在这一切都很好,除非 Table2 有多个 LocationID 值

Table2
+----+------------+
| ID | LocationID |
+----+------------+
| 1  |     1      |
| 2  |     2      |
| 3  |     3      |
| 4  |     4      |
| 5  |     5      |
| 6  |     6      |
| 6  |     7      |
| 6  |     7      |
| 7  |     8      |
| 7  |     9      |
+----+------------+

我想忽略:

Table2
+----+------------+
| ID | LocationID |
+----+------------+
| 6  |     7      |
| 6  |     7      |
+----+------------+

然后得到这个:

Table2
+----+------------+
| ID | LocationID |
+----+------------+
| 1  |     1      |
| 2  |     2      |
| 3  |     3      |
| 4  |     4      |
| 5  |     5      |
| 6  |     6      |
| 7  |     8      |
| 7  |     9      |
+----+------------+

但我确实想要:

Table2
+----+------------+
| ID | LocationID |
+----+------------+
| 6  |     6      |
+----+------------+

因为 LocationID 没有重复。

另外,我确实想要:

Table2
+----+------------+
| ID | LocationID |
+----+------------+
| 7  |     8      |
| 7  |     9      |
+----+------------+

再次因为 LocationID 不重复。

如果我必须这样做或者效率更高,我也愿意在之前从 TempDS 中删除这些行:

        dgvQueryResult.DataSource = TempDS.Tables[0];

如果需要或者最有效地从 dgvQueryResult 中删除条目

【问题讨论】:

首先执行 CTE 以获取 count > 1 的项目,然后添加到 where 子句以排除这些项目。我会给你 SQL 但我必须去开会。 如果您不熟悉如何创建公用表表达式(CTE),可以查看此 MSDN 站点CTE SQL Server @Hogan 我确实尝试过,但不确定语法,因为我在 strSelectSql 的开头添加了任何形式的 WITH 我得到了 SqlException。我以前从未使用过 CTE,也从未使用过拥有 Count(*)= 1 函数。并且找不到很多关于该主题的优秀文档,尤其是在 C# 中使用它时。 @user2140261 我经常在with 前面加上一个分号,因为SQL Server 喜欢抱怨它:;with @user2140261 - Paul 的回答很好,但这里有一个简单的例子 >> WITH ctename as ( SELECT * FROM table ) SELECT * FROM ctename 【参考方案1】:

而不是

LEFT JOIN Table2

尝试:

LEFT JOIN (Select id, locationId from table2 group by id, locationId having count(*) = 1) as table2

【讨论】:

这完全符合我的预期,这实际上与我脑海中最初尝试的几乎相同,不知道为什么我的不起作用,但效果很好。这与其他用户所说的尝试相比如何,CTE 路线对我来说似乎几乎是一样的。 我相信这是一个偏好问题。使用 CTE 应该优化到完全相同的计划。当子查询变得更复杂时,我个人发现 CTE 更具可读性,但在更琐碎的情况下使用子查询。

以上是关于C# SQL 在左连接中选择右表只返回唯一值,而不是每个值的一个实例的主要内容,如果未能解决你的问题,请参考以下文章

左连接

使用唯一随机值更新sql表中的所有行,而不使用c#中的主键或唯一键

SQL:左连接,右连接是啥概念啊

SQL JOIN 数据库表关联关系

连接 MySQL 表:在左表的一行中显示右表的所有结果

SQL——左连接(Left join)右连接(Right join)内连接(Inner join)