I'm trying to create a materialized view in Oracle 11.1, which apparently does not support nested selects in a materialized view (Why this is, I haven't been able to figure out).. Is there a way to write this query to work as a materialized view? Thanks!
CREATE MATERIALIZED VIEW MV_Area90DayReport
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
select
T.TASKID,
V.PROJECTID,
V.VERSIONID,
T.GOLDDATE,
P.BUSINESSLAUNCHDATE,
V.NAME as ProjectName,
T.NAME as TaskName,
T.COURSECODE,
DT.NAME as DeliveryMethod,
T.DELIVERABLELENGTHHOUR,
T.DELIVERABLELENGTHMINUTE,
V.PRIORITY,
(SELECT MIN(STARTDATE) FROM TPM_TRAININGPLAN WHERE PROJECTID=V.PROJECTID AND TRAININGPLANTYPE='prescribed') as TrainingDeliveryDate,
(SELECT wm_concat(WORKGROUPID) FROM TPM_PROJECTWORKGROUPS WHERE PROJECTID=V.PROJECTID GROUP BY PROJECTID) as Workgroups,
from TPM_TASK T
inner join TPM_PROJECTVERSION V ON (V.PROJECTID = T.PROJECTID AND V.VERSIONID = T.VERSIONID)
inner join TPM_PROJECT P ON (P.PROJECTID = T.PROJECTID)
inner join TPM_DOCUMENTTYPE DT ON (DT.DOCUMENTTYPEID = T.DOCUMENTTYPEID);
The error I get is:
>[Error] Script lines: 1-25 -------------------------
ORA-22818: subquery expressions not allowed here
Script line 20, statement line 20, column 115
I believe this is a limitation (that was raised as a bug sometime back), documented here on the Oracle site - http://download.oracle.com/docs/cd/B12037_01/server.101/b10736/basicmv.htm#sthref431
To resolve, you should use JOINS rather than subqueries.
Try the following query:
select
T.TASKID,
V.PROJECTID,
V.VERSIONID,
T.GOLDDATE,
P.BUSINESSLAUNCHDATE,
V.NAME as ProjectName,
T.NAME as TaskName,
T.COURSECODE,
DT.NAME as DeliveryMethod,
T.DELIVERABLELENGTHHOUR,
T.DELIVERABLELENGTHMINUTE,
V.PRIORITY,
TP.TrainingDeliveryDate,
WG.Workgroups,
from TPM_TASK T
inner join TPM_PROJECTVERSION V ON (V.PROJECTID = T.PROJECTID AND V.VERSIONID = T.VERSIONID)
inner join TPM_PROJECT P ON (P.PROJECTID = T.PROJECTID)
inner join TPM_DOCUMENTTYPE DT ON (DT.DOCUMENTTYPEID = T.DOCUMENTTYPEID)
left join (
SELECT PROJECTID, MIN(STARTDATE) as TrainingDeliveryDate
FROM TPM_TRAININGPLAN
WHERE TRAININGPLANTYPE='prescribed'
GROUP BY PROJECTID
) TP on TP.PROJECTID=V.PROJECTID
left join (
SELECT PROJECTID, wm_concat(WORKGROUPID) as Workgroups
FROM TPM_PROJECTWORKGROUPS
GROUP BY PROJECTID
) WG on WG.PROJECTID=V.PROJECTID
Related
EDIT:
The result supposed to be like this:
desired result
I have this query:
SELECT DISTINCT mitarbeiter.mitarbnr, mitarbeiter.login, mitarbeiter.name1, mitarbeiter.name2
FROM vertragspos
left join vertrag_ek_vk_zuord ON vertragspos.id = vertrag_ek_vk_zuord.ek_vertragspos_id
left join mitarbeiter ON vertrag_ek_vk_zuord.anlage_mitarbnr = mitarbeiter.mitarbnr
left join vertragskopf ON vertragskopf.id = vertragspos.vertrag_id
left join
(
SELECT wkurse.*, fremdwaehrung.wsymbol
FROM wkurse
INNER join
(
SELECT lfdnr, Max(tag) AS maxTag
FROM wkurse
WHERE tag < SYSDATE
GROUP BY lfdnr
) t1
ON wkurse.lfdnr = t1.lfdnr AND wkurse.Tag = t1.maxTag
INNER JOIN fremdwaehrung ON wkurse.lfdnr = fremdwaehrung.lfdnr
) wkurse ON vertragskopf.blfdwaehrung = wkurse.lfdnr
left join
(
SELECT vertrag_ID, Sum (preis) preis, Sum (menge) menge, Sum (preis * menge / Decode (vertragskopf.zahlintervall, 1,1,2,2,3,3,4,6,5,12,1) / wkurse.kurs) vertragswert
FROM vertragspos
GROUP BY vertrag_ID
) s ON vertragskopf.id = s.vertrag_id
But I always get an error on line 21 Pos 145:
ORA-00904 WKURSE.KURS invalid identifier
The WKURSE table is supposed be joined already above, but why do I still get error?
How can I do join with all these tables?
I need to join all these tables:
Mitarbeiter, Vertragspos, vertrag_ek_vk_zuord, wkurse, fremdwaehrung, vertragskopf.
What is the right syntax? I'm using SQL Tool 1,8 b38
Thank you.
Because LEFT JOIN is executed on entire dataset, and not in row-by-row manner. So there's no wkurse.kurs available in the execution context of subquery. Since you join that tables, you can place the calculation in the top-most select statement.
EDIT:
After you edited the statement, it became clear where does vertragskopf.zahlintervall came from. But I don't know where are you going to use calculated vertragswert (now it is absent in the query), so I've put it in the result. As I'm not a SQL parser and have no idea of your tables, so I cannot check the code, but calculation now can be resolved (all the values are available in calculation context).
SELECT DISTINCT mitarbeiter.mitarbnr, mitarbeiter.login, mitarbeiter.name1, mitarbeiter.name2, s.amount / Decode (vertragskopf.zahlintervall, 1,1,2,2,3,3,4,6,5,12,1) / wkurse.kurs) vertragswert
FROM vertragspos
left join vertrag_ek_vk_zuord ON vertragspos.id = vertrag_ek_vk_zuord.ek_vertragspos_id
left join mitarbeiter ON vertrag_ek_vk_zuord.anlage_mitarbnr = mitarbeiter.mitarbnr
left join vertragskopf ON vertragskopf.id = vertragspos.vertrag_id
left join (
SELECT wkurse.*, fremdwaehrung.wsymbol
FROM wkurse
INNER join (
SELECT lfdnr, Max(tag) AS maxTag
FROM wkurse
WHERE tag < SYSDATE
GROUP BY lfdnr
) t1
ON wkurse.lfdnr = t1.lfdnr AND wkurse.Tag = t1.maxTag
INNER JOIN fremdwaehrung ON wkurse.lfdnr = fremdwaehrung.lfdnr
) wkurse ON vertragskopf.blfdwaehrung = wkurse.lfdnr
left join (
SELECT vertrag_ID, Sum (preis) preis, Sum (menge) menge, Sum (preis * menge) as amount
FROM vertragspos
GROUP BY vertrag_ID
) s ON vertragskopf.id = s.vertrag_id
Rewriting the code using WITH clause makes it much clearer than select from select.
Also get the rate on last day before today in oracle is as simple as
select wkurse.lfdnr
, max(wkurse.kurs) keep (dense_rank first order by wkurse.tag desc) as rate
from wkurse
where tag < sysdate
group by wkurse.lfdnr
One option is a lateral join:
left join lateral
(SELECT vertrag_ID, Sum(preis) as preis, Sum(menge) as menge,
Sum (preis * menge / Decode (vertragskopf.zahlintervall, 1,1,2,2,3,3,4,6,5,12,1) / wkurse.kurs) vertragswert
FROM vertragspos
GROUP BY vertrag_ID
) s
ON vertragskopf.id = s.vertrag_id
Anybody know why this isn't working? I'm getting: ERROR: syntax error at or near "most_recent"
with most_recent as (SELECT MAX(public."Master_playlist".updated_at)
FROM public."Master_playlist")
SELECT * from public."Playlist"
JOIN public."Master_playlist_playlist" on public."Playlist".id = public."Master_playlist_playlist".playlist_id
JOIN public."Master_playlist" on public."Master_playlist_playlist".master_playlist_id = public."Master_playlist".id
WHERE public."Master_playlist".updated_at = most_recent;
Supposed to be getting the most recent date from Master_playlist and then using that to select a Master_playlist to join the inner query with
Thanks! HM
The with clause creates a derived table, which you need select from, using a join or a subquery. You also need to alias the column so you can refer to it afterwards, as in:
with most_recent as (
SELECT MAX(updated_at) max_updated_at
FROM public."Master_playlist"
)
SELECT *
from public."Playlist"
JOIN public."Master_playlist_playlist"
on public."Playlist".id = public."Master_playlist_playlist".playlist_id
JOIN public."Master_playlist"
on public."Master_playlist_playlist".master_playlist_id = public."Master_playlist".id
WHERE public."Master_playlist".updated_at = (SELECT max_updated_at FROM most_recent)
But here, it looks like it is simpler to use a row-limiting query:
select ...
from (
select *
from public."Master_playlist"
order by updated_at desc
limit 1
) mp
inner join public."Master_playlist_playlist" mpp
on mpp.master_playlist_id = mp.id
inner join public."Playlist" p
on p.id = mpp.playlist_id
Ok, so here is example code for view. Second part with select RT.RoleID[...] seems clear to me. That's the part that's going to be displayed when the query will be run to use the view. first part is unclear though.
First two lines are standard as i understand, then goes the whole with section. Could someone explain it to me? Never seen with "something" as (select) formula
CREATE VIEW [dbo].[sviw_System_MyPermissions_CurrentDomain]
AS
WITH MyDomainRoles AS (
SELECT RM.Domain, RM.RoleID
FROM stbl_System_RolesMembersDomains AS RM WITH (NOLOCK)
WHERE RM.Domain = (SELECT CurrentDomain FROM stbl_System_Users WITH (NOLOCK) WHERE Login = SUSER_SNAME())
AND RM.Login = SUSER_SNAME()
)
SELECT RT.RoleID, RT.TableName, DR.Domain, RT.GrantUpdate, RT.GrantInsert, RT.GrantDelete
FROM stbl_System_RolesTables AS RT WITH (NOLOCK)
JOIN MyDomainRoles AS DR ON RT.RoleID = DR.RoleID
GO
It is called Common Table Expresion and basically your view is the same as:
CREATE VIEW vSalesStaffQuickStats
AS
SELECT E.EmployeeID,
EmployeeOrders = OS.NumberOfOrders,
EmployeeLastOrderDate = OS.MostRecentOrderDate,
E.ManagerID,
ManagerOrders = OM.NumberOfOrders,
ManagerLastOrderDate = OM.MostRecentOrderDate
FROM HumanResources.Employee AS E
INNER JOIN (
SELECT SalesPersonID, COUNT(*) NumberOfOrders
, MAX(OrderDate) MostRecentOrderDate
FROM Sales.SalesOrderHeader
GROUP BY SalesPersonID
) AS OS
ON E.EmployeeID = OS.SalesPersonID
LEFT OUTER JOIN (
SELECT SalesPersonID, COUNT(*) NumberOfOrders
, MAX(OrderDate) MostRecentOrderDate
FROM Sales.SalesOrderHeader
GROUP BY SalesPersonID
) AS OM
ON E.ManagerID = OM.SalesPersonID
As you see you could easily exchange it with subquery. But in your case you need do it twice (with CTE you do it only once).
EDIT:
With new query after update:
CREATE VIEW [dbo].[sviw_System_MyPermissions_CurrentDomain]
AS
SELECT RT.RoleID, RT.TableName, DR.Domain, RT.GrantUpdate, RT.GrantInsert, RT.GrantDelete
FROM stbl_System_RolesTables AS RT WITH (NOLOCK)
JOIN (
SELECT RM.Domain, RM.RoleID
FROM stbl_System_RolesMembersDomains AS RM WITH (NOLOCK)
WHERE RM.Domain = (SELECT CurrentDomain FROM stbl_System_Users WITH (NOLOCK) WHERE Login = SUSER_SNAME())
AND RM.Login = SUSER_SNAME()
) AS DR ON RT.RoleID = DR.RoleID
The WITH keyword just refers to Common Table Expression ( read more here: https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql ) Basically everything within the WITH statement could be considered as externalized subquery which result set is then used in the main query.
i.e.:
WITH MyDomainRoles AS (
--- sub-query Start
SELECT RM.Domain, RM.RoleID
FROM stbl_System_RolesMembersDomains AS RM WITH (NOLOCK)
WHERE RM.Domain = (SELECT CurrentDomain FROM stbl_System_Users WITH (NOLOCK) WHERE Login = SUSER_SNAME())
AND RM.Login = SUSER_SNAME()
--- sub-query End
)
... and the result set from the sub-query above is held within the CTE named MyDomainRoles. Then you can refer to MyDomainRoles as to a table. Makes things simpler to read and cleaner to write.
Since this CTE is so simple, you could easily re-write it as follows but it just does not look as neat:
WITH MyDomainRoles AS (
)
SELECT RT.RoleID, RT.TableName, DR.Domain, RT.GrantUpdate, RT.GrantInsert, RT.GrantDelete
FROM stbl_System_RolesTables AS RT WITH (NOLOCK)
JOIN (
SELECT RM.Domain, RM.RoleID
FROM stbl_System_RolesMembersDomains AS RM WITH (NOLOCK)
WHERE RM.Domain = (SELECT CurrentDomain FROM stbl_System_Users WITH (NOLOCK) WHERE Login = SUSER_SNAME())
AND RM.Login = SUSER_SNAME()
) AS DR ON RT.RoleID = DR.RoleID
I have a SQL query
Select
temp1.domainname,
temp1.employeeid,
temp1.alletec_plantcode,
temp1.name,
temp1.alletec_customerengineer1name,
temp1.alletec_cityname,
temp1.alletec_regionname,
temp1.alletec_ce1name,
temp1.alletec_casecalltypename,
count(temp1.alletec_ce1name) as TOTALMIFASSIGN ,
(select count( MIF.alletec_ce1name) from temp1 where temp1.alletec_casecalltypename='aa') as CMMIFASSIGN
from (
Select
User1.domainname,
User1.employeeid,
User1.alletec_plantcode,
BU.name,
MIF.alletec_customerengineer1name,
MIF.alletec_cityname,
MIF.alletec_regionname,
MIF.alletec_ce1name,
Incident.alletec_casecalltypename
From
FilteredSystemUser As User1 Inner Join FilteredBusinessUnit As BU ON User1.businessunitid=BU.businessunitid
Inner join Filteredalletec_mif As MIF ON MIF.alletec_ce1=User1.systemuserid
Inner join FilteredIncident As Incident On Incident.alletec_serialnomif=MIF.alletec_mifid
where MIF.alletec_ce1name='Amit Chauhan' AND MIF.alletec_cityname='Gurgaon' and MIF.alletec_regionname='North' and Incident.statecodename='Resolved'
group by User1.domainname,
User1.employeeid,
User1.alletec_plantcode,
BU.name,
MIF.alletec_cityname,
MIF.alletec_regionname,
MIF.alletec_ce1name,
MIF.alletec_customerengineer1name,
Incident.alletec_casecalltypename
) As temp1
group by
temp1.domainname,
temp1.employeeid,
temp1.alletec_plantcode,
temp1.name,
temp1.alletec_customerengineer1name,
temp1.alletec_cityname,
temp1.alletec_regionname,
temp1.alletec_ce1name,
temp1.alletec_casecalltypename
The particular query above showing the temp1 as Invalid Object in the count query as i am require to place further filtration on it. Cant we use the above query in Aggregate function. Kindly suggest the an alternative to it.
Thanks.
The problem seem to be that the table alias temp1 isn't available when the query processor tries to resolve it. One solution that should work would be to wrap the query in a common table expression (cte). I believe this will work.
Try this:
;with temp1 (
domainname, employeeid,
alletec_plantcode, name,
alletec_customerengineer1name,
alletec_cityname, alletec_regionname,
alletec_ce1name, alletec_casecalltypename
)
as (
Select
User1.domainname,
User1.employeeid,
User1.alletec_plantcode,
BU.name,
MIF.alletec_customerengineer1name,
MIF.alletec_cityname,
MIF.alletec_regionname,
MIF.alletec_ce1name,
Incident.alletec_casecalltypename
From
FilteredSystemUser As User1 Inner Join FilteredBusinessUnit As BU ON User1.businessunitid=BU.businessunitid
Inner join Filteredalletec_mif As MIF ON MIF.alletec_ce1=User1.systemuserid
Inner join FilteredIncident As Incident On Incident.alletec_serialnomif=MIF.alletec_mifid
where MIF.alletec_ce1name='Amit Chauhan' AND MIF.alletec_cityname='Gurgaon' and MIF.alletec_regionname='North' and Incident.statecodename='Resolved'
group by User1.domainname,
User1.employeeid,
User1.alletec_plantcode,
BU.name,
MIF.alletec_cityname,
MIF.alletec_regionname,
MIF.alletec_ce1name,
MIF.alletec_customerengineer1name,
Incident.alletec_casecalltypename
)
Select
temp1.domainname,
temp1.employeeid,
temp1.alletec_plantcode,
temp1.name,
temp1.alletec_customerengineer1name,
temp1.alletec_cityname,
temp1.alletec_regionname,
temp1.alletec_ce1name,
temp1.alletec_casecalltypename,
(select count(temp1.alletec_ce1name) from temp1) as TOTALMIFASSIGN
from temp1
I have this strange error in SQL Server 2005 where I take a working query, add the UNION keyword below it and then copy the query again. In my opinion, this should always be working, but it is not. I get the message 'Incorrect syntax near the keyword 'union'.
What could create this problem ?
To be more specific, here is the complete query :
select distinct deliveries.id, orders.id, 20 + sum(orders.mass1) as allowed_duration
from features_resources
inner join features on features.id = featureid
inner join orders on orders.id = features_resources.resourceid
inner join orderinformations on orders.id = orderinformations.orderid
inner join deliveries on orderinformations.deliveryid = deliveries.id
where features.name = 'O_FRAIS'
and (deliveries.ID IN
(SELECT ID
FROM dbo.DeliveriesInExportedSchedule))
group by deliveries.id, features.name ,orders.id order by deliveries.id
union
select distinct deliveries.id, orders.id, 20 + sum(orders.mass1) as allowed_duration
from features_resources
inner join features on features.id = featureid
inner join orders on orders.id = features_resources.resourceid
inner join orderinformations on orders.id = orderinformations.orderid
inner join deliveries on orderinformations.deliveryid = deliveries.id
where features.name = 'O_FRAIS'
and (deliveries.ID IN
(SELECT ID
FROM dbo.DeliveriesInExportedSchedule))
group by deliveries.id, features.name ,orders.id order by deliveries.id
I have tried to reproduce the error on a smaller query, by starting from a simple query and adding features one by one (inner join, nested queryes, group by, sum,....) but failed to reproduce the error again.
Any idea ?
It is actually the order by deliveries.id in the top half that causes the problem.
The order by needs to apply to the whole query.
Example Syntax
SELECT v1.number
FROM master.dbo.spt_values v1
WHERE v1.number > 2000
UNION
SELECT v2.number
FROM master.dbo.spt_values v2
WHERE v2.number < 10
ORDER BY v1.number
Try putting the individual SELECTs in parentheses:
(SELECT ... )
UNION
(SELECT ... )
The way you have it now, the second WHERE and GROUP BY clauses are ambiguous - should that apply to the SELECT, or to the UNION? I don't have any way to tell, and neither has your DB server.