SQL 服务器查询同一列的多个条件
SQL Server query for multiple conditions on the same column
这是我正在使用的模式和数据
CREATE TABLE tbl (
name varchar(20) not null,
groups int NOT NULL
);
insert into tbl values('a', 35);
insert into tbl values('a', 36);
insert into tbl values('b', 35);
insert into tbl values('c', 36);
insert into tbl values('d', 37);
| name | groups|
|------|-------|
| a | 35 |
| a | 36 |
| b | 35 |
| c | 36 |
| d | 37 |
现在我只需要组数大于或等于 35 的名称
但还有一个额外的问题是,当相应的 groups=36 也存在时,我只能包含 group=35 的行
| name | groups|
|------|-------|
| a | 35 |
| a | 36 |
第二个条件是它可以包括那些组数大于或等于 36 而组数不等于 35 的名称
| name | groups|
|------|-------|
| c | 36 |
| d | 37 |
唯一应该忽略的情况是记录只有 groups=35 而没有对应的 groups=36
| name | groups|
|------|-------|
| b | 35 |
我试过以下方法
select name from tbl
where groups>=35
group by name
having count(distinct(groups))>=2
or groups>=36;
这是我面临的错误Column 'tbl.groups' is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause.
因此,据我所知,您只想限制组 35 所在的位置。我想,让我们尝试隔离那些只有 groups=35 然后不存在的名称。这是您想要的正确输出吗?
此外,在 where 子句中使用复杂的 OR 通常会导致您的查询不可搜索。最好使用 UNION 或一些构建查询的方法,以便每个部分都可以使用索引(如果可以的话)。
if object_id('tempdb..#tbl') is not null drop table #tbl;
CREATE TABLE #tbl (
name varchar(20) not null,
groups int NOT NULL
);
insert into #tbl values('a', 35), ('a', 36), ('b', 35), ('c', 36), ('d', 37);
select *
from #tbl tbl
WHERE NOT EXISTS
(
SELECT COUNT(groups), name
FROM #tbl t
WHERE EXISTS
(
SELECT name
FROM #tbl tb
WHERE groups = 35
and tb.name=t.name
)
AND t.name = tbl.name
GROUP BY name
HAVING COUNT(groups)=1
)
;
您似乎需要一个 exists() 条件。尝试:
select *
from tbl t
where t.groups >= 35
and (
t.groups > 35
or exists(select * from tbl t2 where t2.name = t.name and t2.groups = 36)
)
还有其他方法可以安排 where 子句来达到相同的效果。预先设置 t.groups >= 35 条件应该使查询优化器能够利用组上的索引。
您可以为此使用窗口计数
这样可以避免多次加入 table
SELECT
name,
groups
FROM (
SELECT *,
Count36 = COUNT(CASE WHEN groups = 36 THEN 1 END) OVER (PARTITION BY name)
FROM tbl
WHERE groups >= 35
) tbl
WHERE groups >= 36 OR Count36 > 0;
试试这个:
DECLARE @tbl table ( [name] varchar(20) not null, groups int NOT NULL );
INSERT INTO @tbl VALUES
('a', 35), ('a', 36), ('b', 35), ('c', 36), ('d', 37);
DECLARE @group int = 35;
; WITH cte AS (
SELECT
[name]
, COUNT ( DISTINCT groups ) AS distinct_group_count
FROM @tbl
WHERE
groups >= @group
GROUP BY
[name]
)
SELECT t.* FROM @tbl AS t
INNER JOIN cte
ON t.[name] = cte.[name]
WHERE
cte.distinct_group_count > 1
OR t.groups > @group;
RETURNS
+------+--------+
| name | groups |
+------+--------+
| a | 35 |
| a | 36 |
| c | 36 |
| d | 37 |
+------+--------+
基本上,这会将名称结果限制为值 >= 35 且关联了多个不同组的组,或者组值大于 35 的任何名称。针对您的数据做出了多项假设,但我相信这个逻辑仍然适用。
这是我正在使用的模式和数据
CREATE TABLE tbl (
name varchar(20) not null,
groups int NOT NULL
);
insert into tbl values('a', 35);
insert into tbl values('a', 36);
insert into tbl values('b', 35);
insert into tbl values('c', 36);
insert into tbl values('d', 37);
| name | groups|
|------|-------|
| a | 35 |
| a | 36 |
| b | 35 |
| c | 36 |
| d | 37 |
现在我只需要组数大于或等于 35 的名称 但还有一个额外的问题是,当相应的 groups=36 也存在时,我只能包含 group=35 的行
| name | groups|
|------|-------|
| a | 35 |
| a | 36 |
第二个条件是它可以包括那些组数大于或等于 36 而组数不等于 35 的名称
| name | groups|
|------|-------|
| c | 36 |
| d | 37 |
唯一应该忽略的情况是记录只有 groups=35 而没有对应的 groups=36
| name | groups|
|------|-------|
| b | 35 |
我试过以下方法
select name from tbl
where groups>=35
group by name
having count(distinct(groups))>=2
or groups>=36;
这是我面临的错误Column 'tbl.groups' is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause.
因此,据我所知,您只想限制组 35 所在的位置。我想,让我们尝试隔离那些只有 groups=35 然后不存在的名称。这是您想要的正确输出吗?
此外,在 where 子句中使用复杂的 OR 通常会导致您的查询不可搜索。最好使用 UNION 或一些构建查询的方法,以便每个部分都可以使用索引(如果可以的话)。
if object_id('tempdb..#tbl') is not null drop table #tbl;
CREATE TABLE #tbl (
name varchar(20) not null,
groups int NOT NULL
);
insert into #tbl values('a', 35), ('a', 36), ('b', 35), ('c', 36), ('d', 37);
select *
from #tbl tbl
WHERE NOT EXISTS
(
SELECT COUNT(groups), name
FROM #tbl t
WHERE EXISTS
(
SELECT name
FROM #tbl tb
WHERE groups = 35
and tb.name=t.name
)
AND t.name = tbl.name
GROUP BY name
HAVING COUNT(groups)=1
)
;
您似乎需要一个 exists() 条件。尝试:
select *
from tbl t
where t.groups >= 35
and (
t.groups > 35
or exists(select * from tbl t2 where t2.name = t.name and t2.groups = 36)
)
还有其他方法可以安排 where 子句来达到相同的效果。预先设置 t.groups >= 35 条件应该使查询优化器能够利用组上的索引。
您可以为此使用窗口计数
这样可以避免多次加入 table
SELECT
name,
groups
FROM (
SELECT *,
Count36 = COUNT(CASE WHEN groups = 36 THEN 1 END) OVER (PARTITION BY name)
FROM tbl
WHERE groups >= 35
) tbl
WHERE groups >= 36 OR Count36 > 0;
试试这个:
DECLARE @tbl table ( [name] varchar(20) not null, groups int NOT NULL );
INSERT INTO @tbl VALUES
('a', 35), ('a', 36), ('b', 35), ('c', 36), ('d', 37);
DECLARE @group int = 35;
; WITH cte AS (
SELECT
[name]
, COUNT ( DISTINCT groups ) AS distinct_group_count
FROM @tbl
WHERE
groups >= @group
GROUP BY
[name]
)
SELECT t.* FROM @tbl AS t
INNER JOIN cte
ON t.[name] = cte.[name]
WHERE
cte.distinct_group_count > 1
OR t.groups > @group;
RETURNS
+------+--------+
| name | groups |
+------+--------+
| a | 35 |
| a | 36 |
| c | 36 |
| d | 37 |
+------+--------+
基本上,这会将名称结果限制为值 >= 35 且关联了多个不同组的组,或者组值大于 35 的任何名称。针对您的数据做出了多项假设,但我相信这个逻辑仍然适用。