Select 项在每个组中按列不同
Select item that is different in each of group by a column
我有这个样品table
+--------+-------------+
| 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。
使用NOT EXISTS
SELECT *
FROM yourtable t
WHERE NOT EXISTS
(
SELECT *
FROM yourtable x
WHERE x.Description = t.Description
AND x.DBName <> t.DBName
)
有趣的问题。这里有几个解决方案。围绕这些技术进行了讨论 here,并提出了一些处理此类情况的其他途径的建议。
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
子句排除所有已存在的组合。
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
子句来删除现有组合。
理想情况下,您应该有一个数据主列表。如果你不这样做,你应该从数据中导出它,然后像下面这样对它们进行检查:
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
你应该多扔一点样本数据。
试试这个,
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
我有这个样品table
+--------+-------------+
| 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。
使用NOT EXISTS
SELECT *
FROM yourtable t
WHERE NOT EXISTS
(
SELECT *
FROM yourtable x
WHERE x.Description = t.Description
AND x.DBName <> t.DBName
)
有趣的问题。这里有几个解决方案。围绕这些技术进行了讨论 here,并提出了一些处理此类情况的其他途径的建议。
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
子句排除所有已存在的组合。
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
子句来删除现有组合。
理想情况下,您应该有一个数据主列表。如果你不这样做,你应该从数据中导出它,然后像下面这样对它们进行检查:
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
你应该多扔一点样本数据。
试试这个,
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