SQL ORA-00904: invalid identifier - join issue - sql

have a problem with my query:
select Sources.dataset.name setName, x.element_name Commodity_Is, y.element_name Provider_Is
from meta.object_meta_v x, meta.object_meta_v y
join dw.load_set2_curve on x.object_id = dw.load_set2_curve.curve_id
join Sources.dataset on Sources.dataset.id = dw.load_set2_curve.load_set_id
where dw.load_set2_curve.curve_id in (
select max(curve_id) sample_curve_id from dw.load_Set2_curve
group by load_set_id
)
and (meta.object_meta_v.attribute = 'Provider' or meta.object_meta_v.attribute = 'Commodity');
the error is on the line:
join dw.load_set2_curve on x.object_id = dw.load_set2_curve.curve_id
I know why, because, according to this article 'https://stackoverflow.com/questions/10500048/invalid-identifier-on-oracle-inner-join' - "Looks like you cannot refer to an outer table alias in the join condition of the inner query." Unfortunately, I don't know how to find a workaround as I am looking for two different records (Commodity_is and Provider_is) from the same table in my query (with aliases 'x' and 'y').
Do you have any hints?

Your problem is that you are not using the table aliases in the SELECT, ON and WHERE clauses and are trying to refer to identifiers as schema.table.column and, in some cases that is ambiguous and you need to use table_alias.column.
Additionally, you are trying to mix legacy comma joins with ANSI joins (which does work but the comma joins need to be last, not first, so its easier just to use ANSI joins all the way through):
select ds.name setName,
x.element_name Commodity_Is,
y.element_name Provider_Is
from meta.object_meta_v x
CROSS JOIN meta.object_meta_v y
INNER JOIN dw.load_set2_curve lsc
ON x.object_id = lsc.curve_id
INNER JOIN Sources.dataset ds
ON ds.id = lsc.load_set_id
where lsc.curve_id in (
select max(curve_id) sample_curve_id
from dw.load_Set2_curve
group by load_set_id
)
and ( x.attribute = 'Provider'
or y.attribute = 'Commodity');
Which, for the sample data:
CREATE TABLE meta.object_meta_v (object_id, element_name, attribute) AS
SELECT 1, 'A', 'Provider' FROM DUAL UNION ALL
SELECT 2, 'B', 'Commodity' FROM DUAL;
CREATE TABLE dw.load_set2_curve (curve_id, load_set_id) AS
SELECT 1, 100 FROM DUAL UNION ALL
SELECT 2, 200 FROM DUAL;
CREATE TABLE sources.dataset (id, name) AS
SELECT 100, 'DS1' FROM DUAL UNION ALL
SELECT 200, 'DS2' FROM DUAL;
Outputs:
SETNAME
COMMODITY_IS
PROVIDER_IS
DS1
A
B
DS1
A
A
DS2
B
B
db<>fiddle here

Related

Unable to convert this legacy SQL into Standard SQL in Google BigQuery

