Invalid Identifier -- SQL compilation error with multiple joins - snowflake-cloud-data-platform

I am trying to run query with Multiple joins.
EX -
SELECT * FROM SC1.TABLE1 IHF
JOIN SC1.TABL2 IAF ON IHF.COL1 = IAF.COL1
AND IAF.COL2 = 'N'
AND IAF.COL2 = 2001
AND IHF.COL1 = 'N'
AND IAF.COL2 = 2001
LEFT OUTER JOIN SC1.TABL3 AID ON IAF.COL1 = AID.COL1
AND AID.COL2 = 2001
LEFT OUTER JOIN (
SELECT COL1 AS ID,UPPER(TRIM(COL2)) FROM SC1.TABLE4
WHERE COL3 = 'ADV' AND COL4 = 2001) AEM
ON COALESCE((UPPER(TRIM(AID.COL3))),'') = UPPER(TRIM(AEM.COL3));
But after running 2nd left join it gives SQL compilation error -invalid identifier c.col1
First left join works but 2nd gives error

so in Snowflake, using some made up data in the CTE it runs just for me.
with table1(col1) as (
select * from values
(1),(2),(3)
), table2(col2) as (
select * from values
(1),(2),(3)
), table3(col1, col2) as (
select * from values
(1,''),(2,'not empty'),(3,'')
)
Select
a.col1,
b.col2,
c.col1
from table1 a
join table2 b
ON a.col1 = b.col2
left outer join (
select col1 from table3 where col2=''
) c
on a.col1 = c.col1;
gives me the result:
COL1
COL2
COL1_2
1
1
1
2
2
null
3
3
3
can you provide better example data that triggers your problem, to scope your question better to which system (t-sql, snowflake) is giving you the problem, and again with what data.
Code update:
So two problems I can see inside AEM you output two columns, the second has no alias/label, And in the ON clause AEM.col3 correctly does not exist. Nether you need to select that also so it can be used OR the second select was meant to be aliased to that.
but if I rewrite your SQL:
SELECT
ihf.*,
iaf.*,
aid.*,
aem.id,
aem.clean_col2
FROM sc1.table1 AS ihf
JOIN sc1.tabl2 AS iaf
ON ihf.col1 = iaf.col1
AND iaf.col2 = 'N'
AND iaf.col2 = 2001
AND ihf.col1 = 'N'
AND iaf.col2 = 2001
LEFT OUTER JOIN SC1.TABL3 AID
ON IAF.COL1 = AID.COL1
AND AID.COL2 = 2001
LEFT OUTER JOIN (
SELECT
COL1 AS ID,
UPPER(TRIM(COL2)) as clean_col2,
col3
FROM SC1.TABLE4
WHERE COL3 = 'ADV' AND COL4 = 2001
) AEM
ON COALESCE((UPPER(TRIM(AID.COL3))),'') = UPPER(TRIM(AEM.COL3));
You can see I gave a name to the cleaned up col2 of AEM, but I would suggest you should move those "clean-ups" used in the ON into the related selects, so it can be a equi-join. But the join ON of IAF is broken as it stands:
JOIN sc1.tabl2 AS iaf
ON ihf.col1 = iaf.col1
AND iaf.col2 = 'N'
AND iaf.col2 = 2001
AND ihf.col1 = 'N'
AND iaf.col2 = 2001
how can iaf.col2 = 'N' AND iaf.col2 = 2001 at which point I would guess that was a typo, and it should read
JOIN sc1.tabl2 AS iaf
ON ihf.col1 = iaf.col1
AND iaf.col1= 'N'
AND iaf.col2 = 2001
AND ihf.col1 = 'N'
AND iaf.col2 = 2001
but that feels somewhat redundant, but at least Snowflake should push the filters to the correct spot.
but really I would tend to write the code as, for performance reasons:
SELECT
ihf.*,
iaf.*,
aid.*, -- mimus clean_col3
aem.id,
aem.clean_col2
FROM sc1.table1 AS ihf
JOIN sc1.tabl2 AS iaf
ON ihf.col1 = iaf.col1
AND iaf.col1 = 'N'
AND iaf.col2 = 2001
AND ihf.col1 = 'N'
AND iaf.col2 = 2001
LEFT OUTER JOIN (
SELECT *,
COALESCE((UPPER(TRIM(col3))),'') AS clean_col3
FROM sc1.tabl3
) AS aid
ON iaf.col1 = aid.col1
AND aid.col2 = 2001
LEFT OUTER JOIN (
SELECT
col1 AS id,
UPPER(TRIM(col2)) AS clean_col2,
UPPER(TRIM(aem.col3)) AS clean_col3
FROM sc1.table4
WHERE col3 = 'ADV' AND col4 = 2001
) AEM
ON AID.clean_col3 = AEM.clean_col3;

