SQLite Table alias with period inside parentheses is not found - sql

I am working on a open source ORM, and have ended up with the following generated Statement
SELECT "Task"."id"
,"Task"."title"
,"Task"."projectId"
,"Project"."id" AS "Project.id"
,"Project"."title" AS "Project.title"
,"Project"."userId" AS "Project.UserId"
,"Project.User"."id" AS "Project.User.id"
,"Project.User"."username" AS "Project.User.username"
FROM "Task" AS "Task"
LEFT OUTER JOIN ("Project" AS "Project"
INNER JOIN "User" AS "Project.User" ON "Project"."userId" = "Project.User"."id"
AND "Project.User"."username" = 'test01' ) ON "Task"."projectId" = "project"."id";
which produces the following error
no such column: Project.User.id
Thanks to help from a previous question here I was able to solve it by removing the periods from the alias inside the parentheses
SELECT "Task"."id"
,"Task"."title"
,"Task"."projectId"
,"Project"."id" AS "Project.id"
,"Project"."title" AS "Project.title"
,"Project"."userId" AS "Project.UserId"
,"Project_User"."id" AS "Project.User.id"
,"Project_User"."username" AS "Project.User.username"
FROM "Task" AS "Task"
LEFT OUTER JOIN ("Project" AS "Project"
INNER JOIN "User" AS "Project_User" ON "Project"."userId" = "Project_User"."id"
AND "Project_User"."username" = 'test01' ) ON "Task"."projectId" = "project"."id";
However, since I am working on an ORM the format of the the SQL statement is important and having the periods in those inner aliases would help a lot. I have discovered the following SQL works.
SELECT "Task"."id"
,"Task"."title"
,"Task"."projectId"
,"Project"."id" AS "Project.id"
,"Project"."title" AS "Project.title"
,"Project"."userId" AS "Project.UserId"
,"Project.User"."id" AS "Project.User.id"
,"Project.User"."username" AS "Project.User.username"
FROM "Task" AS "Task"
LEFT OUTER JOIN ("Project" AS "Project"
INNER JOIN "User" AS "Project.User" ON "Project"."userId" = "Project.User"."id"
AND "Project.User"."username" = 'test01' ) "Project.User" ON "Task"."projectId" = "project"."id";
But I do not understand why, or how to scale this to a solution that has many nested joins of a similar nature.
All columns and tables exist with the names given, and no other problems are getting in the way (I assume this mainly based on the failure of the first example and the success of the second.) The initial error only happens in sqlite, all over dialects I have tried seem to not have an issue.
My question is, a, why does the third example work and, b, would it scale to even deeper joins with aliases with periods?

Related

Convert Legacy SQL Outer JOIN *=, =* to ANSI