I am not able to validate this legacy sql into standard bigquery sql as I don't know what else is required to change here(This query fails during validation if I choose standard SQL as big query dialect):
SELECT
lineitem.*,
proposal_lineitem.*,
porder.*,
company.*,
product.*,
proposal.*,
trafficker.name,
salesperson.name,
rate_card.*
FROM (
SELECT
*
FROM
dfp_data.dfp_order_lineitem
WHERE
DATE(end_datetime) >= DATE(DATE_ADD(CURRENT_TIMESTAMP(), -1, 'YEAR'))
OR end_datetime IS NULL ) lineitem
JOIN (
SELECT
*
FROM
dfp_data.dfp_order) porder
ON
lineitem.order_id = porder.id
LEFT JOIN (
SELECT
*
FROM
adpoint_data.dfp_proposal_lineitem) proposal_lineitem
ON
lineitem.id = proposal_lineitem.dfp_lineitem_id
JOIN (
SELECT
*
FROM
dfp_data.dfp_company) company
ON
porder.advertiser_id = company.id
LEFT JOIN (
SELECT
*
FROM
adpoint_data.dfp_product) product
ON
proposal_lineitem.product_id=product.id
LEFT JOIN (
SELECT
*
FROM
adpoint_data.dfp_proposal) proposal
ON
proposal_lineitem.proposal_id=proposal.id
LEFT JOIN (
SELECT
*
FROM
adpoint_data.dfp_rate_card) rate_card
ON
proposal_lineitem.ratecard_id=rate_card.id
LEFT JOIN (
SELECT
id,
name
FROM
dfp_data.dfp_user) trafficker
ON
porder.trafficker_id =trafficker.id
LEFT JOIN (
SELECT
id,
name
FROM
dfp_data.dfp_user) salesperson
ON
porder. salesperson_id =salesperson.id
Most likely the error you are getting is something like below
Duplicate column names in the result are not supported. Found duplicate(s): name
Legacy SQL adjust trafficker.name and salesperson.name in your SELECT statement into respectively trafficker_name and salesperson_name thus effectively eliminating column names duplication
Standard SQL behaves differently and treat both those columns as named name thus producing duplication case. To avoid it - you just need to provide aliases as in example below
SELECT
lineitem.*,
proposal_lineitem.*,
porder.*,
company.*,
product.*,
proposal.*,
trafficker.name AS trafficker_name,
salesperson.name AS salesperson_name,
rate_card.*
FROM ( ...
You can easily check above explained using below simplified/dummy queries
#legacySQL
SELECT
porder.*,
trafficker.name,
salesperson.name
FROM (
SELECT 1 order_id, 'abc' order_name, 1 trafficker_id, 2 salesperson_id
) porder
LEFT JOIN (SELECT 1 id, 'trafficker' name) trafficker
ON porder.trafficker_id =trafficker.id
LEFT JOIN (SELECT 2 id, 'salesperson' name ) salesperson
ON porder. salesperson_id =salesperson.id
and
#standardSQL
SELECT
porder.*,
trafficker.name AS trafficker_name,
salesperson.name AS salesperson_name
FROM (
SELECT 1 order_id, 'abc' order_name, 1 trafficker_id, 2 salesperson_id
) porder
LEFT JOIN (SELECT 1 id, 'trafficker' name) trafficker
ON porder.trafficker_id =trafficker.id
LEFT JOIN (SELECT 2 id, 'salesperson' name ) salesperson
ON porder. salesperson_id =salesperson.id
Note: if you have more duplicate names - you need to alias all of them too

Oracle to T-SQL conversion. How can I make this work?

Having trouble converting Oracle syntax to T-SQL. Trying to convert the following statement:
SELECT ORIG.*
,V.COUNTRY_COMMON_NAME
FROM
(SELECT O.*
,LC.LOCAL_COUNCIL
,LC.REGIONAL_COUNCIL
FROM ES_W_ORG_DIM_INIT O
LEFT JOIN ES_W_ORG_DIM_INIT CNTR ON (O.RSC_CNTR_ORG_ID = CNTR.ORG_ID)
LEFT JOIN ES_W_LCL_CNCL_BASE LC ON (TO_CHAR(O.STK_DIST_UNIT_NUMBER) =
TRIM(LC.UNITNUMBER))
WHERE O.ORG_TYPE_ID IN (7,8)
UNION
SELECT O.*
,LC.LOCAL_COUNCIL
,LC.REGIONAL_COUNCIL
FROM ES_W_ORG_DIM_INIT O
LEFT JOIN ES_W_ORG_DIM_INIT CNTR ON (O.RSC_CNTR_ORG_ID = CNTR.ORG_ID)
LEFT JOIN ES_W_LCL_CNCL_BASE LC ON (TO_CHAR(O.UNIT_NUMBER) =
TRIM(LC.UNITNUMBER))
WHERE O.ORG_TYPE_ID IN (5,6)
UNION
SELECT O.*
,NULL AS LOCAL_COUNTCIL
,NULL AS REGIONAL_COUNCIL
FROM ES_W_ORG_DIM_INIT O
WHERE O.ORG_TYPE_ID IN (60,61)
) ORIG
LEFT JOIN DW_ERSDB_ORG_ADDR_VW V ON (ORIG.ORG_ID = V.ORG_ID AND
V.ORG_ADDRESS_TYPE_ID = 1)
Attempted conversion:
WITH ORIG AS(
SELECT O.*
,LC.LOCAL_COUNCIL
,LC.REGIONAL_COUNCIL
FROM DSS_ERS_STAGE.ES_ORG_DIM O
LEFT JOIN DSS_ERS_STAGE.ES_ORG_DIM CNTR ON (O.RSC_CNTR_ORG_ID = CNTR.ORG_ID)
LEFT JOIN DSS_ERS_STAGE.ES_W_LCL_CNCL_BASE LC ON (CONVERT(VARCHAR,
O.STK_DIST_UNIT_NUMBER) = RTRIM(LTRIM(LC.UNITNUMBER)))
WHERE O.ORG_TYPE_ID IN (7,8)
UNION
(SELECT O.*
,LC.LOCAL_COUNCIL
,LC.REGIONAL_COUNCIL
FROM DSS_ERS_STAGE.ES_ORG_DIM O
LEFT JOIN DSS_ERS_STAGE.ES_ORG_DIM CNTR ON (O.RSC_CNTR_ORG_ID = CNTR.ORG_ID)
LEFT JOIN DSS_ERS_STAGE.ES_W_LCL_CNCL_BASE LC ON (CONVERT(VARCHAR,
O.UNIT_NUMBER) = RTRIM(LTRIM(LC.UNITNUMBER)))
WHERE O.ORG_TYPE_ID IN (5,6)
UNION
SELECT O.*
,NULL AS LOCAL_COUNCIL
,NULL AS REGIONAL_COUNCIL
FROM DSS_ERS_STAGE.ES_ORG_DIM O
WHERE O.ORG_TYPE_ID IN (60,61)
))
SELECT ORIG.*, V.COUNTRY_COMMON_NAME
FROM ORIG
LEFT JOIN DSS_ERS_STAGE.DW_ERSDB_ORG_ADDR_VW V ON (ORIG.ORG_ID = V.ORG_ID
AND
V.ORG_ADDRESS_TYPE_ID = 1)
*Just a note that the schemas specified are required in the target database
SQL Server error:
Msg 8156, Level 16, State 1, Line 1
The column 'LOCAL_COUNCIL' was specified multiple times for 'ORIG'.
Any ideas on how I can engineer this to make it work in SQL Server?
Jamie mentioned this in a comment but I'll try to explain in a bit more detail. For purposes of illustration, suppose I have the following two very simple tables.
create table CouncilA (LOCAL_COUNCIL int);
create table CouncilB (LOCAL_COUNCIL int);
insert CouncilA values (1);
insert CouncilB values (1);
SQL Server does allow you to query a result set that has non-unique column names. For instance, the following is legal:
select *
from
CouncilA A
inner join CouncilB B on A.LOCAL_COUNCIL = B.LOCAL_COUNCIL;
It produces the following result set:
LOCAL_COUNCIL LOCAL_COUNCIL
1 1
However, the documentation for common table expressions explicitly states:
Duplicate names within a single CTE definition are not allowed.
So if I try to wrap my earlier query like this, as you've done in your attempted conversion:
with CTE as
(
select *
from
CouncilA A
inner join CouncilB B on A.LOCAL_COUNCIL = B.LOCAL_COUNCIL
)
select * from CTE;
Then I get the error message that you're seeing:
Msg 8156, Level 16, State 1, Line 7
The column 'LOCAL_COUNCIL' was specified multiple times for 'CTE'.
Incidentally, the same is true for a sub-SELECT:
select * from
(
select *
from
CouncilA A
inner join CouncilB B on A.LOCAL_COUNCIL = B.LOCAL_COUNCIL
) X;
Result:
Msg 8156, Level 16, State 1, Line 13
The column 'LOCAL_COUNCIL' was specified multiple times for 'X'.
The error message you see refers to ORIG, which is the name of your CTE, so the definition of that CTE has multiple columns called LOCAL_COUNCIL, which presumably means that your ES_W_ORG_DIM_INIT table has a column called LOCAL_COUNCIL. Make sure your column names are unique within your CTE and you should be okay.

SQL sub query not working with group by clause

I am using SQL Server 2012. Can anyone tell me where i am going wrong ?
SELECT
avg ( tbl.FirstBillComplete )
FROM
( select l.MONTH, a.OverallScore, (a.FirstBillComplete), ( a.EmailComplete)
from tbl_T1 a join calls.dbo.c1_LP l on a.QID = l.QID
union
select l.MONTH, a.OverallScore, (a.FirstBillComplete), ( a.EmailComplete)
from tbl_2 a join calls.dbo.C3_LP l on a.QID = l.QID
union ALL
select l.MONTH, a.OverallScore, (a.FirstBillComplete), ( a.EmailComplete)
from tbl_3 a join c2 l on a.QID = l.QID
) As tbl
GROUP BY tbl.MONTH
The error I get is :
No column was specified for column 7 of 'tbl'.
No column was specified for column 8 of 'tbl'
You need to specify a column name for column 7 and 8 of tbl: use
'' AS MyColumn7,
For example.

sql parameterised cte query

I have a query like the following
select *
from (
select *
from callTableFunction(#paramPrev)
.....< a whole load of other joins, wheres , etc >........
) prevValues
full join
(
select *
from callTableFunction(#paramCurr)
.....< a whole load of other joins, wheres , etc >........
) currValues on prevValues.Field1 = currValues.Field1
....<other joins with the same subselect as the above two with different parameters passed in
where ........
group by ....
The following subselect is common to all the subselects in the query bar the #param to the table function.
select *
from callTableFunction(#param)
.....< a whole load of other joins, wheres , etc >........
One option is for me to convert this into a function and call the function, but i dont like this as I may be changing the
subselect query quite often for.....or I am wondering if there is an alternative using CTE
like
with sometable(#param1) as
(
select *
from callTableFunction(#param)
.....< a whole load of other joins, wheres , etc >........
)
select
sometable(#paramPrev) prevValues
full join sometable(#currPrev) currValues on prevValues.Field1 = currValues.Field1
where ........
group by ....
Is there any syntax like this or technique I can use like this.
This is in SQL Server 2008 R2
Thanks.
What you're trying to do is not supported syntax - CTE's cannot be parameterised in this way.
See books online - http://msdn.microsoft.com/en-us/library/ms175972.aspx.
(values in brackets after a CTE name are an optional list of output column names)
If there are only two parameter values (paramPrev and currPrev), you might be able to make the code a little easier to read by splitting them into two CTEs - something like this:
with prevCTE as (
select *
from callTableFunction(#paramPrev)
.....< a whole load of other joins, wheres , etc
........ )
,curCTE as (
select *
from callTableFunction(#currPrev)
.....< a whole load of other joins, wheres , etc
........ ),
select
prevCTE prevValues
full join curCTE currValues on
prevValues.Field1 = currValues.Field1 where
........ group by
....
You should be able to wrap the subqueries up as parameterized inline table-valued functions, and then use them with an OUTER JOIN:
CREATE FUNCTION wrapped_subquery(#param int) -- assuming it's an int type, change if necessary...
RETURNS TABLE
RETURN
SELECT * FROM callTableFunction(#param)
.....< a whole load of other joins, wheres , etc ........
GO
SELECT *
FROM
wrapped_subquery(#paramPrev) prevValues
FULL OUTER JOIN wrapped_subquery(#currPrev) currValues ON prevValues.Field1 = currValues.Field1
WHERE ........
GROUP BY ....
After failing to assign scalar variables before with, i finally got a working solution using a stored procedure and a temp table:
create proc hours_absent(#wid nvarchar(30), #start date, #end date)
as
with T1 as(
select c from t
),
T2 as(
select c from T1
)
select c from T2
order by 1, 2
OPTION(MAXRECURSION 365)
Calling the stored procedure:
if object_id('tempdb..#t') is not null drop table #t
create table #t([month] date, hours float)
insert into #t exec hours_absent '9001', '2014-01-01', '2015-01-01'
select * from #t
There may be some differences between my example and what you want depending on how your subsequent ON statements are formulated. Since you didn't specify, I assumed that all the subsequent joins were against the first table.
In my example I used literals rather than #prev,#current but you can easily substitute variables in place of literals to achieve what you want.
-- Standin function for your table function to create working example.
CREATE FUNCTION TestMe(
#parm int)
RETURNS TABLE
AS
RETURN
(SELECT #parm AS N, 'a' AS V UNION ALL
SELECT #parm + 1, 'b' UNION ALL
SELECT #parm + 2, 'c' UNION ALL
SELECT #parm + 2, 'd' UNION ALL
SELECT #parm + 3, 'e');
go
-- This calls TestMe first with 2 then 4 then 6... (what you don't want)
-- Compare these results with those below
SELECT t1.N AS AN, t1.V as AV,
t2.N AS BN, t2.V as BV,
t3.N AS CN, t3.V as CV
FROM TestMe(2)AS t1
FULL JOIN TestMe(4)AS t2 ON t1.N = t2.N
FULL JOIN TestMe(6)AS t3 ON t1.N = t3.N;
-- Put your #vars in place of 2,4,6 adding select statements as needed
WITH params
AS (SELECT 2 AS p UNION ALL
SELECT 4 AS p UNION ALL
SELECT 6 AS p)
-- This CTE encapsulates the call to TestMe (and any other joins)
,AllData
AS (SELECT *
FROM params AS p
OUTER APPLY TestMe(p.p)) -- See! only coded once
-- Add any other necessary joins here
-- Select needs to deal with all the columns with identical names
SELECT d1.N AS AN, d1.V as AV,
d2.N AS BN, d2.V as BV,
d3.N AS CN, d3.V as CV
-- d1 gets limited to values where p = 2 in the where clause below
FROM AllData AS d1
-- Outer joins require the ANDs to restrict row multiplication
FULL JOIN AllData AS d2 ON d1.N = d2.N
AND d1.p = 2 AND d2.p = 4
FULL JOIN AllData AS d3 ON d1.N = d3.N
AND d1.p = 2 AND d2.p = 4 AND d3.p = 6
-- Since AllData actually contains all the rows we must limit the results
WHERE(d1.p = 2 OR d1.p IS NULL)
AND (d2.p = 4 OR d2.p IS NULL)
AND (d3.p = 6 OR d3.p IS NULL);
What you want to do is akin to a pivot and so the complexity of the needed query is similar to creating a pivot result without using the pivot statement.
Were you to use Pivot, duplicate rows (such as I included in this example) would be aggreagted. This is also a solution for doing a pivot where aggregation is unwanted.

Adding the results of multiple SQL selects?

I have three SQL selects, the results of which I need to add together. Two of the three use fairly complex joins.
select sum(field_one) from t_a join t_b on (t_a.bid = t_b.id) where t_b.user_id=:id
select sum(field_two) from t_c join t_d on (t_c.did = t_d.id) where t_d.user_id=:id
select sum(field_three) from t_e where t_e.user_id=:id
What I need is the sum of all three values. sum(field_one)+sum(field_two)+sum(field_three). Is there anyway to do this in a single statement?
You could UNION ALL them.
Do not use UNION, since it omits duplicate values (5+5+5 would result in 5).
Select Sum(s)
From
(
Select Sum(field_one) As s ...
Union All
Select Sum(field_two) ...
Union All
Select Sum(field_three) ...
) x
You can do this without using Union like this
Sample Query
select( (select 15) + (select 10) + (select 20))
Your Query
select
(
(select sum(field_one) from t_a join t_b on (t_a.bid = t_b.id) where t_b.user_id=:id) +
(select sum(field_two) from t_c join t_d on (t_c.did = t_d.id) where t_d.user_id=:id) +
(select sum(field_three) from t_e where t_e.user_id=:id)
)
You can use a UNION and a subselect to do that:
select sum(`sum`) FROM
(
select sum(field_one) as `sum` from t_a join t_b on (t_a.bid = t_b.id) where t_b.user_id=:id
UNION ALL
select sum(field_two) from t_c join t_d on (t_c.did = t_d.id) where t_d.user_id=:id
UNION ALL
select sum(field_three) from t_e where t_e.user_id=:id
) as x;
Edit: Updated my answer to use UNION ALL, as suggested by Peter Lang.