Related

How to use inner join and left join for two tables in same query using T-SQL

Given two tables:
tblBase - database table (code_no, empid)
#type_temp is a temporary user defined table which will come from vb.net frontend (code_no, name)
Firstly I need to get code_no which are in #type_temp and not in tblBase.
Query:
select
t.code_no, 'Non-existing' as Remark
from
#type_temp t
left join
tblBase b on t.code_no = b.code_no
where
b.code_no is null
Next I need to get all code_no that have empid = 1.
Query :
select
t.code_no, 'Existing' as Remark
from
#type_temp t
inner join
tblBase b on t.code_no = b.code_no
where
b.empid = 1
I need to use both these queries together.
Currently I'm using union to club the two.
select
t.code_no, 'Non-existing' as Remark
from
#type_temp t
left join
tblBase b on t.code_no = b.code_no
where
b.code_no is null
union
select
t.code_no, 'Existing' as Remark
from
#type_temp t
inner join
tblBase b on t.code_no = b.code_no
where
b.empid = 1
I do not want union here. Any other alternative possible?
Does this work for you?
SELECT type_temp.code_no
, CASE WHEN tblBase.code_no IS NULL THEN 'Non-existing' ELSE 'Existing' END AS Remark
FROM #type_temp AS type_temp
LEFT
JOIN tblBase
ON tblBase.code_no = type_temp.code_no
WHERE tblBase.empid = 1
OR tblBase.code_no IS NULL
;
An even better option than #gvee's answer, is to put the conditions into the ON clause
SELECT
type_temp.code_no,
CASE WHEN tblBase.code_no IS NULL THEN 'Non-existing' ELSE 'Existing' END AS Remark
FROM #type_temp AS type_temp
LEFT JOIN tblBase ON tblBase.code_no = type_temp.code_no
AND tblBase.empid = 1;
This is likely to be more performant, as the join is pre-filtered.

Microsoft SQL - Update while Select

is there any way to update while selecting data to avoid extra accesses?
We select 2500 datasets and need to set a value to 1 while we do this, current solution WOULD be to do it in the profile, 1 by 1, which leads to 2500 accesses to the database...
You can turn your SELECT query into an UPDATE easily.
I don't know what your SELECT looks like, but you could follow this pattern:
SELECT
c.column1
, b.column2
, a.column3
FROM Table1 a
INNER JOIN Table2 b
ON a.PK = b.FK
INNER JOIN Table3 c
ON b.PK = c.FK
WHERE a.column4 = 'a'
AND b.column4 = 'x'
to
UPDATE a
SET column3 = 1
, column4 = 'b'
FROM Table1 a
INNER JOIN Table2 b
ON a.PK = b.FK
INNER JOIN Table3 c
ON b.PK = c.FK
WHERE a.column4 = 'a'
AND b.column4 = 'x'
This will do 1 database access and do all the work.

insert query with subqueries

