SELECT Statement within IF statement - if-statement

I would like to get a different result to my select statement when a parameter is 0, 1 or 2. I am not very skilled in PLSQL so I am not sure if my code would give the expected result. If i run this code i get a "SQL statement ignored" on line 3.
BEGIN
IF (:PARTYPE = 1) THEN
SELECT * FROM x
WHERE to_date(date) >= (Select to_date(sysdate)from DNV.dual)
ELSE
SELECT * FROM x
WHERE to_date(date) <= (Select to_date(sysdate)from DNV.dual)
END IF;
END;
This is just a example of my SELECT statement. Later this statement will become longer and more complex but I think this shows which results I am trying to get.
Below is a copy of my entire code but because I am not allowed to show this it has become very unreadable:
BEGIN
IF (:PARTYPE = 1) THEN
Select table1.Column1
, table1.Column2
, table1.Column3
, table1.Column4
, table1.Column5
, table1.Column6
, table1.Column7
, table1.Column8
, table1.Column9
, table1.Column10
, table1.Column11
, table1.Column12
, (Select table2.ColumnX From x2 table2 Where somthing) as "something" From x1 table1
WHERE to_date(date) >= (Select to_date(sysdate)from DNV.dual)
Order by columnX
ELSE
Select table1.Column1
, table1.Column2
, table1.Column3
, table1.Column4
, table1.Column5
, table1.Column6
, table1.Column7
, table1.Column8
, table1.Column9
, table1.Column10
, table1.Column11
, table1.Column12
, (Select table2.ColumnX From x2 table2 Where somthing) as "something" From x1 table1
WHERE to_date(date) <= (Select to_date(sysdate)from DNV.dual)
Order by columnX
END IF;
END;
I have created some new code with which i am trying to learn how a case statement works. This might help me with the code above. Unfortunately this code also doesn't work but I think it explanes my situation better. In this excample i use a separate table with data i made up. In some cases user2 is null but user1 is always filled. I want to get all items where user2 equals the parameter but if user2 is null and user1 does equal the paramter i still need that item to apear.
Select t1.user1,
t1.user2
From table t1
Where (Case
When t1.user2 IS NULL Then t1.user1 in (:PARUSER)
ELSE t1.user2 in (:PARUSER)
End Case)

Since the relational operator of the where clause depends on the partype, you cannot do the traditional CASE statement charm here. I'll have to resort with this one:
SELECT * FROM x
WHERE (to_date(date) >= (Select to_date(sysdate)from DNV.dual) AND :PARTYPE = 1)
OR (to_date(date) <= (Select to_date(sysdate)from DNV.dual) AND :PARTYPE != 1)

Related

JOINING Two Tables together in SAS

I am working on the this SAS code and would need assistance with joining the two tables below. I am getting errors while trying to join the two tables.
Requirement: i. Left Join Table B to Table A
Table A:
PROC SQL;
create table stand as select distinct
put(datepart(Max(a.REPORT_DATE)),Date9.) as M_Date
, a.BUSINESS_GROUP as PORTF_LEVEL1
, A.SPLIT as PORTF_LEv2
, Count(distinct a.Report_Date) as Number_of_Days
, (B.TOTAL_BREACH/Count(distinct a.Report_Date))*100 as FREQ
, A.MINIMUM_ACCEPTABLE_COUNT
, A.MAX_COUNT
, (case WHEN (B.TOTAL_BREACH/Count(distinct a.Report_Date)) * 100 LT MIN_COUNT
THEN 'TRUE' ELSE 'FALSE' END) as NUMBER__UNDER
, (case WHEN (B.TOTAL_BREACH/Count(distinct a.Report_Date)) * 100 GT MAX_COUNT THEN 'TRUE' ELSE 'FALSE' END) as NUMBER__OVER
from temp a
INNER join
( select BUSINESS_GROUP as PORTF_LEVEL1
,SPLIT AS PORTF_LEv2
,Count(distinct c.Report_Date) as Number_of_Days
from temp c
Inner join temp2 d
on c.Report_Date=d.Report_Date
WHERE &Alert and TENOR = '+'
and datepart(c.REPORT_DATE) ge '31-APR-21'd
and datepart(c.REPORT_DATE) le '31-APR-22'd
Group by BUSINESS_GROUP, SPLIT
)B
on a.BUSINESS_GROUP = b.PORTF_LEVEL1
AND a.SPLIT = b.PORTF_LEVEL2
INNER JOIN temp2 e
on a.REPORT_DATE = e.REPORT_DATE
where &Alert and TENOR = '+'
and datepart(a.REPORT_DATE) ge '31-APR-21'd
and datepart(a.REPORT_DATE) le '31-APR-22'd
Group by Business_GROUP, SPLIT
;
QUIT;
Table B:
In the table B, i am trying to find the median of the variable Data_M. The code seems to be okay. I only need assistance joining the Table B to table A above.
Proc sql outobs=1; create table median_dt1 as select distinct put(datepart(max(REPORT_DATE)), date9.) as M_Date , median(Data_M) as median_data from transp
WHERE datepart(REPORT_DATE) ge '01-APR-22'd and datepart(REPORT_DATE) le '31-APR-22'd group by BUSINESS_GROUP order by Report_Date Desc; quit;
Thank you in advance!
sas
from temp a
INNER join
( select BUSINESS_GROUP as PORTF_LEVEL1
,SPLIT AS PORTF_LEv2
,Count(distinct c.Report_Date) as Number_of_Days
from temp c
Inner join temp2 d
on c.Report_Date=d.Report_Date
WHERE &Alert and TENOR = '+'
and datepart(c.REPORT_DATE) ge '31-APR-21'd
and datepart(c.REPORT_DATE) le '31-APR-22'd
Group by BUSINESS_GROUP, SPLIT
)B
on a.BUSINESS_GROUP = b.PORTF_LEVEL1
AND a.SPLIT = b.PORTF_LEVEL2
You're trying to join on b.PORTF_LEVEL2. However, that column doesn't exist in B. The column "PORTF_LEV2" exists, though. Try that?
If that doesn't resolve the issue, please paste the complete error message that you're receiving.

