如果有多个值,则选择列不为null的行;如果为1值,则选择null

时间:2019-03-14 09:10:30

标签: sql sql-server

我有一个包含标题和值的表。

对于不同的标题,我想检索所有非空值,除非该标题仅具有NULL值。

我的桌子的样品看起来像这样:

Title    Value          
---------------
ex1      8
ex1      9
ex1      NULL
ex2      8
ex2      NULL
ex3      NULL

在此示例中,我希望我的期望输出如下所示:

Libelle  TPO_code   
--------------------        
ex1      8
ex1      9
ex2      8
ex3      NULL

我可以通过以下请求来获取除NULL值以外的所有值,但是在标题只有NULL值的情况下我被阻止了:

select distinct Title, Value 
from mytable
where Value is not null

7 个答案:

答案 0 :(得分:4)

您可以使用“不存在”:

SELECT  DISTINCT T.Title
,       T.Value 
FROM    mytable T
WHERE   T.Value IS NOT NULL
    OR  NOT EXISTS (
                        SELECT  NULL
                        FROM    mytable T2
                        WHERE   T2.Value IS NOT NULL
                            AND T2.Title = T1.Title
                    )

答案 1 :(得分:2)

如果需要,您可以避免使用联合并尝试:

DECLARE @myTable AS TABLE (Title CHAR(4) NOT NULL, Value INT NULL);

INSERT INTO @myTable (Title, Value)
VALUES ('ex1', 8)
,      ('ex1', 9)
,      ('ex1', NULL)
,      ('ex2', 8)
,      ('ex2', NULL)
,      ('ex3', NULL);

SELECT      DISTINCT
            T1.Title
,           T2.Value
  FROM      @myTable T1
  LEFT JOIN @myTable T2 ON  T2.Title = T1.Title
                       AND  T2.Value IS NOT NULL;

我建议您针对实际数据的形状尝试所有这些选项,以找到最有效的版本。也值得花一些时间检查索引等以使其更快。

答案 2 :(得分:1)

另一种选择是使用联合和子查询

declare @t table (Title varchar(10), Value int)
insert into @t (Title, Value)
values ('ex1', 8), ('ex1', 9), ('ex1', null), ('ex2', 8), ('ex2', null), ('ex3', null)

-- first get all rows with Value different from null
select t.Title,
       t.Value
from   @t t
where  t.Value is not null

union 

-- now also get all rows with just one row and where that row has null in value
select t.Title,
       t.Value
from   @t t
where  t.Title in ( select t2.title from @t t2 group by t2.Title having count(t2.Title) = 1 )
and    t.Value is null

这将返回此结果

Title   Value   
-----   -----   
ex1     8   
ex1     9   
ex2     8   
ex3     null    

答案 3 :(得分:1)

其他选项:

DECLARE @myTable AS TABLE (Title CHAR(4) NOT NULL, Value INT NULL);

INSERT INTO @myTable (Title, Value)
VALUES ('ex1', 8)
,      ('ex1', 9)
,      ('ex1', NULL)
,      ('ex2', 8)
,      ('ex2', NULL)
,      ('ex3', NULL);

-- Original
SELECT      DISTINCT
            T1.Title
,           T2.Value
  FROM      @myTable T1
  LEFT JOIN @myTable T2 ON  T2.Title = T1.Title
                       AND  T2.Value IS NOT NULL;

-- Common Table Expression example
WITH cte AS
    (SELECT *
     ,      ROW_NUMBER() OVER (PARTITION BY Title
ORDER BY Value DESC) RN
       FROM @myTable)
SELECT  cte.Title
,       cte.Value
  FROM  cte
 WHERE  RN = 1
   OR   cte.Value IS NOT NULL

如果您遍历公用表表达式并分配行号,则可以确保每个“标题”至少有一行,而不会出现多个表。如果您并排运行两个执行计划,那么我会发现在联接上节省了CTE版本。这将取决于要输入的数据量,尽管排序可能会比连接昂贵,尽管连接版本需要针对不同的数据进行排序。

让他们尝试实际数据并获得一些时间安排。让我知道是否有帮助。

答案 4 :(得分:0)

尝试一下

;WITH CTE (Title, Value)
AS
(          
SELECT 'ex1', 8    UNION ALL
SELECT 'ex1', 9    UNION ALL
SELECT 'ex1', NULL UNION ALL
SELECT 'ex2', 8    UNION ALL
SELECT 'ex2', NULL UNION ALL
SELECT 'ex3', NULL

)
,CTe2
AS
(
SELECT Title, Value, COUNT(Title)OVER(PARTITION BY Title ORDER BY Title) cnt
FROM CTE
)
SELECT  Title, 
        Value 
FROM CTe2 WHERE ISNULL(Value,1) <> 1
UNION ALL
SELECT  Title,
        Value 
FROM CTe2 WHERE cnt =1

结果

Title   Value
-------------
ex1      8
ex1      9
ex2      8
ex3      NULL

答案 5 :(得分:0)

我可以为您的问题建议以下解决方案,

select title,value from mytable where id is not null
union
select title,value from (
  select title,value, dense_rank() over (partition by title order by value)  rank from mytable)
where rank=1

答案 6 :(得分:0)

SELECT      
    DISTINCT a.Title,           
             b.Value   
FROM      
    mytable a   
LEFT JOIN 
    mytable b 
ON  
    a.Title = b.Title 
AND  
    b.Value IS NOT NULL;