I'm trying to rewrite the following query which was generated in some part by Impromptu. For some reason I cannot get my head around the multiple tables after the FROM and the nest of joins that follows. I have always used a "master" table then joined anything I would need after that. i.e select from, left join (table) on x=x left join (table) on x=x and so on.
I'm having a difficult time with the parenths etc... in this. What would it look like written in "normal" query style? Thanks so much in advance!
select
T6."dateofservice"
, getdate(), -20000 - (1 - convert(float(53),-2) / abs(-2)) / 2
, T1."pgrp_specialty"
, T1."pgrp_prov_combo"
, T2."patsex"
, T3."restricted"
, T2."patdob"
, T2."patdecdate"
, T2."acctno"
, T2."patno"
from
"acctdemo_t" T3, "transaction_t" T5,
("patdemo_t" T2
LEFT OUTER JOIN ("provcode_t" T8
LEFT OUTER JOIN "provalt_t" T1 on T8."px" = T1."accesspractice" and T8."provcode" = T1."accessprovidercode") on T2."provcode" = T8."provcode")
LEFT OUTER JOIN "insset_t" T4 on T2."acctno" = T4."acctno" and T2."patno" = T4."patno", "charge_t" T6
LEFT OUTER JOIN "poscode_t" T7 on T6."poscode" = T7."poscode"
where
T2."patsex" <> 'U'
and T7."posid" = '3'
and T6."correction" = 'N'
and T5."txtype" = 'C'
and (T4."defaultset" = 'Y' or
(T4."inssetno" = 0 or T4."inssetno" is null)
and T4."defaultset" is null)
and T6."chgno" = T5."chgno"
and T2."patno" = T6."patno"
and T2."acctno" = T6."acctno"
and T2."acctno" = T3."acctno"
SQL written with multiple tables, separated by comma is implied INNER JOIN, with the where clause serving as the join clause. For example,
select * from table1 a, table2 b
where a.id = b.id
is the same as:
select * from table1 a inner join table2 b on a.id = b.id
So, in your case, this part:
from "acctdemo_t" T3
, "transaction_t" T5
is implying inner join between acctdemo_t and transaction_t.
And - the third part of this:
("patdemo_t" T2 LEFT OUTER JOIN
("provcode_t" T8 LEFT OUTER JOIN "provalt_t" T1 on T8."px" = T1."accesspractice" and T8."provcode" = T1."accessprovidercode")
on T2."provcode" = T8."provcode")
Is actually a tableset being created on the fly with its own clauses, and is basically acting as a table in this join. Also being joined with Inner join, since its added with a comma.
I believe this can definitely written to be more readable, and the inline tableset being created isn't going to be good for performance, but that totally depends on the number of records you have.
Related
I'm trying to run this SQL Expression in Access:
Select *
From ((TableA
Left Join TableB
On TableB.FK = TableA.PK)
Left Join TableC
On TableC.FK = TableB.PK)
Left Join (SELECT a,b,c FROM TableD WHERE b > 1) AS TableD
On (TableD.FK = TableC.PK AND TableA.a = TableD.a)
but it keeps getting error: Join-Expression not supported.
Whats the problem?
Sorry, im just starting with Jet-SQL and in T-SQL its all fine.
Thanks
The issue is that the final outer join condition TableA.a = TableD.a will cause the query to contain ambiguous outer joins, since the records to which TableA is joined to TableD will depend upon the results of the joins between TableA->TableB, TableB->TableC and TableC->TableD.
To avoid this, you'll likely need to structure your query with the joins between tables TableA, TableB & TableC existing within a subquery, the result of which is then outer joined to TableD. This unambiguously defines the order in which the joins are evaluated.
For example:
select * from
(
select TableA.a, TableC.PK from
(
TableA left join TableB on TableA.PK = TableB.FK
)
left join TableC on TableB.PK = TableC.FK
) q1
left join
(
select TableD.a, TableD.b, TableD.c, TableD.FK from TableD
where TableD.b > 1
) q2
on q1.a = q2.a and q1.PK = q2.FK
Consider relating every join to the FROM table to avoid having to nest relations.
SELECT *
FROM ((TableA
LEFT JOIN TableB
ON TableB.FK = TableA.PK)
LEFT JOIN TableC
ON TableC.FK = TableA.PK)
LEFT JOIN
(SELECT FK,a,b,c
FROM TableD WHERE b > 1
) AS TableD
ON (TableD.FK = TableA.PK)
AND (TableD.a = TableA.a)
I'm asking if is it possible to use join with 2 clauses of differente tables like :
select t1.x,t1.y, t1.z
from t1
inner join t2 on t1.conditionA = t2.conditionA
inner join t3 on t2.conditionB = t3.conditionB
inner join t4 on t3.conditionC = t4.conditionC and t2.conditionD = t4.conditionD
where....
Is it worng? how should I do it?
Yes, you can, but it is a clue that your tables are not well designed.
I have a join query I use to pull data from another table:
SELECT [THEME].[NAME],
[THEMETYPE].[TYPE]
FROM [THEME]
LEFT OUTER JOIN [THEMETYPE]
ON [THEME].[THEMETYPEID] = [THEMETYPE].[PK_THEMETYPE]
WHERE COALESCE([THEME].[THEMETYPEID], 'null') LIKE '%'
ORDER BY CASE
WHEN [THEMETYPE].[TYPE] IS NULL THEN 1
ELSE 0
END,
[THEMETYPE].[TYPE]
I need to add the ability to narrow it down if a 3rd tables values match up:
Where producttheme.productid = variable-paramater-here
AND producttheme.themeid = theme.pk_theme
Here is a pic of the table:
So if the 1 is chosen above, it will return all [Theme].[Name] and the associated [ThemeType].[Type] where The ThemeId is associated with ProductId = 1
Edit: to be more clear ThemeId is the Primary key in the Theme table where Theme.Name exists.
This would give you some idea, please adjust the column names accordingly:
SELECT [Theme].[Name], [ThemeType].[Type]
FROM [Theme]
Left Outer Join [ThemeType]
ON [Theme].[ThemeTypeId] = [ThemeType].[PK_ThemeType]
join ProductTheme PT
on PT.ProductID=ThemeType.ProductID
WHERE ProductTheme.ProductID = VARIABLE-PARAMATER-HERE AND ProductTheme.ThemeId = Theme.PK_Theme
ORDER BY [ThemeType].[Type]
Depending on whether or not you need the WHERE condition before you add the 3rd table, you can try one of these 2 options:
SELECT *
FROM TABLE1 T1
LEFT OUTER JOIN TABLE2 T2
ON T1.FIELDA = T2.FIELDA
INNER JOIN TABLE3 T3
ON T1.FIELDA = T3.FIELDA
WHERE T1.FIELDB = 'aaa'
AND T3.FIELDC = 12
or:
SELECT *
FROM (SELECT T1.FIELDA,
T2.FIELDB
FROM TABLE1 T1
LEFT OUTER JOIN TABLE2 T2
ON T1.FIELDA = T2.FIELDA
WHERE T1.FIELDC = 'aaa')T3
INNER JOIN TABLE3 T4
ON T3.FIELDA = T3.FIELDA
AND T4.FIELDC = 12
I hope this gives you something to work with.
If you provide some sample data, I can set up a working example.
I want to be able to inner join two tables based on the value of a column I'm selecting.
My Query:
SELECT varA, varB, MAX(varC) varC
FROM table1
INNER JOIN table2 ON varB = table2.varB
INNER JOIN #tempTable ON varA = table1.column
INNER JOIN table3 ON varC = table3.column AND table3.column2 = 1 -- **IF NOT varA = 100**
INNER JOIN table4 ON varC = table4.column **-- IF varA = 100**
LEFT OUTER JOIN table5 ON table2.column = table5.column AND table5.column2 = 1 AND table5.column3 = 4
GROUP BY varB, varA
So, in short INNER JOIN on table4 if value of column(varA) is not 100 else INNER JOIN on table3
I think this will get the result you're after:
LEFT JOIN table3 ON varC = table3.column AND table3.column2 = 1 AND varA <> 100 -- **IF NOT varA = 100**
LEFT JOIN table4 ON varC = table4.column AND varA = 100 **-- IF varA = 100**
...
WHERE (Table3.Column IS NOT NULL OR Table4.Column IS NOT NULL)
Basically allows a join to either table, but only return rows where one of those joins found a record. If you want to return the actual columns from the table as part of the select then you could use an ISNULL:
SELECT ISNULL(Table3.Column, Table4.Column) AS Column
EDIT: I should have added that you can't conditionally join to tables unless you want to use dynamic SQL. You can either join to the table or not. What I outlined above lets you do the join to both tables and then check that one of them did join (which is basically what an Inner Join does).
So, in short INNER JOIN on table3 if varA is not 100 else INNER JOIN on table4.
That cannot be effectively done in one query. At execution time, the database must decide what joins to perform on a whole-table basis, not a row-by-row basis. If you attempt to do what you propose, what you will get, at best, is that the database will join on both table3 and table4. At worst, the joins will be Cartesian (unrestricted "all rows * all rows" joins).
So you only have these two options:
Join to both tables, and select on a row-by-row basis whether to produce data from table3 or table4 for that row.
Split the query into two queries joined by UNION. One of the queries joins with table3, the other joins with table4. You use the condition to control which rows are produced by the first query and which by the second one; i.e., the subquery that joins with table3 has varA != 100 in the WHERE clause, and the subquery that joins with table4 has varA = 100.
Your question isn't quite clear and if this doesn't work please provide more info but I think this is your answer.
You can place a CASE statement in the join.
Updated, try this.
INNER JOIN table4 ON (CASE WHEN varA != 100 THEN 1 ELSE 0 END) = 1 AND tablekey=table4key
INNER JOIN table3 ON (CASE WHEN varA = 100 THEN 1 ELSE 0 END) = 0 AND tablekey=table3key
I need to do something like this to fill a parts table:
SELECT (CASE t1.part IS NULL THEN t2.part ELSE t1.part END) AS partno,
t3.desc
FROM t1
LEFT JOIN join t2 ON [certain condition]
LEFT JOIN t3 ON t1.part = t3.part
OR t2.part = t3.part
...so this will select the value for partno from t2 in case that part is null in t1, then i need to take the description from t3 but when I run it it takes forever and never return the results, How can I do this faster? if I am missing some details please ask.
this are the tables
alt text http://img15.imageshack.us/img15/3878/74385879.png
this is the actual procedure
DELIMITER $$
DROP PROCEDURE IF EXISTS `getMonthDetail` $$
CREATE DEFINER=`root`#`%` PROCEDURE `getMonthDetail`(fechai Date, wid int)
BEGIN
select distinct
ins.inventoryinid,
(
select group_concat(concat(documents.documentname,': ', inventoryin_documents.documentno))
from inventoryin_documents
left join documents on documents.documentid=inventoryin_documents.documentid
where inventoryin_documents.inventoryinid = docin.inventoryinid
group by inventoryin_documents.inventoryinid
)as docin,
trace.inventoryoutid,
(
select group_concat(concat(documents.documentname,': ', inventoryout_documents.documentno))
from inventoryout_documents
left join documents on documents.documentid=inventoryout_documents.documentid
where inventoryout_documents.inventoryoutid = docout.inventoryoutid
group by inventoryout_documents.inventoryoutid
) as docout,
outs.inventoryoutdate,
(case when trace.partnumberp is null then indetails.partnumberp else trace.partnumberp end) as nopart,
p.descriptionsmall,
trace.quantity
from
inventoryin as ins
left join inventoryinouttrace as trace on trace.inventoryinid = ins.inventoryinid
left join inventoryin_documents as docin on docin.inventoryinid = ins.inventoryinid
left join inventoryout_documents as docout on docout.inventoryoutid = trace.inventoryoutid
left join inventoryout as outs on outs.inventoryoutid = trace.inventoryoutid
left join inventoryindetails indetails on ins.inventoryinid = indetails.inventoryinid
left join product as p on trace.partnumberp=p.partnumberp
where
((ins.inventorydate > fechai+0 and ins.inventorydate < fechai+100)
or (outs.inventoryoutdate > fechai+0 and outs.inventoryoutdate < fechai+100));
END $$
DELIMITER ;
and when I Hit the explain button in the query browser it returns a error...
Try:
SELECT COALESCE(t1.part, t2.part) AS partno,
COALESCE(t3.desc, t4.desc)
FROM t1
LEFT JOIN join t2 ON [certain condition]
LEFT JOIN t3 ON t3.part = t1.part
LEFT JOIN t3 AS t4 ON t4.part = t1.part
OR's are notorious for poor performance.
OR clauses run slow and you should consider replacing them with a UNION which would still utilize any INDEXES you may have on your t1, t2, and t3 tables:
SELECT IFNULL(t1.part, t2.part) AS partno, t3.desc
FROM t1
LEFT JOIN t2 ON (condition here)
LEFT JOIN t3 ON (t1.part = t3.part)
UNION DISTINCT
SELECT IFNULL(t1.part, t2.part) AS partno, t3.desc
FROM t1
LEFT JOIN t2 ON (condition here)
LEFT JOIN t3 ON (t2.part = t3.part)
Also, your CASE() function, much the same as my simplified IFNULL() function, ends up using a temporary table. This is unavoidable when utilizing such functions.
Tell us the actual structure of the data and please show us the EXPLAIN of the query so we can see why it runs slow!
Only a guess: Are there indexes on the right coumns?
Your certain condition should be t2.id=t1.id and have more where clauses in your WHERE statement.
You may want to simplify this down to just have two select statements and see if it is slow, first.
You may be missing an index that would be helpful.
Once the two selects are fine, then you can add in the case command to the sql, and see what is going on, but don't change anything else in your query.
Then, you can give queries and times, which will help people to give a better answer.
Ok for the bleeding obvious : I suppose you have indexed the fields that you use in your joins?