SQL查询对我来说太复杂了

时间:2016-11-02 10:07:09

标签: sql oracle

我有一个包含note列的表格,其值可能为“开始”或“结束”。然后还有其他列可以具有相同的值,但只有差异在于'note'列...

我需要选择将'note'设置为'Start'的行,但只有那些,没有行具有相同的值,'note'设置为'End'。对不起,解释起来很复杂。我会尝试展示一些例子。

Coll1   Coll2   Coll3   note
-----------------------------
a       a       a       Start
a       a       a       End
b       b       b       Start
b       b       b       End
c       c       c       Start <- I need select those rows
-- There is no row with 'c c c End' combination in the table
d       d       d       Start
d       d       d       End
e       e       e       Start <- I need select those rows
-- There is no row with 'e e e End' combination in the table

有人可以帮帮我吗?

8 个答案:

答案 0 :(得分:4)

尝试使用

SELECT *
  FROM tbl t1
  WHERE t1.note = 'Start' AND NOT EXISTS (SELECT * 
                                            FROM tbl t2 
                                           WHERE t2.note = 'End' 
                                             AND t2.Coll1 = t1.Coll1 
                                             AND t2.Coll2 = t1.Coll1 
                                             AND t2.Coll3 = t1.Coll3)

也许这个查询不是最优的,但这个查询很容易理解。

答案 1 :(得分:2)

这对你有用吗?

SELECT *
FROM mytable t1
LEFT JOIN mytable t2 ON
    t1.Coll1 = t2.Coll1 AND
    t1.Coll2 = t2.Coll2 AND
    t1.Coll3 = t2.Coll3 AND
    t2.note = 'End'
WHERE t1.note = 'Start' AND t2.Coll1 IS NULL

答案 2 :(得分:2)

最简单的方法应该是聚合记录并检查该组是否有结束记录:

select col1, col2, col3
from mytable
group by col1, col2, col3
having count(case when note = 'Start' then 1 end) = 1
   and count(case when note = 'End' then 1 end) = 0;

根据需要调整此项(例如,如果您对几个开始记录没事,请将其设为&gt; = 1而不是= 1)。

答案 3 :(得分:2)

如果在问题中包含CREATE TABLE和INSERT语句,您将获得更多答案。我正在使用PostgreSQL; Oracle类似。

create table test (
  col1 char(1) not null,
  col2 char(1) not null,
  col3 char(1) not null,
  note varchar(10) not null
    check (note in ('start', 'end')),
  primary key (col1, col2, col3, note)
);

我假设primary key (col1, col2, col3, note)。 NULL的存在使这种方法复杂化。

insert into test values
('a', 'a', 'a', 'start'),
('a', 'a', 'a', 'end'),
('b', 'b', 'b', 'start'),
('b', 'b', 'b', 'end'),
('c', 'c', 'c', 'start'),
('d', 'd', 'd', 'start'),
('d', 'd', 'd', 'end'),
('e', 'e', 'e', 'start');

现在我们可以采取一系列启动和一系列目标。左外连接将保留启动中的所有行;末尾缺少的行将填充NULL。

with starts as (
  select * from test where note = 'start'
), ends as (
  select * from test where note = 'end'
)
select s.* from starts s
left outer join ends e
  on e.col1 = s.col1 
 and e.col2 = s.col2 
 and e.col3 = s.col3 
where e.col1 is null
  and e.col2 is null
  and e.col3 is null
  and e.note is null;

答案 4 :(得分:0)

SELECT coll1, coll2, coll3, count(*)
FROM tbl
Where note='start'
GROUP BY coll1, coll2, coll3,
HAVING count(*) < 2

答案 5 :(得分:0)

这是另一种解决方案,可以添加到您已经拥有的解决方案中:

WITH sample_data AS (SELECT 'a' Coll1, 'a' Coll2, 'a' Coll3, 'Start' note FROM dual UNION ALL
                     SELECT 'a' Coll1, 'a' Coll2, 'a' Coll3, 'End' note FROM dual UNION ALL
                     SELECT 'b' Coll1, 'b' Coll2, 'b' Coll3, 'Start' note FROM dual UNION ALL
                     SELECT 'b' Coll1, 'b' Coll2, 'b' Coll3, 'End' note FROM dual UNION ALL
                     SELECT 'c' Coll1, 'c' Coll2, 'c' Coll3, 'Start' note FROM dual UNION ALL
                     SELECT 'd' Coll1, 'd' Coll2, 'd' Coll3, 'Start' note FROM dual UNION ALL
                     SELECT 'd' Coll1, 'd' Coll2, 'd' Coll3, 'End' note FROM dual UNION ALL
                     SELECT 'e' Coll1, 'e' Coll2, 'e' Coll3, 'Start' note FROM dual)
-- End of mimicking a table called "sample_data" with your data in it
-- for use in the query below:
SELECT coll1,
       coll2,
       coll3,
       MAX(CASE WHEN note = 'Start' THEN note END) note
FROM   sample_data
GROUP BY coll1,
         coll2,
         coll3
HAVING   MAX(CASE WHEN note = 'Start' THEN note END) = 'Start'
AND      MAX(CASE WHEN note = 'End' THEN note END) IS NULL;

COLL1 COLL2 COLL3 NOTE
----- ----- ----- -----
e     e     e     Start
c     c     c     Start

它只有一次访问表(与Surename的答案中的两次访问相反),但是您应该测试哪种解​​决方案最适合您的数据和表结构 - 一种可能比另一种更快。

答案 6 :(得分:0)

为了完整起见,因为在评论中建议优先考虑一组:

select col1, col2, col3 from mytable where note = 'Start'
minus
select col1, col2, col3 from mytable where note = 'End';

答案 7 :(得分:0)

从tb1中选择col1,col2,col3,count(注释) 按col1,col2,col3分组 有计数(注释)= 1

你也可以做到

从tb1中选择* 注意&lt;&gt; &#39;结束&#39;并注意=&#39;开始&#39;