I am trying to join two tables in SQL Server. Their are no PK / FK in the tables so I have to join on a few conditions.
What I want to have happen is if I am unable to match on my first criteria I then want to join on different criteria. I was thinking there could be way to do this using a case statement... If it matches on my first condition then all is good, if it does not match on the first condition then try to join on a different condition.
Here is what I have so far.
SELECT *
FROM Table1
INNER JOIN Table2
ON Table1.DOS = CAST(SUBSTRING(Table2.SurgeryDate, 6, 2) + '/' + SUBSTRING(Table2.SurgeryDate, 9, 2) + '/' + SUBSTRING(Table2.SurgeryDate, 1, 4) AS DATE)
AND Table1.DateOfBirth = CAST(SUBSTRING(Table2.BirthDate, 6, 2) + '/' + SUBSTRING(Table2.BirthDate, 9, 2) + '/' + SUBSTRING(Table2.BirthDate, 1, 4) AS DATE)
AND Table1.Gender = CASE WHEN Table2.gender = 'Male' THEN 'M'
WHEN Table2.gender = 'Female' THEN 'F'
ELSE 'U'
END
AND LTRIM(RTRIM(Table1.HspId)) = LTRIM(RTRIM(Table2.HspId))
---If those people who do not match on the above criteria then I would want to match them on their last name.
Sample data will be needed to give a specific answer, but here are a couple general approaches:
You can use OR while ruling out the previous condition:
SELECT cols
FROM Table1 t1
JOIN Table2 t2 ON t1.col1 = t2.col1
OR (t1.col1 <> t2.col1 AND t1.col2 = t2.col2)
Note you have to rule out the previous condition to create the join predicate hierarchy and avoid duplicates.
Another way is to use repeated LEFT JOINs for each condition and add NULL handling:
SELECT COALESCE(t2.col1, t3.col1)
FROM Table1 t1
LEFT JOIN Table2 t2 ON t1.col1 = t2.col1
LEFT JOIN Table2 t3 ON t1.col2 = t3.col2
WHERE COALESCE(t2.col1, t3.col1) IS NOT NULL
COALESCE() returns the first non NULL value. The LEFT JOINs will return NULL if the join does not find a match row. Thus, the select COALESCE() is handling 'displaying' the correct column based on the join hierarchy order. The where COALESCE() is filtering out the rows where none of joins are successful (recreating the INNER JOIN you have in your current query)
The second approach, while ugly, can perform better because OR queries have trouble optimizing properly.
Related
I have 2 tables that showing data Item master and BOM. I would like to join the tables between Item master as T1 and BOM as T2 and the additional table for table BOM as T3. Item master table containing ITM_CD, ITM_TYP (1,2,3,4) where each ITM_TYP represents a code for the first digit on ITM_CD. The thing that I want is like the picture below
CHILD_CD2 value replace to CHILD_CD1 value. So the data should be like this. What query should I fix ? I am very new using oracle query.
Here is mycode;
SELECT DISTINCT
T1.ITM_CD,
T2.C_ITM_CD AS CHILD_CD1,
T3.C_ITM_CD AS CHILD_CD2
FROM CM_HINMO_ALL T1
INNER JOIN (SELECT P_ITM_CD, C_ITM_CD, BOM_PTN FROM SM_BOM_ALL) T2
ON T1.ITM_CD = T2.P_ITM_CD
LEFT JOIN (SELECT P_ITM_CD, C_ITM_CD, BOM_PTN FROM SM_BOM_ALL) T3
ON T2.C_ITM_CD = t3.P_ITM_CD
WHERE 0=0
AND T2.BOM_PTN IN (1)
AND T1.ITM_TYP IN (1,2)
AND T1.ITM_CD = '110100370'
ORDER BY 2
Just use Case expression to replace the values.
SELECT ITM_CD, CASE WHEN CHILD_CD2 IS NULL THEN CHILD_CD2 ELSE CHILD_CD1 END AS CHILD_CD1
FROM TABLE1
If I understood, you want child_cd2 value should taken precedence over child_cd1 if available. If this assumption is right then we can use coalesce which returns the fist non null expression to achieve the same.
SELECT DISTINCT
T1.ITM_CD,
COALESCE(T3.C_ITM_CD,T2.C_ITM_CD) AS CHILD_CD1
FROM CM_HINMO_ALL T1
INNER JOIN SM_BOM_ALL T2
ON T1.ITM_CD = T2.P_ITM_CD
LEFT JOIN SM_BOM_ALL T3
ON T2.C_ITM_CD = t3.P_ITM_CD
WHERE T2.BOM_PTN IN (1)
AND T1.ITM_TYP IN (1,2)
AND T1.ITM_CD = '110100370'
ORDER BY 2
I have two tables as shown in the image. I would like to join two table. As shown in thane tables, first row is matching exactly, but in the second row last 17 digits(WSAV_3PE_RET_0720) are matching. I would like join this one also. So there should be two conditions.
Exactly matching
Last 17 digits are matching.
How to write the code in this scenario. Here is my partial code.
Select *,t2.Balance from t1 left join t2 on t1.Place = t2.Place
Below is for BigQuery Standard SQL
#standardSQL
SELECT t1.*, t2.Balance
FROM `project.dataset.table1` t1
LEFT JOIN `project.dataset.table2` t2
ON SUBSTR(REVERSE(t1.Place), 1, 17) = SUBSTR(REVERSE(t2.Place), 1, 17)
I solved the query at this link
Can you return a list of characters and TV shows that are not named "Willow Rosenberg" and not in the show "How I Met Your Mother"?
with the following code:
SELECT ch.name,sh.name
FROM character ch
INNER JOIN character_tv_show chat
ON ch.id = chat.character_id
INNER JOIN tv_show sh
ON chat.tv_show_id=sh.id
WHERE ch.name != "Willow Rosenberg" AND sh.name !="How I Met Your Mother"
;
However, my first try was:
SELECT ch.name,sh.name
FROM character ch
WHERE ch.name != "Willow Rosenberg" /*This here*/
INNER JOIN character_tv_show chat
ON ch.id = chat.character_id
INNER JOIN tv_show sh
ON chat.tv_show_id=sh.id
WHERE sh.name !="How I Met Your Mother"
;
because I thought that in this way only the table character would have been filtered before doing the joins and, therefore, it would have been less computationally heavy.
Does it make any sense?
Is there a way to "split" the WHERE clause when joining multiple tables?
Think of JOINs as a cross-product of two tables, which is filtered using the conditions specified in the ON clause. Your WHERE clause is then applied on the result set, and not on the individual tables participating in the join.
If you want to apply WHERE on only one of the joined tables, you'll have to use a sub-query. The filtered result of that sub-query will then be treated as a normal table and joined with a real table using JOIN again.
If you are doing this for performance, remember though that a join is almost always faster on standard JOINs compared to sub-queries, for properly indexed tables. You'll find that queries using JOIN will be orders of magnitude faster than the ones using sub-queries, except for rare cases.
You can using subqueries
SELECT ch.name,sh.name
FROM (
SELECT ch.name
FROM character ch
WHERE ch.name != "Willow Rosenberg") ch
INNER JOIN character_tv_show chat
ON ch.id = chat.character_id
INNER JOIN tv_show sh
ON chat.tv_show_id=sh.id
WHERE sh.name !="How I Met Your Mother"
but i think it don't have sense. subqueries will make temp table.
First query will be optimized by database server, and likely select only rows from character table that need
JOIN and WHERE clauses are not necessarily executed in the order you write them. In general, the query optimizer will rearrange things to make them as efficient as possible (or at least what it thinks is most efficient), so adding a second WHERE clause wouldn't be any different from adding another AND condition (which is why it's not allowed).
Your idea wasn't bad, but it's just not how databases actually work.
A SELECT can only have 1 WHERE clause.
And it comes after the JOIN's.
But you can have additional WHERE clauses in the sub-queries you join.
And sometimes a criteria that you've added to a WHERE clause can be moved to the ON of a JOIN.
For example the queries below would return the same results
SELECT *
FROM Table1 AS t1
JOIN Table2 AS t2 ON t2.ID = t1.table2ID
WHERE t1.Col1 = 'foo'
AND t2.Col1 = 'bar'
SELECT *
FROM
(
SELECT *
FROM Table1
WHERE Col1 = 'foo'
) AS t1
JOIN Table2 AS t2 ON t2.ID = t1.table2ID
WHERE t2.Col1 = 'bar'
SELECT *
FROM Table1 AS t1
JOIN Table2 AS t2 ON (t2.ID = t1.table2ID AND t2.Col1 = 'bar')
WHERE t1.Col1 = 'foo'
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.
I have a join on two tables defined as a left outer join so that all records are returned from the left hand table even if they don't have a record in the right hand table. However I also need to include a where clause on a field from the right-hand table, but.... I still want a row from the left-hand table to be returned for each record in the left-hand table even if the condition in the where clause isn't met. Is there a way of doing this?
Yes, put the condition (called a predicate) in the join conditions
Select [stuff]
From TableA a
Left Join TableB b
On b.Pk = a.Pk
-- [Put your condition here, like this]
And b.Column = somevalue
The reason this works is because the query processor applies conditions in a where clause after all joins are completed, and the final result set has been constructed. So, at that point, a column from the a table on the outer side of a join that has null in a a column you have established a predicate on will be excluded.
Predicates in a join clause are applied before the two result sets are "joined". At this point all the rows on both sides of the join are still there, so the predicate is effective.
You just need to put the predicate into the JOIN condition. Putting it into the WHERE clause would effectively convert your query to an inner join.
For Example:
...
From a
Left Join b on a.id = b.id and b.condition = 'x'
You can use
WHERE (right_table.column=value OR right_table.column IS NULL)
This will return all rows from table 1 and table 2, but only where table 1 does not have a corresponding row in table 2 or the corresponding row in table 2 matches your criteria.
SELECT x.fieldA, y.fieldB
FROM x
LEFT OUTER JOIN (select fieldb, fieldc from Y where condition = some_condition)
ON x.fieldc = y.fieldc
select *
from table1 t1
left outer join table2 t2 on t1.id = t2.id
where t1.some_field = nvl(t2.some_field, t1.some_field)
UPD: errr... no. this way:
select *
from table1 t1
left outer join table2 t2 on t1.id = t2.id
where some_required_value = nvl(t2.some_field, some_required_value)
nvl is an Oracle syntax which replaces first argument with second in case it is null (which is common for outer joins). You can use ifnull or coalesce for other databases.
Thus, you compare t2.some_field with your search criteria if it has met join predicate, but if it has not, then you just return row from table1, because some_required_value compared to itself will always be true (unless it is null, however - null = null yields null, neither true not false.