问题
I have the following SQL which works:
Select TRADING_DWKEY,
M_SM_USER_CODE,
FIRST_TRADE,
'New Footprint' Status,
Null Q4Vol,
CQVol
From (Select A.TRADING_DWKEY||A.RM_SM_USER_CODE,
A.TRADING_DWKEY,
A.RM_SM_USER_CODE,
B.FIRST_TRADE, SUM(A.RISK_AMOUNT_ADJ)/1000000 CQVol
from FACT_TRADE_ROLLUP A,
(SELECT TRADING_DWKEY,
MIN(FIRST_TRADE_DATE) FIRST_TRADE
FROM ACCOUNT_FIRST_LAST_TRADE_DATES
Having MIN(FIRST_TRADE_DATE) >= to_char(trunc((sysdate-1),'Y'),'dd-Mon-yy')
GROUP BY TRADING_DWKEY) B
WHERE A.DATE_KEY>='01-Jan-16' AND
((A.PRODUCT_DWKEY IN ('RT') AND A.Account_Type='Customer') OR
A.PRODUCT_DWKEY IN('OB','BS','MM')) AND
A.Role = 'SM' AND
A.TRADING_DWKEY = B.TRADING_DWKEY
GROUP BY A.TRADING_DWKEY||A.RM_SM_USER_CODE,
A.TRADING_DWKEY,
A.RM_SM_USER_CODE,
B.FIRST_TRADE
HAVING SUM(A.RISK_AMOUNT_ADJ)>=20000000) NewFP;
When I attempt to add a INNER JOIN to the subquery (to pull a name instead of a code), I get an error that A.RM_SM_USER_CODE is not a valid identifier on the line where I write the INNER JOIN. However, I am positive this field exists in the FACT_TRADE_ROLLUP table. I suspect the error has something to do with where I place the INNER JOIN, but cannot figure it.
Here is the fully modified SQL (but I get the error even if I just place the INNER JOIN statement in without actually modifying the columns.
Select TRADING_DWKEY,
RM_SM_NAME,
FIRST_TRADE,
'New Footprint' Status,
Null Q4Vol,
CQVol
From (Select A.TRADING_DWKEY||A.RM_SM_USER_CODE,
A.TRADING_DWKEY,
q.RM_SM_NAME,
B.FIRST_TRADE,
SUM(A.RISK_AMOUNT_ADJ)/1000000 CQVol
from FACT_TRADE_ROLLUP A,
(SELECT TRADING_DWKEY, MIN(FIRST_TRADE_DATE) FIRST_TRADE
FROM ACCOUNT_FIRST_LAST_TRADE_DATES
Having MIN(FIRST_TRADE_DATE)>=to_char(trunc((sysdate-1),'Y'),'dd-Mon-yy')
GROUP BY TRADING_DWKEY) B
--- error thrown on this line, specifying it at the end
INNER JOIN REF_RM_SM_REGION q
on q.RM_SM_USER_CODE = A.RM_SM_USER_CODE
WHERE A.DATE_KEY>='01-Jan-16' AND
((A.PRODUCT_DWKEY IN('RT') AND A.Account_Type='Customer') OR
A.PRODUCT_DWKEY IN('OB','BS','MM')) AND
A.Role = 'SM' AND
A.TRADING_DWKEY = B.TRADING_DWKEY
GROUP BY A.TRADING_DWKEY||A.RM_SM_USER_CODE,
A.TRADING_DWKEY,
q.RM_SM_NAME,
B.FIRST_TRADE
HAVING SUM(A.RISK_AMOUNT_ADJ)>=20000000) NewFP;
回答1:
Without any DDL statements defining the tables it is difficult to test but:
- You are comparing dates using strings - Oracle is probably doing an implicit conversion back to a date using the value of the
NLS_DATE_FORMAT
session parameter (which is hopefullyDD-MON-YY
) but if this ever changes then it will break the query (and the query won't have changed so it will be a pain to debug). Stop using strings as dates and use date literals - i.e.DATE '2016-01-01'
. - You have the first
HAVING
clause before theGROUP BY
clause - swap them around. - You also are mixing a legacy comma join and ANSI join - replace the comma join with an
INNER JOIN
and move the join condition out of theWHERE
clause. - Grouping by
A.TRADING_DWKEY||A.RM_SM_USER_CODE
is inefficient. You already haveA.TRADING_DWKEY
as one of theGROUP BY
terms so don't concatenate the strings just include the other column in theGROUP BY
clause.
Something like:
Select TRADING_DWKEY,
RM_SM_NAME,
FIRST_TRADE,
'New Footprint' Status,
Null Q4Vol,
CQVol
From (
Select A.TRADING_DWKEY,
q.RM_SM_NAME,
B.FIRST_TRADE,
SUM(A.RISK_AMOUNT_ADJ)/1000000 CQVol
from FACT_TRADE_ROLLUP A
INNER JOIN
( SELECT TRADING_DWKEY,
MIN(FIRST_TRADE_DATE) FIRST_TRADE
FROM ACCOUNT_FIRST_LAST_TRADE_DATES
GROUP BY TRADING_DWKEY
HAVING MIN(FIRST_TRADE_DATE)>= trunc(sysdate-1,'Y')
) B
ON ( A.TRADING_DWKEY=B.TRADING_DWKEY )
INNER JOIN REF_RM_SM_REGION q
ON ( q.RM_SM_USER_CODE = A.RM_SM_USER_CODE )
WHERE A.DATE_KEY >= DATE '2016-01-01'
AND ( ( A.PRODUCT_DWKEY IN('RT')
AND A.Account_Type='Customer'
)
OR A.PRODUCT_DWKEY IN('OB','BS','MM')
)
AND A.Role = 'SM'
GROUP BY A.RM_SM_USER_CODE,
A.TRADING_DWKEY,
q.RM_SM_NAME,
B.FIRST_TRADE
HAVING SUM(A.RISK_AMOUNT_ADJ)>=20000000
);
回答2:
Select TRADING_DWKEY, RM_SM_NAME, FIRST_TRADE, 'New Footprint' Status, Null Q4Vol, CQVol
From (
Select
A.TRADING_DWKEY || A.RM_SM_USER_CODE, /* No name. So is this even used? */
A.TRADING_DWKEY,
q.RM_SM_NAME, B.FIRST_TRADE, SUM(A.RISK_AMOUNT_ADJ) / 1000000 CQVol
from FACT_TRADE_ROLLUP A INNER JOIN /* <--- Changed here... */
(
SELECT TRADING_DWKEY, MIN(FIRST_TRADE_DATE) FIRST_TRADE
FROM ACCOUNT_FIRST_LAST_TRADE_DATES
Having MIN(FIRST_TRADE_DATE)>=to_char(trunc((sysdate-1),'Y'),'dd-Mon-yy')
GROUP BY TRADING_DWKEY /* Very odd it ran with this after HAVING */
) B
ON B.TRADING_DWKEY = A.TRADING_DWKEY /* <--- ...and here */
INNER JOIN REF_RM_SM_REGION q on q.RM_SM_USER_CODE = A.RM_SM_USER_CODE
WHERE
A.DATE_KEY>='01-Jan-16'
AND (A.PRODUCT_DWKEY IN('RT') AND A.Account_Type='Customer')
OR A.PRODUCT_DWKEY IN('OB','BS','MM'))
AND A.Role = 'SM'
/* removed line that was here */
GROUP BY
A.TRADING_DWKEY||A.RM_SM_USER_CODE, A.TRADING_DWKEY,
q.RM_SM_NAME, B.FIRST_TRADE
HAVING SUM(A.RISK_AMOUNT_ADJ) > =20000000
) NewFP;
I made a minimal effort to clean it up. Hopefully I didn't break it in the process. As noted it was probably the mixing of two types of join syntax that caused the error.
来源:https://stackoverflow.com/questions/37602127/adding-inner-join-to-query-with-subquery-with-inline-select-statement