按列选择每个组中不同的项目

Posted

技术标签:

【中文标题】按列选择每个组中不同的项目【英文标题】:Select item that is different in each of group by a column 【发布时间】:2018-08-23 08:22:36 【问题描述】:

我有这个示例表

+--------+-------------+
| DBName | Description |
+--------+-------------+
| A      | Car         |
| A      | Boat        |
| B      | Car         |
| B      | Plane       |
| C      | Car         |
| C      | Boat        |
| C      | Plane       |
+--------+-------------+

我只想获取每个 DBName 上不存在的描述,并显示没有描述的 DBName。

我想要的查询结果

+--------+-------------+
| DBName | Description |
+--------+-------------+
| A      | Plane       |
| B      | Boat        |
+--------+-------------+

请记住,它不仅仅是 DBName 上的 A、B、C。

【问题讨论】:

是否有包含所有可能描述的查找表? 您可以尝试对描述进行区分并将其假设为主数据 【参考方案1】:

有趣的问题。这里有几个解决方案。围绕这些技术 here 进行了讨论,并提出了一些其他处理此类情况的路线的建议。


SQL Fiddle Example

select DBName, Description
from (
    select DBName, Description
    from (select distinct DBName from demo) a
    cross join (select distinct Description from demo) b
) c
except
select DbName, Description from demo

此解决方案的工作原理是获取所有可能的组合(通过每列不同值的交叉连接),然后通过except 子句排除所有已经存在的组合。


SQL Fiddle Example

select [each].DBName, missing.Description
from (select distinct DBName from demo) [each]
cross join (select distinct Description from demo) [missing]
where not exists 
(
  select top 1 1
  from demo [exists]
  where [exists].DbName = [each].DBName
  and [exists].Description = [missing].Description
)

此解决方案与上述相同,只是我们使用where not exists 代替except cluase 来删除现有的组合。

【讨论】:

第二个查询(不存在的地方)返回不正确的 C 船,第一个查询对我有用 谢谢@AdinugrahaTawaqal。仅供参考:第二个查询应该有效;只有我在演示数据上犯了一个错误(填充了两次C, Car,而不是包括C, Boat)。现在正在调整 SQL Fiddle 链接... 没问题,我应该说谢谢。【参考方案2】:

理想情况下,您应该有一个主数据列表。如果你不这样做,你应该从数据中导出它,然后像下面这样对它们进行检查:

SQL Fiddle Example

select 
masterlistDbname.Dbname,
masterlistDesc.Description 
from
(
    select distinct Description from yourtable
) masterlistDesc
cross join
(
    select distinct Dbname from yourtable
) masterlistDbname
left join
yourtable t1 
on t1.Dbname = masterlistDbname.Dbname
and t1.Description = masterlistDesc.Description 
where t1.Dbname is NULL

【讨论】:

我试图解决的是我在多个数据库上拥有主数据,相同的结构不同的内容。我想让主数据描述统一或至少尝试指出数据库之间的差异。每个数据库都是它自己的公司,我在控股公司工作。【参考方案3】:

使用NOT EXISTS

SELECT *
FROM   yourtable t
WHERE  NOT EXISTS
       (
           SELECT *
           FROM   yourtable x
           WHERE  x.Description = t.Description 
           AND    x.DBName     <> t.DBName 
       ) 

【讨论】:

有一个小问题,它只会返回来自yourtable 的记录;所以不会完成选择那些不存在于该表中的记录的任务,因为它们不存在。【参考方案4】:

你应该多扔一些样本数据。

试试这个,

create table #test(DBName varchar(50),Descriptions varchar(50) )

insert into #test VALUES
('A','Car')        
,('A','Boat')       
,('B','Car')        
,('B','Plane')      
,('C','Car')        
,('C','Boat')       
,('C','Plane')      

;

WITH CTE
AS (
    SELECT *
        ,ROW_NUMBER() OVER (
            ORDER BY (
                    SELECT NULL
                    )
            ) rn
        ,ROW_NUMBER() OVER (
            PARTITION BY DBName ORDER BY (
                    SELECT NULL
                    )
            ) rn1
    FROM #test
    )
SELECT t.DBName
    ,t1.Descriptions
FROM cte t
CROSS APPLY (
    SELECT TOP 1 Descriptions
    FROM cte t1
    WHERE t1.rn > t.rn
        AND t.Descriptions <> t1.Descriptions
        AND t.dbname <> t1.dbname
    ORDER BY t1.rn
    ) t1
WHERE t.rn1 = 1



drop table #test

【讨论】:

以上是关于按列选择每个组中不同的项目的主要内容,如果未能解决你的问题,请参考以下文章

按列从表组中获取3行数据

按列和值比较两个 csv 文件并显示不同值的行号 [关闭]

表格:按列对齐文本

从不同的相关记录组中选择两列之一中包含重复值的所有行

如何对每个表进行分组计数并按列打印? [复制]

SQL:如何选择组中同一SINGLE行的两个字段?