I am trying to insert some values (CIID and AID) taken from another tables, but as not an expert, I couldn't manage to do it.
Insert query :
INSERT INTO INST_ACTIVE_ACTIONS act
(act.CIID, act.AID, act.STEPNUM, act.CREATEDATE)
VALUES
(CIID , ,0,GETDATE())
The CIID Query is :
SELECT C.CIID FROM INST_COURSE C
LEFT JOIN INST_ACTIVE_ACTIONS AA ON (AA.CIID = C.CIID)
LEFT JOIN INST_TASKS T ON (T.CIID = C.CIID)
LEFT JOIN SYS_SCH_ACTION SCH ON (SCH.CIID = C.CIID)
LEFT JOIN SYS_SUB_STACK SUB ON (SUB.RETURN_CIID=C.CIID)
WHERE C.COMPLETED IS NULL AND AA.AID IS NULL AND T.AID IS NULL AND SCH.AID IS NULL AND SUB.RETURN_AID IS NULL
AID Query is :
SELECT TOP 1 ca.AID
FROM INST_COMPLETE_ACTIONS CA
INNER JOIN TMPL_ACT_MASTER TAM ON CA.AID=TAM.AID
WHERE ca.CIID =c.CIID ORDER BY TSTAMP DESC
act.CIID = C.CIID = ca.CIID and CA.AID = act.AID
Edited :
the last query is
INSERT INTO INST_ACTIVE_ACTIONS (CIID,AID,stepnum,CREATEDATE
)
VALUES
(
(SELECT c.CIID
FROM INST_COURSE C
LEFT JOIN INST_ACTIVE_ACTIONS AA
ON (
aa.CIID = c.CIID)
LEFT JOIN INST_TASKS T
ON (
t.CIID = c.CIID)
LEFT JOIN SYS_SCH_ACTION SCH
ON (
sch.CIID = c.CIID)
LEFT JOIN sys_sub_stack SUB
ON (
sub.RETURN_CIID = c.CIID)
WHERE c.completed IS NULL
AND aa.AID IS NULL
AND t.AID IS NULL
AND sch.AID IS NULL
AND sub.return_AID IS NULL),
(
SELECT TOP 1
ca.AID
FROM INST_COMPLETE_ACTIONS CA
INNER JOIN tmpl_act_master TAM
ON ca.AID=tam.AID
ORDER BY tstamp DESC
),
0,
Getdate() )
but i get an error as
Msg 512, Level 16, State 1, Line 1 Subquery returned more than 1
value. This is not permitted when the subquery follows =, !=, <, <= ,
, >= or when the subquery is used as an expression. The statement has been terminated.
Just condensed though its real busy if you ask me.
INSERT INTO INST_ACTIVE_ACTIONS
(CIID, AID, STEPNUM, CREATEDATE)
--OUTPUT INSERTED.* --if you want to see what was inserted uncomment this
(SELECT C.CIID,
(SELECT TOP 1 CA.AID
FROM INST_COMPLETE_ACTIONS CA
INNER JOIN TMPL_ACT_MASTER TAM ON CA.AID=TAM.AID
WHERE CA.CIID =C.CIID ORDER BY TSTAMP DESC)
, 0,GETDATE())
FROM INST_COURSE C
LEFT JOIN INST_ACTIVE_ACTIONS AA ON (AA.CIID = C.CIID)
LEFT JOIN INST_TASKS T ON (T.CIID = C.CIID)
LEFT JOIN SYS_SCH_ACTION SCH ON (SCH.CIID = C.CIID)
LEFT JOIN SYS_SUB_STACK SUB ON (SUB.RETURN_CIID=C.CIID)
WHERE C.COMPLETED IS NULL AND AA.AID IS NULL AND T.AID IS NULL AND SCH.AID IS NULL AND SUB.RETURN_AID IS NULL)
Revised. tested, and working on my end. I still think if you have control on these tables you might look into the concept of Normalizing your database tables.
You can always perform something like this, and use as many sub queries as needed. Make sure that the types are matching on both sides.
Insert into table1 (value1, value2) Select val1,val2 from table2 ...
edit
INSERT INTO INST_ACTIVE_ACTIONS act (act.CIID, act.AID,
act.STEPNUM, act.CREATEDATE) Select
(SELECT C.CIID FROM INST_COURSE C LEFT JOIN INST_ACTIVE_ACTIONS AA ON (AA.CIID = C.CIID) LEFT JOIN INST_TASKS T ON
(T.CIID = C.CIID) LEFT JOIN SYS_SCH_ACTION SCH ON (SCH.CIID = C.CIID)
LEFT JOIN SYS_SUB_STACK SUB ON (SUB.RETURN_CIID=C.CIID) WHERE
C.COMPLETED IS NULL AND AA.AID IS NULL AND T.AID IS NULL AND SCH.AID
IS NULL AND SUB.RETURN_AID IS NULL), (SELECT TOP 1 ca.AID FROM
INST_COMPLETE_ACTIONS CA INNER JOIN TMPL_ACT_MASTER TAM ON
CA.AID=TAM.AID WHERE ca.CIID =c.CIID ORDER BY TSTAMP DESC act.CIID
= C.CIID = ca.CIID and CA.AID ),0,GETDATE()