How to use string as column name in Bigquery

There is a scenario where I receive a string to the bigquery function and need to use it as a column name.
here is the function
CREATE OR REPLACE FUNCTION METADATA.GET_VALUE(column STRING, row_number int64) AS (
(SELECT column from WORK.temp WHERE rownumber = row_number)
);
When I call this function as select METADATA.GET_VALUE("TXCAMP10",149); I get the value as TXCAMP10 so we can say that it is processed as SELECT "TXCAMP10" from WORK.temp WHERE rownumber = 149 but I need it as SELECT TXCAMP10 from WORK.temp WHERE rownumber = 149 which will return some value from temp table lets suppose the value as A
so ultimately I need value A instead of column name i.e. TXCAMP10.
I tried using execute immediate like execute immediate("SELECT" || column || "from WORK.temp WHERE rownumber =" ||row_number) from this stack overflow post to resolve this issue but turns out I can't use it in a function.
How do I achieve required result?
I don't think you can achieve this result with the help of UDF in standard SQL in BigQuery.
But it is possible to do this with stored procedures in BigQuery and EXECUTE IMMEDIATE statement. Consider this code, which simulates the situation you have:
create or replace table d1.temp(
c1 int64,
c2 int64
);
insert into d1.temp values (1, 1), (2, 2);
create or replace procedure d1.GET_VALUE(column STRING, row_number int64, out result int64)
BEGIN
EXECUTE IMMEDIATE 'SELECT ' || column || ' from d1.temp where c2 = ?' into result using row_number;
END;
BEGIN
DECLARE result_c1 INT64;
call d1.GET_VALUE("c1", 1, result_c1);
select result_c1;
END;
After some research and trial-error methods, I used this workaround to solve this issue. It may not be the best solution when you have too many columns but it surely works.
CREATE OR REPLACE FUNCTION METADATA.GET_VALUE(column STRING, row_number int64) AS (
(SELECT case
when column_name = 'a' then a
when column_name = 'b' then b
when column_name = 'c' then c
when column_name = 'd' then d
when column_name = 'e' then e
end from WORK.temp WHERE rownumber = row_number)
);
And this gives the required results.
Point to note: the number of columns you use in the case statement should be of the same datatype else it won't work

Big query analytical function not giving expected results