I need to convert a legacy SQL outer Join to ANSI.
The reason for that being, we're upgrading from a legacy DB instance (2000/5 ?) to SQL 2016.
Legacy SQL query :-
SELECT
--My Data to Select--
FROM counterparty_alias ca1,
counterparty_alias ca2,
counterparty cp,
party p
WHERE cp.code *= ca1.counterparty_code AND
ca1.alias = 'Party1' AND
cp.code *= ca2.counterparty_code AND
ca2.alias = 'Party2' AND
cp.code *= p.child_code AND
cp.category in ('CAT1','CAT2')
Here, Party1 and Party2 Are the party type codes and CAT1 and CAT2 are the category codes. They're just data; I have abstracted it, because the values don't really matter.
Now, when I try to replace the *= with a LEFT OUTER JOIN, I get a huge mismatch on the Data, both in terms of the number of rows, as well as the Data itself.
The query I'm using is this :
What am I doing wrong ?
SELECT
--My Data to Select--
FROM
counterparty cp
LEFT OUTER JOIN counterparty_alias ca1 ON cp.code = ca1.counterparty_code
LEFT OUTER JOIN counterparty_alias ca2 ON cp.code = ca2.counterparty_code
LEFT OUTER JOIN party p ON cp.code = p.child_code
WHERE
ca1.alias = 'Party1' AND
ca2.alias = 'Party2' AND
cp.category in ('CAT1','CAT2')
Clearly , in all the three legacy joins , the cp (counterparty) table is on the Left hand Side of the *=. So that should translate to a LEFT OUTER JOIN WITH all the three tables. However, my solution doesn't seem to to be working
How can I fix this ? What am I doing wrong here ?
Any help would be much appreciated. Thanks in advance :)
EDIT
I also have another query like this :
SELECT
--My Data to Select--
FROM dbo.deal d,
dbo.deal_ccy_option dvco,
dbo.deal_valuation dv,
dbo.strike_modifier sm
WHERE d.deal_id = dvco.deal_id
AND d.deal_id = dv.deal_id
AND dvco.base + dvco.quoted *= sm.ccy_pair
AND d.maturity_date *= sm.expiry_date
In this case, both the dvco and d tables seem to be doing a LEFT OUTER JOIN on the same table sm. How do I proceed about this ?
Maybe join in on the same table and use an alias sm1 and sm2 ?
Or should I use sm as the central table and change the join to RIGHT OUTER JOIN on dvco and d tables ?
I think the problem with your translation is that you are using conditions on the right tables in the where clause instead of in the on clause.
When I tried to translate it, this is the translation I've got:
FROM counterparty cp
LEFT JOIN counterparty_alias ca1 ON cp.code = ca1.counterparty_code
AND ca1.alias = 'Party1'
LEFT JOIN counterparty_alias ca2 ON cp.code *= ca2.counterparty_code
AND ca2.alias = 'Party2'
LEFT JOIN party p ON cp.code = p.child_code
WHERE cp.category in ('CAT1','CAT2')
However, it's hard to know if I'm correct since you didn't provide sample data, desired results, or even a complete query.
If you're doing a conversion, it has been my experience that *= is a RIGHT OUTER JOIN and =* is a LEFT OUTER JOIN in terms of a straight conversion.
I am converting hundreds of stored procs and views now and through testing this is what matches. I run the query as the original first, then make the changes and re-run it with the ANSI compliant code.
The data returned needs to be the same for consistency in our application.
So for your second query I think it would look something like this:
FROM dbo.deal d
INNER JOIN dbo.deal_ccy_option dvco ON d.deal_id = dvco.deal_id
INNER JOIN dbo.deal_valuation dv ON d.deal_id = dv.deal_id
RIGHT OUTER JOIN dbo.strike_modifier sm ON d.maturity_date = sm.expiry_date
AND (dvco.base + dvco.quoted) = sm.ccy_pair
Thanks for the help and sorry for the late post, but I got it to work with a quick hack, using the Query Designer Tool inbuilt in SSMS. It simply refactored all my queries and put in the correct Join, Either Left or Right , and the Where condition as an AND condition on the Join itself, so I was getting the correct data result set for both pre and post, only sometimes the data sorting/ordering was a little off.
I got lost with deadlines and couldnt update with the solution earlier. Thanks again for the help. Hope this helps someone else too !!
Still a little bit unsure though why the ordering/sorting was a little off if the Join condition was the same and the filters as well, because data was a 100 % match.
To get the query Designer to Work , just select your legacy SQL, and
open the Query Designer by pressing Ctrl + Shift + Q or Goto Main Menu
ToolBar => Query => Design Query in Editor.
Thats it. This will refactor your legacy code to new ANSI standards. You wll get the converted query with the new Joins that you can copy and test. Worked 100% of the time for me, except in some cases where the sorting was not matching, which you can check by adding a simple order by clause to both pre and post to compare the data.
For reference, I cross checked with this post :
http://sqlblog.com/blogs/john_paul_cook/archive/2013/03/02/using-the-query-designer-to-convert-non-ansi-joins-to-ansi.aspx

MS Access INNER JOIN/LEFT JOIN problems

