如果所有列都返回null或仅返回非null列,如何返回一条记录

时间:2019-05-16 07:20:36

标签: sql oracle plsql

我需要一种方法来处理以下情况。

编写查询以转换以下结果集

  SizedBox(
     width : 300,
     height: 300,
     child:    Stack(
            fit: StackFit.expand,
            alignment: Alignment.center,
            children: <Widget>[
              new Container(
                 decoration: new BoxDecoration(color: Colors.black45),
              )
            ...

...对此

ID|Location|NameA|ValueA|NameB|ValueB|NameC|ValueC|NameD|ValueD|
__|________|_____|______|_____|______|_____|______|_____|______|
0 |   BL   |NULL |NULL  |NULL |NULL  |NULL |NULL  |NULL |NULL  | 
__|________|_____|______|_____|______|_____|______|_____|______|
1 |   GT   |x    |y     |NULL |NULL  |s    |z     |NULL |NULL  |
__|________|_____|______|_____|______|_____|______|_____|______|
2 |   SZ   |c    |d     |e    |f     |NULL |NULL  |NULL |NULL  | 
__|________|_____|______|_____|______|_____|______|_____|______|
  • 对于所有“名称/值”为NULL的记录,在结果表中我不希望有四个记录,我只需要一个。
  • 对于具有多个NON-NULL名称/值对的记录,我希望它们显示为结果表的单独记录,而忽略NULL名称/值对。
  • 例如,如果NameA不为null且ValueA为null,则按照原始方案将其从结果表中丢弃。

编辑: 我决定使用您的交叉应用选项,但是在实现它时遇到了麻烦, 我将在原始查询中粘贴已更改的表名,以便Gordon或其他人可以提供帮助。

ID|Location|Name |Value |
__|________|_____|______|
0 |   BL   |NULL |NULL  |
__|________|_____|______|
1 |   GT   |x    |y     |
__|________|_____|______|
1 |   GT   |s    |z     |
__|________|_____|______|
2 |   SZ   |c    |d     |
 _|________|_____|______|
2 |   SZ   |e    |f     |

4 个答案:

答案 0 :(得分:2)

或者您可以按以下方式使用UNPIVOT

-- Sample Data:
WITH dat(ID,Location,NameA,ValueA,NameB,ValueB,NameC,ValueC,NameD,ValueD) AS
  (SELECT 0 ,   'BL'   ,NULL ,NULL  ,NULL ,NULL,NULL ,NULL,NULL ,NULL  FROM dual
    UNION
   SELECT 1 ,   'GT'   ,'x'  ,'y'   ,NULL ,NULL,'s'  , 'z',NULL ,NULL  FROM dual
    UNION
   SELECT 2 ,   'SZ'   ,'c'  ,'d'   ,'e'  ,'f' ,NULL ,NULL,NULL ,NULL  FROM dual)
-- SQL-Statement:
SELECT id,location, NAME, VALUE 
  FROM (
    SELECT id,location, NAME, VALUE,sk, MAX(NAME) over (PARTITION BY id) max_name
      FROM dat
      UNPIVOT INCLUDE NULLS(
        (NAME, VALUE) FOR sk IN ((NameA, ValueA) AS 1
                                ,(NameB, ValueB) AS 2
                                ,(NameC, ValueC) AS 3
                                ,(NameD, ValueD) AS 4)
      )
)
WHERE (SK = 1 AND max_name IS NULL)
   OR NAME IS NOT NULL

答案 1 :(得分:1)

Oracle中最简单的答案可能是:

select t.id, t.namea as name. t.valuea as valuea
from t
where t.namea is not null or 
      (t.namea is null and t.nameb is null and t.namec is null and t.named is null)
union all
select t.id, t.nameb as name. t.valueb as valuea
from t
where t.nameb is not null 
union all
select t.id, t.namec as name. t.valuec as valuea
from t
where t.namec is not null 
union all
select t.id, t.named as name. t.valued as valuea
from t
where t.named is not null ;

出于某些(可能是荒谬的原因),我以为该问题被标记为SQL Server,从而在下面提供了答案。 Oracle 12C支持横向联接,因此以下内容可适用于Oracle语法。

我将剩下的答案留在这里。

select t.id, v.name, v.value
from t cross apply
     (values ('a', t.namea, t.valuea),
             ('b', t.nameb, t.valueb),
             ('c', t.namec, t.valuec),
             ('d', t.named, t.valued)
     ) v(which, name, value)
where v.name is not null or
      (v.which = 'a' and

      );

我喜欢使用cross apply取消透视。因此基本的基本原理是:

select t.id, v.name, v.value
from t cross apply
     (values (t.namea, t.valuea), (t.nameb, t.valueb), (t.namec, t.valuec), (t.named, t.valued)
     ) v(name, value);

然后您想要一个条件,即null仅是 all 个值时才出现一次。您可以为此使用窗口功能:

select id, name, value
from (select t.id, v.name, v.value,
             count(*) over (partition by t.id, v.name, v.value) as cnt_nv,
             row_number() over (order by t.id) as seqnum
      from t cross apply
           (values (t.namea, t.valuea), (t.nameb, t.valueb), (t.namec, t.valuec), (t.named, t.valued)
           ) v(name, value)
     ) v
where name is not null or
      (cnt_nv = 4 and seqnum = 1);

我不清楚您是否只是在乎nameNULL还是想同时将namevalue都设为NULL。两种逻辑都可以实现;只是不清楚你想要哪个。

编辑:

您也可以在不使用子查询的情况下执行此操作:

select t.id, v.name, v.value
from t cross apply
     (values ('a', t.namea, t.valuea),
             ('b', t.nameb, t.valueb),
             ('c', t.namec, t.valuec),
             ('d', t.named, t.valued)
     ) v(which, name, value)
where v.name is not null or
      (v.which = 'a' and
       t.namea is null and t.nameb is null and t.namec is null and t.named is null
      );

这可能是编写逻辑的最简单方法。

答案 2 :(得分:0)

只需使用UNION,如下所示:

select ID,Location,NameA,ValueA from table where NameA is not null
union
select ID,Location,NameB,ValueB from table where NameB is not null
union
select ID,Location,NameC,ValueC from table where NameC is not null
union
select ID,Location,NameD,ValueD from table where NameD is not null
union
select ID,Location,null,null from table where coalesce(NameA,NameB,NameC,NameD) is null

答案 3 :(得分:0)

declare @tempTbl table ([ID] int, [Location] nvarchar(10), [Name] nvarchar(10), [Value] nvarchar(10));
insert into  @tempTbl 
 select  [ID],[Location],[Name], [Value] From
(
SELECT [ID],[Location],[NameA] as [Name],[ValueA] as [Value] FROM [dbo].[LocationTbl]
    UNION 
    SELECT [ID],[Location],[NameB],[ValueB] FROM [dbo].[LocationTbl]
    UNION 
    SELECT [ID],[Location],[NameC],[ValueC] FROM [dbo].[LocationTbl]
    UNION 
    SELECT [ID],[Location],[NameD],[ValueD] FROM [dbo].[LocationTbl]
) as X
where [Name] is not null AND [Value] is not null
select * from @tempTbl
UNION
SELECT [ID], [Location], Null as [Name], Null as [Value]
FROM [dbo].[LocationTbl]
WHERE  [Location] not in (select [Location] from @tempTbl)
order by [ID];

尝试一下。