I am trying to write a sql in bigquery and I have a requirement to filter records based on a group by column and another column in the table
what I mean is I want to check if the group by column(column name:mnt) has more than one row then I have to check if col2 (col name: zel) value, then I have to apply a filter saying col2 ='X' and only pass that record else pass i.e dont filter the records if the col1 has only distinct one value per group
So I have written a sql to do this I have used row_number as well as rank , dense rank function but I noticed the value of rank and dense rank and row number functions return same value for a group
Please see the below code
#standardsql
with t1 as (SELECT mnt,
case when rank() over (partition by ltrim(rtrim(mnt)) order by
ltrim(rtrim(mnt)) asc) >1 then 'Y' else 'N' end
as flag,
rank() over (partition by mnt order by mnt) as rn,
dense_rank() over (partition by mnt order by mnt) as drn, FROM
projectname.datasetname.tablename1),
t2 as ( SELECT
mnt,
rel,
lif,
lts,
lokez FROM projectname.datasetname.tablename2
WHERE lts <> "" AND _PARTITIONTIME = TIMESTAMP(CURRENT_DATE()) ) ,
t3 as (SELECT
lif,
lifn,
lts,
par FROM `projectname.datasetname.tablename3`)
,t4 as (SELECT rcv FROM `projectname.datasetname.tablename4` WHERE mes
= 'PRO')
select * from (
SELECT t1.mnt as mnt,
t1.flag,
t1.rn,
t1.drn
t2.rel as zel,
t2.lokez as ZLOEKZ,
t4.rcv as Zrcv
FROM t1 left join t2 on replace(t1.mnt, '00000000', '') =
REPLACE(t2.mnt, '00000000', '') AND t1.lif = t2.lif and t2.lts <> ""
and
case when t1.flag = 'Y' and t2.rel ='X' then 1
when (t1.flag ='N' and t2.rel=t2.rel) or (t1.flag ='N' and t2.rel
is null) then 1
when t1.flag = 'Y' and t2.rel <>'X' then 2
else 3
end = 1
left join t3 ON t1.lif = t3.lif AND t2.lts = t3.lts AND
t3.par = 'BA' left join t4 on t4.rcv = t3.lifn and t2.lokez is null )
where ZLOEKZ is null order by mnt
As you can see I am using a case statement and even it seems to be not working fine. I am pasting the case condition below again
case when t1.flag = 'Y' and t2.rel ='X' then 1
when (t1.flag ='N' and t2.rel=t2.rel) or (t1.flag ='N' and
t2.rel
is null) then 1
when t1.flag = 'Y' and t2.rel <>'X' then 2
else 3
end = 1
But the expected record count did not match so I added the above sql lines to see if my analytical functions were giving me result I wanted
rank() over (partition by mnt order by mnt) as rn,
dense_rank() over (partition by mnt order by mnt) as drn
strangely for same mnt number the rank , dense rank and row_number function are assigning the same value what am i doing wrong here.
mnt flag rn drn rel lokez rcv
100 N 1 1 X abc 123
100 N 1 1 null xyz 123
100 N 1 1 null def 234
This is my output
I mean as per my code for same mnt number I am seeing flag set to N instead of Y and for the rank and dense rank are giving me same number for all 3 mnt it is generating 1 instead of 123 (note for rank function I understand) but dense rank should not do that
I tried to convey the issue as efficiently as I could please let me know if there is any clarifications I can provide.
any help appreciated
thanks
SELECT * EXCEPT(ct) FROM (
SELECT *, COUNT() OVER(PARTITION BY mnt) AS ct
) WHERE ct=1 or zel='X'
This is the code snippet for the problem you mentioned. Use this in your code according to the logic.

How to return multiple values through function

