1
votes

Comment renvoyer un enregistrement si toutes les colonnes renvoient nulles ou ne renvoient que des colonnes non nulles

J'ai besoin d'un moyen de gérer le scénario suivant.

Rédigez une requête pour transformer l'ensemble de résultats suivant

select t.CADID, t.TECHNOLOGYTYPE, t.ACCESSSUPPLIER, t.LOCATION, t.LOCATIONTYPE, t.NETWORKTYPE, t.ACCESSTYPE, t.CARRIERTYPE, t.MAXDOWNSPEED, t.MAXUPSPEED, v.NAME, v.VALUE 
from( TableA t 
LEFT OUTER JOIN TableB VIEW0 ON (VIEW0.access_supplier = t.access_supplier
                                            AND VIEW0.network_type = t.network_type
                                            AND VIEW0.address_location_type_map_id = t.address_location_type_map_id
                                            AND VIEW0.NAME = 'Nls-type')
LEFT OUTER JOIN TableB VIEW1 ON (VIEW1.access_supplier = t.access_supplier
                                           AND VIEW1.network_type = t.network_type
                                            AND VIEW1.address_location_type_map_id = t.address_location_type_map_id
                                            AND VIEW1.NAME = 'NL-type')
LEFT OUTER JOIN TableB VIEW2 ON (VIEW2.access_supplier = t.access_supplier
                                            AND VIEW2.network_type = t.network_type
                                            AND VIEW2.address_location_type_map_id = t.address_location_type_map_id
                                            AND VIEW2.NAME = 'Net-type')
LEFT OUTER JOIN TableB VIEW3 ON (VIEW3.access_supplier = t.access_supplier
                                            AND VIEW3.network_type = t.network_type
                                            AND VIEW3.address_location_type_map_id = t.address_location_type_map_id
                                            AND VIEW3.NAME = 'Interconnect-level')
LEFT OUTER JOIN TableB VIEW4 ON (VIEW4.access_supplier = t.access_supplier
                                            AND VIEW4.network_type = t.network_type
                                            AND VIEW4.address_location_type_map_id = t.address_location_type_map_id
                                            AND VIEW4.NAME = 'FTU-type')
LEFT OUTER JOIN TableB VIEW5 ON (VIEW5.access_supplier = t.access_supplier
                                            AND VIEW5.network_type = t.network_type
                                            AND VIEW5.address_location_type_map_id = t.address_location_type_map_id
                                            AND VIEW5.NAME = 'Area-type')
 )WHERE (t.cad_id = '237864868')
cross apply
     (values ('a', VIEW0.name as name0, VIEW0.value as vaue0),
             ('b', VIEW1.name as name1, VIEW1.valueb as value1),
             ('c', VIEW2.name as name2, VIEW2.valuec as value2),
             ('d', VIEW3.name as name3, VIEW3.valued as value3)
     ) v(which, name, value)
where v.name is not null or
      (v.which = 'a' and
       v.name0 is null and v.name1 is null and v.name2 is null and v.name3 is null
      );

... en celui-ci

ID|Location|Name |Value |
__|________|_____|______|
0 |   BL   |NULL |NULL  |
__|________|_____|______|
1 |   GT   |x    |y     |
__|________|_____|______|
1 |   GT   |s    |z     |
__|________|_____|______|
2 |   SZ   |c    |d     |
 _|________|_____|______|
2 |   SZ   |e    |f     |
  • Pour les enregistrements avec toutes les colonnes NULL "Nom / Valeur" Je ne veux pas de quatre enregistrements dans le tableau résultant, je n'en veux qu'un.
  • Pour les enregistrements avec plus d'une paire nom / valeur NON NULL, je veux qu'ils soient affichés comme enregistrements séparés de la table résultante et les paires nom / valeur NULL ignorées.
  • Si, par exemple, NameA n'est pas nul et ValueA est nul, il est supprimé de la table résultante, comme dans le scénario d'origine.

MODIFIER: J'ai décidé d'utiliser votre option d'application croisée, mais j'ai du mal à l'implémenter, Je vais coller ma requête d'origine avec les noms de table modifiés pour que Gordon ou quelqu'un d'autre puisse m'aider.

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  | 
__|________|_____|______|_____|______|_____|______|_____|______|


4 Réponses :


0
votes

Utilisez simplement UNION , comme ci-dessous:

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


0 commentaires

2
votes

Ou vous pouvez utiliser UNPIVOT comme suit:

-- 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


0 commentaires

0
votes
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];
try this.

0 commentaires

1
votes

La réponse la plus simple dans Oracle est probablement:

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
      );

Pour certains (raison probablement absurde), j'ai fourni la réponse ci-dessous en pensant que la question était étiquetée SQL Server. Oracle 12C prend en charge les jointures latérales, donc ce qui suit pourrait être adapté à la syntaxe Oracle.

Je laisse le reste de la réponse ici.

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);

I aime décomposer en utilisant cross apply . Donc, le décompressé de base est:

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);

Vous voulez alors une condition que null n'apparaisse qu'une seule fois si c'est tout le valeurs. Vous pouvez utiliser les fonctions de fenêtre pour cela:

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

      );

Je ne sais pas si vous vous souciez simplement de savoir si nom est NULL code > ou si vous voulez que nom et valeur soient NULL . L'une ou l'autre logique peut être mise en œuvre; on ne sait tout simplement pas ce que vous voulez.

EDIT:

Vous pouvez également le faire sans sous-requête:

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 ;

Ceci est probablement la manière la plus simple d'écrire la logique.


5 commentaires

Je n'ai pas remarqué votre réponse, je vais essayer maintenant. Et pour répondre à votre question, dans la requête d'origine, VALUE ne sera jamais nulle, donc je me soucie seulement de savoir si toutes les colonnes NAME / VALUE d'un enregistrement sont nulles, pour renvoyer un enregistrement NULL et non celui de chaque paire NAME / VALUE. J'ai des problèmes à cause d'une requête originale complexe que j'ai, ce qui rend les choses un peu difficiles.


@T_Dejan. . . Pour une raison quelconque, la réponse originale était pour SQL Server (évidemment j'ai mal lu ou ignoré les balises sur la question). J'ai fourni une réponse compatible avec Oracle.


Pouvez-vous jeter un oeil, j'ai édité la question. J'ai essayé avec l'option de sous-requête et d'application croisée, mais j'ai du mal à l'implémenter. Est-ce possible dans Oracle?


@T_Dejan. . . Créez un CTE avec votre requête ( avec t comme (...) ), puis utilisez la première version avec union all .


@T_Dejan. . . Y a-t-il une raison pour laquelle vous n'avez pas accepté la réponse? Quelle version d'Oracle utilisez-vous?