DBeaver - Dynamic variable in PIVOT - column - oracle

PS: Thanks for your understanding, my English isn't very good. ;-)
I use DBeaver and when I run this sql :
#set deb_period = 202010
#set end_period = 202109
WITH tmp AS (
--Permet de générer une liste de mois entre les deux bornes temporelles
SELECT to_char(add_months(to_date(:deb_period, 'yyyymm'), level -1), 'yyyymm') mois
FROM dual
CONNECT BY LEVEL <= months_between(to_date(:end_period, 'yyyymm'), to_date(:deb_period, 'yyyymm')) + 1
)
SELECT DISTINCT
per.inss
,tmp.mois
,CASE fam.type
WHEN 'MONO' THEN 'M'
ELSE 'D'
END AS typ_fam
FROM
beneficiaries ben
LEFT JOIN lumpsum_beneficiaries lum ON lum.actor_id = ben.actor_id
INNER JOIN actors ac ON ac.actor_id = ben.actor_id
INNER JOIN persons per ON per.person_id = ac.person_id
AND per.inss IN (00000018043)
INNER JOIN historical_family_situations his_fam ON his_fam.concerned_natural_person_id = ac.person_id
INNER JOIN family_situations fam ON his_fam.historical_fam_situation_id = fam.historical_fam_situation_id
INNER JOIN tmp ON
/*AND*/ TO_NUMBER(TO_CHAR(LAST_DAY(ADD_MONTHS(TO_DATE(tmp.mois, 'yyyymm'), -1)),'yyyymmdd')) BETWEEN TO_NUMBER(TO_CHAR(fam.start_date,'yyyymmdd')) AND NVL(TO_NUMBER(TO_CHAR(fam.end_date,'yyyymmdd')),99991231)
WHERE lum.actor_id IS NULL
ORDER BY 1,2 ASC
;
I get this result:
Result
What I want to do is rotate the data and keep the variable part of the period.
This is what I do with Oracle sdl developer :
column chaque_mois new_value str_in_statement
select listagg(''''||mois||'''',',')
within group (order by mois) as chaque_mois
from (
--Permet de générer une liste de mois entre les deux bornes temporelles
SELECT to_char(add_months(to_date(202010, 'yyyymm'), level -1), 'yyyymm') mois
FROM dual
CONNECT BY LEVEL <= months_between(to_date(202109, 'yyyymm'), to_date(202010, 'yyyymm')) + 1
)
;
WITH tmp AS (
--Permet de générer une liste de mois entre les deux bornes temporelles
SELECT to_char(add_months(to_date(202010, 'yyyymm'), level -1), 'yyyymm') mois
FROM dual
CONNECT BY LEVEL <= months_between(to_date(202109, 'yyyymm'), to_date(202010, 'yyyymm')) + 1
)
SELECT *
FROM
(SELECT DISTINCT
per.inss
,tmp.mois
,CASE fam.type
WHEN 'MONO' THEN 'M'
ELSE 'D'
END AS typ_fam
FROM
beneficiaries ben
LEFT JOIN lumpsum_beneficiaries lum ON lum.actor_id = ben.actor_id
INNER JOIN actors ac ON ac.actor_id = ben.actor_id
INNER JOIN persons per ON per.person_id = ac.person_id
AND per.inss IN (00000018043)
INNER JOIN historical_family_situations his_fam ON his_fam.concerned_natural_person_id = ac.person_id
INNER JOIN family_situations fam ON his_fam.historical_fam_situation_id = fam.historical_fam_situation_id
INNER JOIN tmp ON
/*AND*/ TO_NUMBER(TO_CHAR(LAST_DAY(ADD_MONTHS(TO_DATE(tmp.mois, 'yyyymm'), -1)),'yyyymmdd')) BETWEEN TO_NUMBER(TO_CHAR(fam.start_date,'yyyymmdd')) AND NVL(TO_NUMBER(TO_CHAR(fam.end_date,'yyyymmdd')),99991231)
WHERE lum.actor_id IS NULL
ORDER BY 1,2 ASC
)
PIVOT
(
MAX(TYP_FAM)
--FOR MOIS IN ('202010', '202109')
FOR MOIS IN (&str_in_statement)
)
;
Which gives me the right result:
Result Pivot with dynamic variable
My question: I try to adapt this sql to DBeaver but I get an error ORA-00900: invalid SQL statement. I think DBeaver doesn't want too much Column. Can you confirm and if so, is there any other way to get the same result in DBeaver?

Related

Need help in output for Oracle PLSQL Procedure

Am currently working on an oracle PL SQL procedure to list the project numbers, titles and names of employees who work on a project.
I am able to write a procedure that is able to get this info. However, I can only draw one output at a time as such:
1001 Computation
Alvin
Peter
How can I change my code to output all of the entries at the same time while printing them as such:
[Fragment Example][Showing only 1st 3 entries]
1001 Computation: Alvin, Peter
1002 Study methods: Bob, Robert
1003 Racing car: Robert
[Current Code]
create or replace procedure PROJECTGROUPS(projectid IN WorksOn.P#%TYPE)
is
PID Project.P#%TYPE;
PNAME Project.PTitle%TYPE;
ENAME Employee.Name%TYPE;
CURSOR query is
select Employee.Name from Employee
left outer join WorksOn On Employee.E# = WorksOn.E#
where WorksOn.P# = projectid
order by Employee.Name ASC
fetch first 20 rows only;
--
--
begin
select P#, PTitle into PID, PNAME from project where project.p# = projectid;
DBMS_OUTPUT.PUT_LINE(PID || ' ' || PNAME);
--
open query;
loop
fetch query into ENAME;
if query%NOTFOUND then exit;
end if;
DBMS_OUTPUT.PUT_LINE(ENAME);
end loop;
close query;
end PROJECTGROUPS;
You can directly use it in a single query and loop through it as follows:
CREATE OR REPLACE PROCEDURE PROJECTGROUPS (
PROJECTID IN WORKSON.P#%TYPE
) IS
BEGIN
FOR I IN (
SELECT PROJECT_NAME,
PTITLE,
LISTAGG(EMP_NAME,
',') WITHIN GROUP(
ORDER BY EMP_NAME
) AS EMP_NAMES
FROM (
SELECT P.P# PROJECT_NAME,
P.PTITLE,
E.EMPLOYEE.NAME EMP_NAME,
ROW_NUMBER() OVER(
PARTITION BY P.P#
ORDER BY E.NAME
) AS RN
FROM PROJECT P
JOIN WORKSON W
ON W.P# = P.P#
JOIN EMPLOYEE E
ON E.E# = W.E#
WHERE P.P# = PROJECTID
)
WHERE RN <= 20
GROUP BY PROJECT_NAME,
PTITLE
) LOOP
DBMS_OUTPUT.PUT_LINE(I.PROJECT_NAME
|| ' '
|| I.PTITLE
|| ' : '
|| I.EMP_NAMES);
END LOOP;
END PROJECTGROUPS;
Also, your query is not actually outer joined as you have used the condition in the WHERE clause.
left outer join WorksOn On Employee.E# = WorksOn.E# -- you want outer join
where WorksOn.P# = projected -- but the outer join is converted to inner join

Oracle:if left join table return no rows then change to another left join table

I have two query as below and both of them work well. Now I need to combine them and if the first select find rows then no need to run the second select
1.
select f.*, o.org_sn, ttt.name linkman_name, ttt.phone phone_num
from td_archive_feedback f
left join TD_SM_ORG o
on f.recv_org_id = o.org_id
left join (--if this select returns no row , then change.if find matching rows then don't change
select wm_concat(linkman_name) name,
wm_concat(phone_num) phone,
org_id
from (select linkman_name, phone_num, LINK_ORG_ID, org_id
from TD_SM_LINKMAN
where STATE = '2'
and (LINK_ORG_ID = #link_org_id)) t
group by org_id) ttt
on ttt.org_id = o.org_id
--
left join td_sm_dict_item di
on o.org_level = di.item_id
where f.businessid = #businiessid
select f.*, o.org_sn, ttt.name linkman_name, ttt.phone phone_num
from td_archive_feedback f
left join TD_SM_ORG o
on f.recv_org_id = o.org_id
left join (--if the first left join return no rows ,then change to this
select wm_concat(linkman_name) name,
wm_concat(phone_num) phone,
t.org_id
from (
select linkman_name, phone_num, LINK_ORG_ID, org_id
from TD_SM_LINKMAN
where STATE = '2'
and (LINK_ORG_ID is null or LINK_ORG_ID = '')) t
group by t.org_id) ttt
on ttt.org_id = o.org_id
--
left join td_sm_dict_item di
on o.org_level = di.item_id
where f.businessid = #businessid;
Just like I remarked, if
select wm_concat(linkman_name) name,.... where STATE = '2'
and (LINK_ORG_ID = #link_org_id)) t
... returns no rows,
I want to change this to:
select wm_concat(linkman_name) name,.... where STATE = '2' and (LINK_ORG_ID is null or LINK_ORG_ID = '')) t.
Please help me, thanks.
Use Or condition:
select f.*, o.org_sn, ttt.name linkman_name, ttt.phone phone_num
from td_archive_feedback f
left join TD_SM_ORG o
on f.recv_org_id = o.org_id
left join (--if this select returns no row , then change
select wm_concat(linkman_name) name,
wm_concat(phone_num) phone,
org_id
from (select linkman_name, phone_num, LINK_ORG_ID, org_id
from TD_SM_LINKMAN
where STATE = '2'
and (
(LINK_ORG_ID = #link_org_id) or
(LINK_ORG_ID is null or LINK_ORG_ID = '')
) t
group by org_id) ttt
on ttt.org_id = o.org_id
--
left join td_sm_dict_item di
on o.org_level = di.item_id
where f.businessid = #businiessid

How can I convert this SQL query to Laravel 5.4?

select cu.storage_location,max(current_6kg)opbal6kg,max(current_13kg)opbal13kg, max(current_burner)opbalBurners,max(current_grill)opbalGrills, max(current_50kg)opbal50kg,max(Loaded6KG)in_6kg,max(Loaded13KG)in_13kg,max(Loaded50KG)in_50kg, max(burners)in_burners,max(grills)in_grills ,sum(Unsold6KG)Unsold6KG,sum(Unsold13KG)Unsold13KG,sum(Unsold50KG)Unsold50KG, sum(out_6kg)out_6kg,sum(out_13kg)out_13kg,sum(out_50kg)out_50kg, sum(out_burners)out_burners,sum(out_grills)out_grills from tbl_current_stocks_filled cu left outer join( select * from tblStockTransfer where cast(DateTransferred as date)= cast(getdate() as date)) t on t.destination =cu.storage_location left outer join ( select assignedLocation, sum (op_bal_6KG+Loaded6KG)out_6kg,sum(op_bal_13KG+Loaded13KG)out_13kg, sum(op_bal_50KG+Loaded50KG)out_50kg ,sum(op_bal_grills+Grills)out_grills, sum(op_bal_burners+Burners)out_burners from tblTruckLoading l inner join tblUsers u on l.UserID=u.UserID where cast(l.DateLoaded as date)= cast(getdate() as date) group by assignedLocation ) y on y.assignedLocation=cu.storage_location left outer join ( select Unsold6KG,Unsold13KG,Unsold50KG,UnsoldBurners,UnsoldGrills, assignedLocation from tblTruckUnLoading l left outer join tblUsers u on u.UserID=l.UserID where cast(l.DateOffLoaded as date)= cast(getdate() as date) )x on x.assignedLocation=cu.storage_location
group by cu.storage_location
You can use the DB::raw method found in the documentation here: https://laravel.com/docs/5.4/queries#raw-expressions
$results = DB::select( DB::raw("select cu.storage_location,max(current_6kg)opbal6kg,max(current_13kg)opbal13kg, max(current_burner)opbalBurners,max(current_grill)opbalGrills, max(current_50kg)opbal50kg,max(Loaded6KG)in_6kg,max(Loaded13KG)in_13kg,max(Loaded50KG)in_50kg, max(burners)in_burners,max(grills)in_grills ,sum(Unsold6KG)Unsold6KG,sum(Unsold13KG)Unsold13KG,sum(Unsold50KG)Unsold50KG, sum(out_6kg)out_6kg,sum(out_13kg)out_13kg,sum(out_50kg)out_50kg, sum(out_burners)out_burners,sum(out_grills)out_grills from tbl_current_stocks_filled cu left outer join( select * from tblStockTransfer where cast(DateTransferred as date)= cast(getdate() as date)) t on t.destination =cu.storage_location left outer join ( select assignedLocation, sum (op_bal_6KG+Loaded6KG)out_6kg,sum(op_bal_13KG+Loaded13KG)out_13kg, sum(op_bal_50KG+Loaded50KG)out_50kg ,sum(op_bal_grills+Grills)out_grills, sum(op_bal_burners+Burners)out_burners from tblTruckLoading l inner join tblUsers u on l.UserID=u.UserID where cast(l.DateLoaded as date)= cast(getdate() as date) group by assignedLocation ) y on y.assignedLocation=cu.storage_location left outer join ( select Unsold6KG,Unsold13KG,Unsold50KG,UnsoldBurners,UnsoldGrills, assignedLocation from tblTruckUnLoading l left outer join tblUsers u on u.UserID=l.UserID where cast(l.DateOffLoaded as date)= cast(getdate() as date) )x on x.assignedLocation=cu.storage_location group by cu.storage_location") );

Subquery with Select statement works in 12C but not on 11g

Select
c.id AS case_id,
c.id AS case_number,
tt.description as Target_Type,
coalesce(
v_vendors.vendor_number,
vma.org_code,
TO_CHAR(sm.staff_member_id),
la.org_code,
oe.other_fns_number,
TO_CHAR(oe.other_id),
TO_CHAR(c_clients.client_id)
) as Target_Identifier,
coalesce(
v_vendors.vendor_name,
vma.name,
s_wic_users.username,
la.name,
oe.other_name,
UPPER(
c_clients.last_name || ', ' || c_clients.first_name
)
) as Target_Name,
c.date_opened AS Open_Date,
c.date_closed AS Close_Date,
t.target_type_id,
t.target_id,
s.description AS Status,
case when aIosm.last_name is null then '' else UPPER(
aIosm.last_name || ', ' || aIosm.first_name
) end Investigator,
case when aSosm.last_name is null then '' else UPPER(
aSosm.last_name || ', ' || aSosm.first_name
) end Supervisor,
c.Notes AS Supervisor_Comments,
aI.Date_Assigned as Assign_Date,
----subquery starts
(
select
lat.description
from
investigation_actions_taken iat
join investig_lu_action_type lat on iat.action_type_id = lat.id
where
iat.investigation_case_id = c.id
and iat.is_deleted <> 'T'
order by
iat.date_assessed desc,
iat.date_created desc OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
) AS Last_Action
from
v_investigation_cases c
join investigation_target t on c.target_id = t.target_id
join v_lu_inv_status s on (
case when date_closed <= TRUNC(sysdate) then 2 else case when date_opened > TRUNC(sysdate) then 2 else 1 end end
) = s.status_id
join investigation_target_type tt on t.target_type_id = tt.target_type_id
---left join starts
left join investigation_case_assignment aI on c.id = aI.investigation_case_id
and aI.date_roll_off is null
and aI.assignment_type = 'I'
left join o_staff_members aIosm on aI.staff_member_id = aIosm.staff_member_id
left join investigation_case_assignment Super on c.id = Super.investigation_case_id
and Super.date_roll_off is null
and Super.assignment_type = 'S'
left join o_staff_members aSosm on Super.staff_member_id = aSosm.staff_member_id
-----left join starts
left join v_vendors on t.vendor_id = v_vendors.id
left join o_organizational_units vma on t.vendor_management_area_id = vma.seq_id
left join c_clients on t.client_id = c_clients.client_id
left join o_staff_members sm on t.user_id = sm.staff_member_id
left join s_wic_users on sm.staff_member_id = s_wic_users.sm_staff_member_id
left join investigation_other_entity oe on t.non_wic_vendor_id = oe.other_id
left join o_organizational_units la on t.local_agency_id = la.seq_id
---end of the query
Here's an article about what you can achieve in Oracle 12c with the OFFEST FETCH based on Kaushik Nayak.
http://www.dba-oracle.com/t_offset_fet_first_rows_only.htm
I hope it can help you to convert your original query to 11g. Good luck.

CROSS APPLY too slow for running total - TSQL

Please see my code below as it is running too slowly with the CROSS APPLY.
How can I remove the CROSS APPLY and add something else that will run faster?
Please note I am using SQL Server 2008 R2.
;WITH MyCTE AS
(
SELECT
R.NetWinCURRENCYValue AS NetWin
,dD.[Date] AS TheDay
FROM
dimPlayer AS P
JOIN
dbo.factRevenue AS R ON P.playerKey = R.playerKey
JOIN
dbo.vw_Date AS dD ON Dd.dateKey = R.dateKey
WHERE
P.CustomerID = 12345)
SELECT
A.TheDay AS [Date]
,ISNULL(A.NetWin, 0) AS NetWin
,rt.runningTotal AS CumulativeNetWin
FROM MyCTE AS A
CROSS APPLY (SELECT SUM(NetWin) AS runningTotal
FROM MyCTE WHERE TheDay <= A.TheDay) AS rt
ORDER BY A.TheDay
CREATE TABLE #temp (NetWin money, TheDay datetime)
insert into #temp
SELECT
R.NetWinCURRENCYValue AS NetWin
,dD.[Date] AS TheDay
FROM
dimPlayer AS P
JOIN
dbo.factRevenue AS R ON P.playerKey = R.playerKey
JOIN
dbo.vw_Date AS dD ON Dd.dateKey = R.dateKey
WHERE
P.CustomerID = 12345;
SELECT
A.TheDay AS [Date]
,ISNULL(A.NetWin, 0) AS NetWin
,SUM(B.NetWin) AS CumulativeNetWin
FROM #temp AS A
JOIN #temp AS B
ON A.TheDay >= B.TheDay
GROUP BY A.TheDay, ISNULL(A.NetWin, 0);
Here https://stackoverflow.com/a/13744550/613130 it's suggested to use recursive CTE.
;WITH MyCTE AS
(
SELECT
R.NetWinCURRENCYValue AS NetWin
,dD.[Date] AS TheDay
,ROW_NUMBER() OVER (ORDER BY dD.[Date]) AS RN
FROM dimPlayer AS P
JOIN dbo.factRevenue AS R ON P.playerKey = R.playerKey
JOIN dbo.vw_Date AS dD ON Dd.dateKey = R.dateKey
WHERE P.CustomerID = 12345
)
, MyCTERec AS
(
SELECT C.TheDay AS [Date]
,ISNULL(C.NetWin, 0) AS NetWin
,ISNULL(C.NetWin, 0) AS CumulativeNetWin
,C.RN
FROM MyCTE AS C
WHERE C.RN = 1
UNION ALL
SELECT C.TheDay AS [Date]
,ISNULL(C.NetWin, 0) AS NetWin
,P.CumulativeNetWin + ISNULL(C.NetWin, 0) AS CumulativeNetWin
,C.RN
FROM MyCTERec P
INNER JOIN MyCTE AS C ON C.RN = P.RN + 1
)
SELECT *
FROM MyCTERec
ORDER BY RN
OPTION (MAXRECURSION 0)
Note that this query will work if you have 1 record == 1 day! If you have multiple records in a day, the results will be different from the other query.
As I said here, if you want really fast calculation, put it into temporary table with sequential primary key and then calculate rolling total:
create table #Temp (
ID bigint identity(1, 1) primary key,
[Date] date,
NetWin decimal(29, 10)
)
insert into #Temp ([Date], NetWin)
select
dD.[Date],
sum(R.NetWinCURRENCYValue) as NetWin,
from dbo.dimPlayer as P
inner join dbo.factRevenue as R on P.playerKey = R.playerKey
inner join dbo.vw_Date as dD on Dd.dateKey = R.dateKey
where P.CustomerID = 12345
group by dD.[Date]
order by dD.[Date]
;with cte as (
select T.ID, T.[Date], T.NetWin, T.NetWin as CumulativeNetWin
from #Temp as T
where T.ID = 1
union all
select T.ID, T.[Date], T.NetWin, T.NetWin + C.CumulativeNetWin as CumulativeNetWin
from cte as C
inner join #Temp as T on T.ID = C.ID + 1
)
select C.[Date], C.NetWin, C.CumulativeNetWin
from cte as C
order by C.[Date]
I assume that you could have duplicates dates in the input, but don't want duplicates in the output, so I grouped data before puting it into the table.

Resources