I'm accustomed to doing this in Oracle (and I think even SqlServer a while back), but I haven't figured out how to do it in sqlite.
A standard "simple" join in sqlite can be done like so:
select *
from kennel k
join kennelbreeder kb
on kb.kennelid = k.rowid;
But if I want to also get some information from the breeder, based on my experience elsewhere, I would expect the following to work, but it doesn't:
select *
from kennel k
join kennelbreeder kb
join breeder b
on kb.breederid = b.rowid
on kb.kennelid = k.rowid;
The error I get is 'Error: near "on": syntax error'. What's the correct way to do this?
In Sqlite, joins may not be nested:
select *
from kennel k
join kennelbreeder kb ON kb.kennelid = k.rowid;
join breeder b on kb.breederid = b.rowid
The on must follow the join. It's just a question about the correct order.
select *
from kennel k
join kennelbreeder kb
on kb.kennelid = k.rowid
join breeder b
on kb.breederid = b.rowid;
Your second example seems to be based on the syntax with nested joins which I've only seen used in MS Access, but it's always with parentheses, which are missing in your example. It would seem that this query works with both MS SQL and SQLite3, and possibly other databases too:
SELECT *
FROM kennel k
JOIN ( kennelbreeder kb
JOIN breeder b
ON kb.breederid = b.rowid )
ON kb.kennelid = k.rowid;
I wouldn't recommend using the latter syntax though as it's unclear and not the standard way of writing joins.
Related
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
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])
I have a SQL query :
SELECT TRIM(RL.RDB$RELATION_NAME), TRIM(FR.RDB$FIELD_NAME), FS.RDB$FIELD_TYPE, TRIM(RC.RDB$CONSTRAINT_TYPE)
FROM RDB$RELATIONS RL
LEFT OUTER JOIN RDB$RELATION_FIELDS FR ON FR.RDB$RELATION_NAME = RL.RDB$RELATION_NAME
LEFT OUTER JOIN RDB$FIELDS FS ON FS.RDB$FIELD_NAME = FR.RDB$FIELD_SOURCE
LEFT OUTER JOIN RDB$INDEX_SEGMENTS ISS ON ISS.RDB$FIELD_NAME = FR.RDB$FIELD_NAME
INNER JOIN RDB$RELATION_CONSTRAINTS RC ON RC.RDB$CONSTRAINT_NAME = ISS.RDB$INDEX_NAME
WHERE (RL.RDB$VIEW_BLR IS NULL)
ORDER BY RL.RDB$RELATION_NAME, FR.RDB$FIELD_NAME
Yesterday i asked how correctly translate a query from Firebird to PostgreSQL and I'm asking once again :) . (But I'd just started working with databases and got really hard task (rewrite a big part of code, because RDBMS had been changed) ). A big part is done, but I have a problems with this translation. So, can u help me? There is some code which i've translated by myself.
I'm trying to retrieve a list of components via my computer_system, BUT if a computer system's graphics card is set to null (I.e. It has an onboard), the row isn't returned by my select statement.
I've been trying to use COALESCE without results. I've also tried with and OR in my WHERE clause, which then just returns my computer system with all different kinds of graphic cards.
Relevant code:
SELECT
computer_system.cs_id,
computer_system.cs_name,
motherboard.name,
motherboard.price,
cpu.name,
cpu.price,
gfx.name,
gfx.price
FROM
public.computer_case ,
public.computer_system,
public.cpu,
public.gfx,
public.motherboard,
public.ram
WHERE
computer_system.cs_ram = ram.ram_id AND
computer_system.cs_cpu = cpu.cpu_id AND
computer_system.cs_mb = motherboard.mb_id AND
computer_system.cs_case = computer_case.case_id AND
computer_system.cs_gfx = gfx.gfx_id; <-- ( OR computer_system.cs_gfx IS NULL)
Returns:
1;"Computer1";"Fractal Design"; 721.00; "MSI Z87"; 982.00; "Core i7 I7-4770K "; 2147.00; "Crucial Gamer"; 1253.00; "ASUS GTX780";3328.00
Should I use Joins? Is there no easy way to say return the requested row, even if there's a bloody NULL value. Been struggling with this for at least 2 hours.
Tables will be posted if needed.
EDIT: It should return a second row:
2;"Computer2";"Fractal Design"; 721.00; "MSI Z87"; 982.00; "Core i7 I7-4770K "; 2147.00; "Crucial Gamer"; 1253.00; "null/nothing";null/nothing
You want a LEFT OUTER JOIN.
First, clean up your code so you use ANSI joins so it's readable:
SELECT
computer_system.cs_id,
computer_system.cs_name,
motherboard.name,
motherboard.price,
cpu.name,
cpu.price,
gfx.name,
gfx.price
FROM
public.computer_system
INNER JOIN public.computer_case ON computer_system.cs_case = computer_case.case_id
INNER JOIN public.cpu ON computer_system.cs_cpu = cpu.cpu_id
INNER JOIN public.gfx ON computer_system.cs_gfx = gfx.gfx_id
INNER JOIN public.motherboard ON computer_system.cs_mb = motherboard.mb_id
INNER JOIN public.ram ON computer_system.cs_ram = ram.ram_id;
Then change the INNER JOIN on public.gfx to a LEFT OUTER JOIN:
LEFT OUTER JOIN public.gfx ON computer_system.cs_gfx = gfx.gfx_id
See PostgreSQL tutorial - joins.
I very strongly recommend reading an introductory tutorial to SQL - at least the PostgreSQL tutorial, preferably some more material as well.
It looks like it's just a bracket placement issue. Pull the null check and the graphics card id comparison into a clause by itself.
...
computer_system.cs_case = computer_case.case_id AND
(computer_system.cs_gfx IS NULL OR computer_system.cs_gfx = gfx.gfx_id)
Additionally, you ask if you should use joins. You are in fact using joins, by virtue of having multiple tables in your FROM clause and specifying the join criteria in the WHERE clause. Changing this to use the JOIN ON syntax might be a little easier to read:
FROM sometable A
JOIN someothertable B
ON A.somefield = B.somefield
JOIN somethirdtable C
ON A.somefield = C.somefield
etc
Edit:
You also likely want to make the join where you expect the null value to be a left outer join:
SELECT * FROM
first_table a
LEFT OUTER JOIN second_table b
ON a.someValue = b.someValue
If there is no match in the join, the row from the left side will still be returned.
I am busy converting a query using the old style syntax to the new join syntax. The essence of my query is as follows :
Original Query
SELECT i.*
FROM
InterestRunDailySum i,
InterestRunDetail ird,
InterestPayments p
WHERE
p.IntrPayCode = 187
AND i.IntRunCode = p.IntRunCode AND i.ClientCode = p.ClientCode
AND ird.IntRunCode = p.IntRunCode AND ird.ClientCode = p.ClientCode
New Query
SELECT i.*
FROM InterestPayments p
INNER JOIN InterestRunDailySum i
ON (i.IntRunCode = p.IntRunCode AND i.ClientCode = p.ClientCode)
INNER JOIN InterestRunDetail ird
ON (ird.IntRunCode = p.IntRunCode AND ird.IntRunCode = p.IntRunCode)
WHERE
p.IntrPayCode = 187
In this example, "Original Query" returns 46 rows, where "New Query" returns over 800
Can someone explain the difference to me? I would have assumed that these queries are identical.
The problem is with your join to InterestRunDetail. You are joining on IntRunCode twice.
The correct query should be:
SELECT i.*
FROM InterestPayments p
INNER JOIN InterestRunDailySum i
ON (i.IntRunCode = p.IntRunCode AND i.ClientCode = p.ClientCode)
INNER JOIN InterestRunDetail ird
ON (ird.IntRunCode = p.IntRunCode AND ird.ClientCode = p.ClientCode)
WHERE
p.IntrPayCode = 187
The "new query" is the one compatible with the current ANSI SQL standard for JOINs.
Also, I find query #2 much cleaner:
you are almost forced to think about and specify the join condition(s) between two tables - you will not accidentally have cartesian products in your query. If you happen to list ten tables, but only six join conditions in your WHERE clause - you'll get a lot more data back than expected!
your WHERE clause isn't cluttered with join conditions and thus it's cleaner, less messy, easier to read and understand
the type of your JOIN (whether INNER JOIN, LEFT OUTER JOIN, CROSS JOIN) is typically a lot easier to see - since you spell it out. With the "old-style" syntax, the difference between those join types is rather hard to see, buried somewhere in your lots of WHERE criteria.....
Functionally, the two are identical - #1 might be deprecated sooner or later by some query engines.
Also see Aaron Bertrand's excellent Bad Habits to Kick - using old-style JOIN syntax blog post for more info - and while you're at it - read all "bad habits to kick" posts - all very much worth it!