I have the following SQL string which tries to combine an INNER JOIN with a LEFT JOIN in the FROM section.
As you can see I use table VIP_APP_VIP_SCENARIO_DETAIL_LE to perform the query. When I use it against this table, Access give me an "Invalid Operation" error.
Interestingly, when I use the EXACT same query using the VIP_APP_VIP_SCENARIO_DETAIL_BUDGET or VIP_APP_VIP_SCENARIO_DETAIL_ACTUALS table, it performs flawlessly.
So why would it work on two tables but not the other? All fields are in all tables and the data types are correct.
As a side note: on the query with the error, if I change the LEFT JOIN to an INNER JOIN, it runs with no problem! I really need a LEFT JOIN though.
SELECT
D.MATERIAL_NUMBER,
D.MATERIAL_DESCRIPTION,
D.PRODUCTION_LOT_SIZE,
D.STANDARDS_NAME,
D.WORK_CENTER,
S.OP_SHORT_TEXT,
S.OPERATION_CODE,
D.LINE_SPEED_UPM,
D.PERCENT_STD,
D.EQUIPMENT_SU,
D.EQUIPMENT_CU,
D.OPERATOR_NUM,
V.COSTING_LOT_SIZE,
V.VOL_TOTAL_ADJ
FROM
([STDS_SCENARIO: TEST] AS D INNER JOIN MASTER_SUMMARY AS S ON
D.MATERIAL_NUMBER = S.MATERIAL_NUMBER AND D.WORK_CENTER = S.WORK_CENTER)
LEFT JOIN
(SELECT ITEM_CODE, COSTING_LOT_SIZE, VOL_TOTAL_ADJ
FROM
VIP_APP_VIP_SCENARIO_DETAIL_LE
WHERE SCENARIO_ID = 16968) AS V ON D.MATERIAL_NUMBER = V.ITEM_CODE
ORDER BY D.MATERIAL_NUMBER, D.STANDARDS_NAME, S.OPERATION_CODE;
tried to mock this up in SQL server with some tables of my own, but the structure seemed to work, this follows the pattern referenced above. (hopefully no syntax errors left here)
SELECT * FROM (
select
D.MATERIAL_NUMBER,
D.MATERIAL_DESCRIPTION,
D.PRODUCTION_LOT_SIZE,
D.STANDARDS_NAME,
D.WORK_CENTER,
S.OP_SHORT_TEXT,
S.OPERATION_CODE,
D.LINE_SPEED_UPM,
D.PERCENT_STD,
D.EQUIPMENT_SU,
D.EQUIPMENT_CU,
D.OPERATOR_NUM
FROM [STDS_SCENARIO: TEST] D
INNER JOIN MASTER_SUMMARY S
ON D.MATERIAL_NUMBER = S.MATERIAL_NUMBER AND D.WORK_CENTER = S.WORK_CENTER) AS J
LEFT JOIN
(SELECT ITEM_CODE, COSTING_LOT_SIZE, VOL_TOTAL_ADJ
FROM
VIP_APP_VIP_SCENARIO_DETAIL_LE
WHERE SCENARIO_ID = 16968) AS V ON J.MATERIAL_NUMBER = V.ITEM_CODE
ORDER BY J.MATERIAL_NUMBER, J.STANDARDS_NAME, J.OPERATION_CODE;
Had help from a friend and we discovered that it was a casting problem between a linked Oracle table and the Access table. To fix the problem we casted both sides of the linked fields to a string:
CSTR(D.[MATERIAL_NUMBER]) = CSTR(V.[ITEM_CODE])

SQL Server : multi-join with tuple IN clause

I'm trying to join 4 tables that have a somewhat complex relationship. Because of where this will be used, it needs to be contained in a single query, but I'm having trouble since the primary query and the IN clause query both join 2 tables together and the lookup is on two columns.
The goal is to input a SalesNum and SalesType and have it return the Price
Tables and relationships:
sdShipping
SalesNum[1]
SalesType[2]
Weight[3]
sdSales
SalesNum[1]
SalesType[2]
Zip[4]
spZones
Zip[4]
Zone[5]
spPrices
Zone[5]
Price
Weight[3]
Here's my latest attempt in T-SQL:
SELECT
spp.Price
FROM
spZones AS spz
LEFT OUTER JOIN
spPrices AS spp ON spz.Zone = spp.Zone
WHERE
(spp.Weight, spz.Zip) IN (SELECT ship.Weight, sales.Zip
FROM sdShipping AS ship
LEFT OUTER JOIN sdSales AS sales ON sales.SalesNum = ship.SalesNum
AND sales.SalesType = ship.SalesType
WHERE sales.SalesNum = (?)
AND ship.SalesType = (?));
SQL Server Management Studio says I have an error in my syntax near ',' (appropriately useless error message). Does anybody have any idea whether this is even allowed in Microsoft's version of SQL? Is there perhaps another way to accomplish it? I've seen the multi-key IN questions answered on here, but never in the case where both sides require a JOIN.
Many databases do support IN on tuples. SQL Server is not one of them.
Use EXISTS instead:
SELECT spp.Price
FROM spZones spz LEFT OUTER JOIN
spPrices spp
ON spz.Zone = spp.Zone
WHERE EXISTS (SELECT 1
FROM sdShipping ship LEFT JOIN
sdSales sales
ON sales.SalesNum = ship.SalesNum AND
sales.SalesType = ship.SalesType
WHERE spp.Weight = ship.Weight AND spz.Zip = sales.Zip AND
sales.SalesNum = (?) AND
ship.SalesType = (?)
);