I have created the below function that will return workspace details which the loggedin user has access to.
But this function is returning only the first record from the select list.
I need all the records to be displayed as output.
Please modify it and let me know.
CREATE OR REPLACE FUNCTION "F_WORKSPACE_LOGIN_USERS" (
p_email VARCHAR2
) RETURN VARCHAR2 IS
l_error VARCHAR2(1000);
l_workspace VARCHAR2(1000);
l_teams VARCHAR2(1000);
l_team VARCHAR2(1000);
BEGIN
FOR i IN ( SELECT a.name workspace,
a.team_id id
FROM slackdatawarehouse.teams a,
( SELECT TRIM(workspaces) workspaces
FROM alluser_workspaces_fact
WHERE lower(email) = lower(p_email)
) b
WHERE a.team_id IN ( SELECT c.team_id
FROM slackdatawarehouse.team_tokens c
)
OR instr(', '
|| lower(b.workspaces),', '
|| lower(a.name) ) > 0
ORDER BY 1 ) LOOP
l_teams := l_team
|| ','
|| i.id;
l_teams := ltrim(rtrim(l_teams,','),',');
RETURN l_teams;
END LOOP;
END;
Current output is :
T6HPQ5LF7,T6XBXVAA1,T905JLZ62,T7CN08JPQ,T9MV4732M,T5PGS72NA,T5A4YHMUH,TAAFTFS0P,T69BE9T2A,T85D2D8MT,T858U7SF4,T9D16DF5X,T9DHDV61G,T9D17RDT3,T5Y03HDQ8,T5F5QPRK7
Required output is :
T6HPQ5LF7
T6XBXVAA1
T905JLZ62
i need output like above as one by one
I don't know what that code really does (can't test it), but this might be the culprit:
...
RETURN l_teams;
END LOOP;
As soon as code reaches the RETURN statement, it exits the loop and ... well, returns what's currently in L_TEAMS variable. Therefore, move RETURN out of the loop:
...
END LOOP;
RETURN l_teams;
If it still doesn't work as expected (which might be the case), have a look at pipelined functions (for example, on Oracle-base site) as they are designed to return values you seem to be looking for.
A simple example:
SQL> create or replace type t_dp_row as object
2 (deptno number,
3 dname varchar2(20));
4 /
Type created.
SQL> create or replace type t_dp_tab is table of t_dp_row;
2 /
Type created.
SQL> create or replace function f_depts
2 return t_dp_tab pipelined
3 is
4 begin
5 for cur_r in (select deptno, dname from dept)
6 loop
7 pipe row(t_dp_row(cur_r.deptno, cur_r.dname));
8 end loop;
9 return;
10 end;
11 /
Function created.
SQL> select * from table(f_depts);
DEPTNO DNAME
---------- --------------------
10 ACCOUNTING
20 RESEARCH
30 SALES
40 OPERATIONS
SQL>

Oracle - how to convert string to row pair with out using WITH clause

In one of the column I have role and organization position
Example postion is 1 and organization is 310492 ...
1|310492|1|12319|1|562548|1|5202558
I need to convert this string to multiple rows
1,310492
1,12319
1,562548
1,5202558
I can not use WITH clause as I need to have is as correlated subquery
SELECT EXTRACT (VALUE (d), '//row/text()').getstringval ()
FROM (SELECT XMLTYPE ( '<rows><row>' || REPLACE (USERPROF.FIELD1, '|', '</row><row>') || '</row></rows>' ) AS xmlval FROM USERPROF WHERE FIELD1 IS NOT NULL ) x, TABLE (XMLSEQUENCE (EXTRACT (x.xmlval, '/rows/row'))) d
however this is converting entire string to multiple rows.
I tried playing with regexp and connect which is not helping me but fetching content of entire table by ignore where condition.
select regexp_substr(FIELD1,'[^|]+', 1, LEVEL) from USERPROF WHERE USERS_ID = 23502
connect by regexp_substr(FIELD1, '[^|]+', 1, level ) is not null;
Thanks in advance.
The SQL below:
with data as
(select '1|310492|1|12319|1|562548|1|5202558' as x from dual)
select fin from(
select 1+level-1 as occurrence
, instr(x,'|',1,1+level-1) as pos
, nvl(lead(instr(x,'|',1,1+level-1),1) over (order by 1+level-1)
, length(x))
as xxxx
, case when
nvl(lead(instr(x,'|',1,1+level-1),1) over (order by 1+level-1)
, length(x)) = length(x)
then instr(x,'|',1,1+level-1)
else
nvl(lag(instr(x,'|',1,1+level-1),1) over (order by 1+level-1),1) end as yyyy
, substr(x
,case when
nvl(lead(instr(x,'|',1,1+level-1),1) over (order by 1+level-1)
, length(x)) = length(x)
then instr(x,'|',1,1+level-1)
else
nvl(lag(instr(x,'|',1,1+level-1),1) over (order by 1+level-1),1) end
,nvl(lead(instr(x,'|',1,1+level-1),1) over (order by 1+level-1)
, length(x))
- case when
nvl(lead(instr(x,'|',1,1+level-1),1) over (order by 1+level-1)
, length(x)) = length(x)
then instr(x,'|',1,1+level-1)
else
nvl(lag(instr(x,'|',1,1+level-1),1) over (order by 1+level-1),1) end
) as fin
, length(x) as lastrw
from data
connect by level <= length(x) - length(replace(x, '|')) - 1
order by 1) x
where mod(occurrence,2) = 1 or xxxx = lastrw
Results in:
FIN
1|310492
|1|12319
|1|562548
|1|520255
Note that I'm just using the with clause to use the data you gave as an example.