sql >> Databasteknik >  >> RDS >> Oracle

exekvera SQL-fråga lagrad i en tabell

Detta verkar vara ett mycket märkligt krav, och ett som kommer att vara svårt att lösa på ett robust sätt. STMT_OR_VALUE är utföringsformen av One Column Two Usages-antimönster. Dessutom kräver att lösa STMT_OR_VALUE flödeskontrolllogik och användning av dynamisk SQL. Följaktligen kan det inte vara en ren SQL-lösning:du måste använda PL/SQL för att sätta ihop och köra den dynamiska frågan.

Här är ett proof of concept för en lösning. Jag har valt en funktion som du kan anropa från SQL. Det beror på ett antagande:varje frågesträng du infogar i TEST1.STMT_OR_VALUE har en projektion av en enda numerisk kolumn och varje värdesträng är en CSV med endast numerisk data . Med detta förbehåll är det enkelt att konstruera en funktion som antingen exekverar en dynamisk fråga eller tokeniserar strängen till en serie nummer; som båda samlas i bulk i en kapslad tabell:

create or replace function get_ids (p_name in test1.name%type) 
  return sys.odcinumberlist
is
  l_rec test1%rowtype;
  return_value sys.odcinumberlist;
begin

  select * into l_rec
  from test1
  where name = p_name;

  if l_rec.type = 'SQL_QUERY' then 
    -- execute a query
    execute immediate l_rec.stmt_or_value
      bulk collect into return_value;
  else
    -- tokenize a string
    select xmltab.tkn
    bulk collect into return_value
    from ( select l_rec.stmt_or_value from dual) t
        , xmltable(  'for $text in ora:tokenize($in, ",") return $text'
                      passing stmt_or_value as "in"
                      columns tkn number path '.'
                   ) xmltab;
  end if;
  return return_value;
end;
/

Observera att det finns mer än ett sätt att exekvera en dynamisk SQL-sats och ett flertal sätt att tokenisera en CSV till en serie siffror. Mina beslut är godtyckliga:ersätt gärna dina föredragna metoder här.

Denna funktion kan anropas med en table() ring:

select * 
from data
where id in ( select * from table(get_ids('first'))) -- execute query
or    id in ( select * from table(get_ids('second'))) -- get string of values
/

Den stora fördelen med detta tillvägagångssätt är att det kapslar in logiken kring utvärderingen av STMT_OR_VALUE och döljer användningen av dynamisk SQL. Följaktligen är det lätt att använda det i vilken SQL-sats som helst med bibehållen läsbarhet, eller att lägga till ytterligare mekanismer för att generera en uppsättning ID:n.

Denna lösning är dock skör. Det fungerar bara om värdena i test1 bord följa reglerna. Det vill säga att de inte bara måste kunna konverteras till en ström av enstaka nummer utan SQL-satserna måste vara giltiga och körbara av EXECUTE IMMEDIATE. Till exempel är det avslutande semikolonet i frågans exempeldata ogiltigt och skulle få EXECUTE IMMEDIATE att slungas. Dynamisk SQL är svårt inte minst eftersom det konverterar kompileringsfel till runtime-fel.



  1. Hur man beställer distinkta tupler i en PostgreSQL-fråga

  2. MySQL gå med och exkludera?

  3. Hur ärver jag en rolls privilegier?

  4. Främmande nycklar kontra partitionering