How to use multiple values in between clause

Hi all is there any way that i can use multiple values in between clause as
column_name between 0 and 100 or 200 and 300 like this
Any help would be appreciated
here is my query SELECT CASE WHEN ISNUMERIC(value_text) = 1 THEN CAST(value_text AS INT) ELSE -1 END) between 0 and 100
i just want to append multiple values in between clause
This is full query
SELECT ROW_NUMBER() OVER
(
order by Vendor_PrimaryInfo.Vendor_ID asc
)AS RowNumber
, Unit_Table.Unit_title, Vendor_Base_Price.Base_Price, Vendor_Base_Price.showprice, Category_Table.Title, Vendor_Registration.Business_Name,
Vendor_PrimaryInfo.Street_Address, Vendor_PrimaryInfo.Locality, Vendor_PrimaryInfo.Nearest_Landmark, Vendor_PrimaryInfo.City, Vendor_PrimaryInfo.State,
Vendor_PrimaryInfo.Country, Vendor_PrimaryInfo.PostalCode, Vendor_PrimaryInfo.Latitude, Vendor_PrimaryInfo.Longitude, Vendor_PrimaryInfo.ImageUrl,
Vendor_PrimaryInfo.ContactNo, Vendor_PrimaryInfo.Email,Vendor_PrimaryInfo.Vendor_ID
FROM Unit_Table INNER JOIN
Vendor_Base_Price ON Unit_Table.Unit_ID = Vendor_Base_Price.Unit_ID INNER JOIN
Vendor_PrimaryInfo ON Vendor_Base_Price.Vendor_ID = Vendor_PrimaryInfo.Vendor_ID INNER JOIN
Vendor_Registration ON Vendor_Base_Price.Vendor_ID = Vendor_Registration.Vendor_ID AND
Vendor_PrimaryInfo.Vendor_ID = Vendor_Registration.Vendor_ID INNER JOIN
Category_Table ON Vendor_Registration.Category_ID = Category_Table.Category_ID
LEFT JOIN
Vendor_Value_Table ON Vendor_Registration.Vendor_ID = Vendor_Value_Table.Vendor_ID LEFT JOIN
Feature_Table ON Vendor_Value_Table.Feature_ID = Feature_Table.Feature_ID
where Vendor_Registration.Category_ID=5 and Vendor_PrimaryInfo.City='City'
AND(
value_text in('Dhol Wala$Shahnai Wala')
or
(SELECT CASE WHEN ISNUMERIC(value_text) = 1 THEN CAST(value_text AS INT) ELSE -1 END) between 0 and 100
)
You can do this using AND/OR logic
value_text NOT LIKE '%[^0-9]%' and
(
value_text between 0 and 100
Or
value_text between 101 and 200
)
If you don't want to repeat the column name then frame the range in table valued constructor and join with your table
SELECT Row_number()
OVER (
ORDER BY Vendor_PrimaryInfo.Vendor_ID ASC )AS RowNumber,
Unit_Table.Unit_title,
Vendor_Base_Price.Base_Price,
Vendor_Base_Price.showprice,
Category_Table.Title,
Vendor_Registration.Business_Name,
Vendor_PrimaryInfo.Street_Address,
Vendor_PrimaryInfo.Locality,
Vendor_PrimaryInfo.Nearest_Landmark,
Vendor_PrimaryInfo.City,
Vendor_PrimaryInfo.State,
Vendor_PrimaryInfo.Country,
Vendor_PrimaryInfo.PostalCode,
Vendor_PrimaryInfo.Latitude,
Vendor_PrimaryInfo.Longitude,
Vendor_PrimaryInfo.ImageUrl,
Vendor_PrimaryInfo.ContactNo,
Vendor_PrimaryInfo.Email,
Vendor_PrimaryInfo.Vendor_ID
FROM Unit_Table
INNER JOIN Vendor_Base_Price
ON Unit_Table.Unit_ID = Vendor_Base_Price.Unit_ID
INNER JOIN Vendor_PrimaryInfo
ON Vendor_Base_Price.Vendor_ID = Vendor_PrimaryInfo.Vendor_ID
INNER JOIN Vendor_Registration
ON Vendor_Base_Price.Vendor_ID = Vendor_Registration.Vendor_ID
AND Vendor_PrimaryInfo.Vendor_ID = Vendor_Registration.Vendor_ID
INNER JOIN Category_Table
ON Vendor_Registration.Category_ID = Category_Table.Category_ID
LEFT JOIN Vendor_Value_Table
ON Vendor_Registration.Vendor_ID = Vendor_Value_Table.Vendor_ID
LEFT JOIN Feature_Table
ON Vendor_Value_Table.Feature_ID = Feature_Table.Feature_ID
JOIN (VALUES (0, 100),
(101, 200),
(201, 300)) tc (st, ed)
ON Try_cast(value_text AS INT) BETWEEN st AND ed
OR Try_cast(value_text AS VARCHAR(100)) = 'Dhol Wala$Shahnai Wala'
WHERE Vendor_Registration.Category_ID = 5
AND Vendor_PrimaryInfo.City = 'City'
Note : You have stored two different information's in a single column which causes lot of pain when you want to extract the data like this. Consider changing your table structure