ORA-00918: column ambigously defined, using DB Link

When I execute the query below I get the following error message :
ORA-00918: column ambigously defined
ORA-02063: preceding line from ABC
Query:
SELECT
dos.*,
cmd.*,
cmd_r.*,
adr_inc.*,
adr_veh.*,
loc.*,
fou_d.*,
fou_r.*, --Works if I comment this line
mot.*
FROM
DOSSIERS#ABC dos
LEFT JOIN CMDS#ABC cmd ON cmd.DOS_CODE_ID = dos.dos_code_id
LEFT JOIN CMDS_RECCSTR#ABC cmd_r ON cmd_r.DOS_CODE_ID = dos.DOS_CODE_ID AND cmd_r.CMD_CODE_ID = cmd.CMD_CODE_ID AND cmd_r.CMD_DT_CREAT = cmd.CMD_DT_CREAT
LEFT JOIN HISTO_ADR#ABC adr_inc ON adr_inc.DOS_CODE_ID = dos.DOS_CODE_ID
LEFT JOIN HISTO_ADR#ABC adr_veh ON adr_veh.DOS_CODE_ID = dos.DOS_CODE_ID
LEFT JOIN LOC#ABC loc ON dos.DOS_CODE_ID = loc.DOS_CODE_ID
LEFT JOIN FOURNISS#ABC fou_d ON fou_d.PAY_CODE_ID = loc.PAY_CODE_ID_D AND fou_d.FOU_CODE_ID = loc.FOU_CODE_ID_D
LEFT JOIN FOURNISS#ABC fou_r ON fou_r.PAY_CODE_ID = loc.PAY_CODE_ID_R AND fou_r.FOU_CODE_ID = loc.FOU_CODE_ID_R
LEFT JOIN REF_MOT#ABC mot ON mot.RMR_CODE_ID = cmd_r.RMR_CODE_ID
WHERE
dos.REF_EXT = 'XXXXXXX'
If I comment fou_r.* in SELECT it works.
The following queries don't work neither:
SELECT *
FROM ... ;
SELECT (SELECT count(xxx) FROM ...)
FROM ...;
I looked at similar issues on SO but they were all using complex queries or was using many SELECT inside WHERE. Mine is simple that is why I don't understand what could be wrong.
Current Database: Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
Target Database (refers to db link ABC target): Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
Client: Toad for Oracle 9.7.2.5
You seem to be hitting bug 13589271. I can't share details from MOS, but there isn't much to share anyway. It's related to the remote table having a column with a 30-character name though, as you have in your remote FOURNIUSS table.
Unfortunately simply aliasing the column in your query, like this:
fou_d.COLUMN_WITH_30_CHARACTERS_NAME alias_a,
fou_r.COLUMN_WITH_30_CHARACTERS_NAME alias_b,
... doesn't help and still gets the same error, as the alias is applied by the local database and the problem seems to be during the remote access. What does seem to work is using an in-line view to apply a column alias before the join:
...
LEFT JOIN LOC#ABC loc ON dos.DOS_CODE_ID = loc.DOS_CODE_ID
LEFT JOIN (
SELECT PAY_CODE_ID, FOU_CODE_ID, COLUMN_WITH_30_CHARACTERS_NAME alias_a FROM FOURNISS#ABC
) fou_d ON fou_d.PAY_CODE_ID = loc.PAY_CODE_ID_D AND fou_d.FOU_CODE_ID = loc.FOU_CODE_ID_D
LEFT JOIN (
SELECT PAY_CODE_ID, FOU_CODE_ID, COLUMN_WITH_30_CHARACTERS_NAME alias_b FROM FOURNISS#ABC
) fou_r ON fou_r.PAY_CODE_ID = loc.PAY_CODE_ID_R AND fou_r.FOU_CODE_ID = loc.FOU_CODE_ID_R
LEFT JOIN REF_MOT#ABC mot ON mot.RMR_CODE_ID = cmd_r.RMR_CODE_ID
...
This even works if you give the column the same alias in both inline views. The downside is that you have to explicitly list all of the columns from the table (or at least those you're interested in) in order to be able to apply the alias to the problematic one, but having done so you can still use fou_d.* and fou_r.* in the outer select list.
I don't have an 11.2.0.2 database but I've run this successfully in an 11.2.0.3 database which still showed the ORA-00918 error from your original code. It's possible something else in 11.2.0.2 will stop this workaround being effective, of course. I don't see the original problem in 11.2.0.4 at all, so upgrading to that terminal patch release might be a better long-term solution.
Using * is generally considered a bad practice anyway though, not least because you're going to get a lot of duplicated columns from the joins (lots of dos_code_id in each row, for example); but you're also likely to be getting other data you don't really want, and anything that consumes this result set will have to assume the column order is always the same in those tables - any variation, or later addition or removal of a column, will cause problems.

Nhibernate join filtering

I have a question about joins in NHIBERNATE. We had an issue with our sql query that was generated but nhibernate. Our db developer optimized the raw sql so it works as we need, but we need to change the nhibernate code to make generated sql look like optimized.
the part of the original part of the query is:
FROM PERSON_VISIT this_
inner join PERSON_Basic per2_
on this_.PERSON_ID = per2_.PERSON_ID
left outer join PERSONC_QUESTIONS perint10_
on per2_.PERSON_ID = perint10_.PERSON_ID
left outer join TELEPHONE_QUESTIONS intaudit13_
on perint10_.PP_QUESTIONS_ID = intaudit13_.PP_QUESTIONS_ID
inner join C_QUESTIONS intdef14_
on perint10_.QUESTION_ID = intdef14_.QUESTION_ID
and perint10_.QUESTIONS_CODE = intdef14_.QUESTIONS_CODE
and perint10_.QUESTION_ID = intdef14_.QUESTION_ID
The optimized one is :
FROM PERSON_VISIT this_
inner join PERSON_Basic per2_
on this_.PERSON_ID = per2_.PERSON_ID
left outer join PERSONC_QUESTIONS perint10_
on per2_.PERSON_ID = perint10_.PERSON_ID
left outer join TELEPHONE_QUESTIONS intaudit13_
on perint10_.PP_QUESTIONS_ID = intaudit13_.PP_QUESTIONS_ID
left outer join C_QUESTIONS intdef14_
on perint10_.QUESTION_ID = intdef14_.QUESTION_ID
and perint10_.QUESTIONS_CODE = intdef14_.QUESTIONS_CODE
and perint10_.QUESTION_ID = intdef14_.QUESTION_ID
and intdef14_.DISCIPLINE_CODE = this_.DISCIPLINE_CODE
To change query from inner join to left outer join is easy, i changed only one line of code:
.CreateAlias("PersonInt.QuestionEntity", "IntDef", JoinType.LeftOuterJoin)
But how I can add
and intdef14_.DISCIPLINE_CODE = this_.DISCIPLINE_CODE
using nhibernate code?
There is an option to add reference from PERSON_VISIT definition to C_QUESTIONS, but the problem is that
PERSON_VISIT is used everywhere and I don't want this change to possibly break other queries, I just wnat to add only one line of code to add, how I can do that? Is there any way to have access to the raw join to change it? Or some other way to add this
and intdef14_.DISCIPLINE_CODE = this_.DISCIPLINE_CODE
To the query?
I know that somebody will say that we can add a restriction to the query through criteria.Add, but it is not an option cause db developer optimized our query taking this restriction from WHERE clause to the join.
How I can do that quickly without changing the models definitions? Just changing only this one query without changing the whole model?
It is possible using HQL and the Criteria API's.
This question gives you the answer: Adding conditionals to outer joins with nhibernate
Something like this may solve your issue.
.CreateAlias("PersonInt.QuestionEntity", "IntDef", JoinType.LeftOuterJoin,
Restrictions.EqProperty("DISCIPLINE_CODE", "IntDef.DISCIPLINE_CODE"))
Thanks for answers. We use 2.0 version of NHibernate in our project so we didn't have a chance to use new methods of .CreateAlias with restrictions.
I have fixed an issue using Interceptors:
public class SqlInterceptor : EmptyInterceptor, IInterceptor
{
SqlString IInterceptor.OnPrepareStatement(SqlString sql)
{
//manipulating with the sql
return sql;
}
}
than
var factory = Session.SessionFactory;
var session = factory.OpenSession(new SqlInterceptor());
And use my query without a change.