multiple count in a sql query

i need a report from a database where i need the final result like
Number of Male, Number of Female, showing against city and finally against State.
I started off with something like.
SELECT p.StateName, d.CityName,
count(api.Gender) as Gender
FROM dbo.Application_Personal_information as api INNER JOIN
dbo.state as p ON api.State = p.ID INNER JOIN
dbo.City as d ON api.City= d.ID
group by p.StateName, d.CityName
when i do this
SELECT p.StateName, d.CityName,
count(api.Gender = 'Male) as Male,
count(api.Gender = 'Female) as Female,
FROM dbo.Application_Personal_information as api INNER JOIN
dbo.state as p ON api.State = p.ID INNER JOIN
dbo.City as d ON api.City= d.ID
group by p.StateName, d.CityName
it give's me error.
incorrect syntax near =.
i also tried with select statement
COUNT(select api.Gender from api where api.Gender ='Male') as Male,
But it is also not working.
...
Any idea?
SELECT
p.StateName, d.CityName,
sum(case when Gender ='Male' then 1 else 0 end ) as Male_count,
sum(case when Gender ='Female' then 1 else 0 end ) as Female_count
FROM
dbo.Application_Personal_information as api INNER JOIN
dbo.state as p ON api.State = p.ID INNER JOIN
dbo.City as d ON api.City= d.ID
group by
p.StateName, d.CityName
You could try the PIVOT function if you are using SQL Server 2005 or later:
WITH CTE AS
( SELECT p.StateName,
d.CityName,
api.Gender
FROM dbo.Application_Personal_information as api
INNER JOIN dbo.state as p
ON api.State = p.ID
INNER JOIN dbo.City as d
ON api.City= d.ID
)
SELECT *
FROM CTE
PIVOT
( COUNT(Gender)
FOR Gender IN ([Male], [Female])
) pvt

Resources