Use of scalar functions in Join condition - sql-server

I am joining with a table to retrieve a value but in order to join I need to do some logic because both the tables do not have a common value in place. So the logic is to do a top 1 and get a certain value from a common table for both the inputs. I am planning to put the logic inside a scalar function and then call it in the join condition.
I have a simple join as something like this
LEFT JOIN <IndexTable> Tbl1 ON Tbl1.PrimaryKey = MainTbl.PrimaryKey
I intend to change this into something like this using a user defined scalar function
LEFT JOIN <IndexTable> Tbl1
ON dbo.fnGetCommonID(Tbl1.PrimaryKey) = dbo.fnGetCommonID(MainTbl.PrimaryKey)
In terms of performance is it good to use it this way or is there any better way for this.

If possible, do your calculation inside the query, maybe using an OUTER APPLY instead of a LEFT JOIN:
OUTER APPLY (
SELECT TOP 1 <at least one field, also values from MainTbl may be used>
FROM <the set of data you need>
WHERE <boolean, also values from MainTbl may be used>
ORDER BY <make the top record the one you want>
) AS Tbl1

Related

Looking up values in multiple tables with multiple joins

How would you do a Select statement to lookup a value in a table and then use that value to lookup another value in another table which is then used to lookup a third value in a third table? I cannot do a join from my initial table as there is no common matching field to do the join on.
In my initial table I have an Instr_Id value which is the only possible way to eventually get the Legal_Id value but the table where the Legal_Id is stored does not have an Instr_Id value. In order to do this I need to look up multiple values from 2 other tables to eventually get to the INSTR_ID value.
Example:
I use INSTR_ID in tbl.ABC and join to INSTR_ID in tbl.DEF in order to get the Fin_Enty_Name value in tbl.DEF I then need to use this Fin_Enty_Name value to join to tbl.GHI to get the Fin_Enty_Id . I finally then need to use this Fin_Enty_Id to look up the LEGAL_ID in tbl.JKL so that I can show the LEGAL_ID for each INSTR_ID in my Select query results.
select
a.INSTR_ID,
d.LEGAL_IT
from tbl.ABC as A
Inner join tbl.DEF as B on A.INSTR_ID = B.INSTR_ID
It looks pretty much straight forward:
select a.instr_id, d.legal_id
from tbl.abc a
join tbl.def b
on a.instr_id = b.instr_id
join tbl.ghi c
on b.fin_enty_name = c.fin_enty_name
join tbl.jkl d
on c.fin_enty_id = d.fin_enty_id

Join with Or Condition

Is there a more efficient way to write this? I'm not sure this is the best way to implement this.
select *
from stat.UniqueTeams uTeam
Left Join stat.Matches match
on match.AwayTeam = uTeam.Id or match.HomeTeam = uTeam.id
OR in JOINS is a bad practice, because MSSQL can not use indexes in right way.
Better way - use two selects with UNION:
SELECT *
FROM stat.UniqueTeams uTeam
LEFT JOIN stat.Matches match
ON match.AwayTeam = uTeam.Id
UNION
SELECT *
FROM stat.UniqueTeams uTeam
LEFT JOIN stat.Matches match
ON match.HomeTeam = uTeam.id
Things to be noted while using LEFT JOIN in query:
1) First of all, left join can introduce NULL(s) that can be a performance issue because NULL(s) are treated separately by server engine.
2) The table being join as null-able should not be bulky otherwise it will be costly to execute (performance + resource).
3) Try to include column(s) that has been already indexed. Otherwise, if you need to include such column(s) than better first you build some index(es) for them.
In your case you have two columns from the same table to be left joined to another table. So, in this case a good approach would be if you can have a single table with same column of required data as I have shown below:
; WITH Match AS
(
-- Select all required columns and alise the key column(s) as shown below
SELECT match1.*, match1.AwayTeam AS TeamId FROM stat.Matches match1
UNION
SELECT match2.*, match2.HomeTeam AS TeamId FROM stat.Matches match2
)
SELECT
*
FROM
stat.UniqueTeams uTeam
OUTER APPLY Match WHERE Match.TeamId = uTeam.Id
I have used OUTER APPLY which is almost similar to LEFT OUTER JOIN but it is different during query execution. It works as Table-Valued Function that can preform better in your case.
my answer is not to the point, but i found this question seeking for "or" condition for inner join, so it maybe be useful for the next seeker
we can use legacy syntax for case of inner join:
select *
from stat.UniqueTeams uTeam, stat.Matches match
where match.AwayTeam = uTeam.Id or match.HomeTeam = uTeam.id
note - this query has bad perfomance (cross join at first, then filter). but it can work with lot of conditions, and suitable for dirty data research(for example t1.id=t2.id or t1.name=t2.name)

which approach is best to get data from multiple tables

I have 2 tables and suppose having bulk of data
Table1 Table2
Id Name Address Id Table1Id Parents_Name Address
1 ABC 123ABC 1 1 DDD Xyz
. ... ...... . . ... ...
. ... ...... . . ... ...
Now if i want solution in below format
Id Name Parents_Name
1 ABC DDD
. ... ...
. ... ...
then which one will be best
Subquery or join
Joins and subqueries are both be used to query data from different tables and may even share the same query plan, but there are many differences between them. Knowing the differences and when to use either a join or subquery to search data from one or more tables is key to mastering SQL.
Joins and subqueries are both used to combine data from different tables into a single result. They share many similarities and differences.
Subqueries can be used to return either a scalar (single) value or a row set; whereas, joins are used to return rows.
A common use for a subquery may be to calculate a summary value for use in a query. For instance we can use a subquery to help us obtain all products have a greater than average product price.
SELECT ProductID,
Name,
ListPrice,
(SELECT AVG(ListPrice)
FROM Production.Product) AS AvgListPrice
FROM Production.Product
WHERE ListPrice > (SELECT AVG(ListPrice)
FROM Production.Product)
There are two subqueries in this SELECT statement. The first’s purpose is to display the average list price of all products, the second’s purpose is for filtering out products less than or equal to the average list price.
Subquery Free Video Offer
Here the subquery is returning a single value which is then used filter out products.
Notice how the subqueries are queries unto themselves. In this example you could paste the subquery, without the parenthesis, into a query window and run it.
Contrast this with a join whose main purpose of a join is to combine rows from one or more tables based on a match condition. For example we can use a join display product names and models.
Select Product.Name,
ProductModel.Name as ModelName
FROM Production.product
INNER JOIN Production.ProductModel
ON Product.ProductModelID = ProductModel.ProductModelID
In this statement we’re using an INNER JOIN to match rows from both the Product and ProductModel tables. Notice that the column ProducModel.Name is available for use throughout the query.
The combined row set is then available by the select statement for use to display, filter, or group by the columns.
This is different than the subquery. There the subquery returns a result, which is immediately used.
Note that join is an integral part of the select statement. It can not stand on its own as a subquery can.
A subquery is used to run a separate query from within the main query. In many cases the returned value is displayed as a column or used in a filter condition such as where or having clause. When a subquery incorporates a column from the main query it is said to be correlated. In this way a sub query is somewhat like a join in that values from two or more tables can be compared.
Joins are used in the FROM clause of the WHERE statement; however, you’ll find subqueries used in most clauses such as the:
SELECT List – here a subqueries used to return single values are used.
WHERE clause– depending on the conditional operator you’ll see single value or row based subqueries.
FROM clause– It is typical to see row based result subqueries used here.
HAVING clause – In my experience scalar (single value) subqueries are used here.
Though joins and subqueries have many differences, they can be used to solve similar problems. In fact just because you write a SQL statement as a subquery doesn’t mean the DBMS executes as such.
you can refer to this link for more details:-
http://www.essentialsql.com/what-is-the-difference-between-a-join-and-subquery/
Asuming you want an INNER JOIN:
SELECT t1.Id
,t1.Name
,t2.Parents_Name
FROM table1 t1
INNER JOIN table2 t2
ON t2.Table1Id = t1.Id
But you could also use an OUTER JOIN to always show rows from table1 and show the matching rows from table2.
SELECT t1.Id
,t1.Name
,t2.Parents_Name
FROM table1 t1
LEFT OUTER JOIN table2 t2
ON t2.Table1Id = t1.Id
You will want to use a join, which will almost certainly be much more efficient. A quick google with give you much more information than you need to learn about the different types of joins available and how to use them, such as https://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
Please create an index on the id of Table1 and Table1Id of Table2 and use this query.
Select t1.Id,
t1.Name,
t2.Parents_Name
from Table1 t1
inner join
Table2 t2 on t1.id=t2.Table1Id
IMHO, Join should be preferred considering query performance. Squbquery will require IN operator that is always a pain with bulk data. However it also depends in your indexing. Better you check both.

SQL FROM clause using n>1 tables

If you add more than one table to the FROM clause (in a query), how does this impact the result set? Does it first select from the first table then from the second and then create a union (i.e., only the rowspace is impacted?) or does it actually do something like a join (i.e., extend the column space)? And when you use multiple tables in the FROM clause, does the WHERE clause filter both sub-result-sets?
Specifying two tables in your FROM clause will execute a JOIN. You can then use the WHERE clause to specify your JOIN conditions. If you fail to do this, you will end-up with a Cartesian product (every row in the first table indiscriminately joined to every row in the second).
The code will look something like this:
SELECT a.*, b.*
FROM table1 a, table2 b
WHERE a.id = b.id
However, I always try to explicitly specify my JOINs (with JOIN and ON keywords). That makes it abundantly clear (for the next developer) as to what you're trying to do. Here's the same JOIN, but explicitly specified:
SELECT a.*, b.*
FROM table1 a
INNER JOIN table2 b ON b.id = a.id
Note that now I don't need a WHERE clause. This method also helps you avoid generating an inadvertent Cartesian product (if you happen to forget your WHERE clause), because the ON is specified explicitly.

Iterating 1 row at a time with massive amounts of links/joins

Ok, basically what is needed is a way to have row numbers while using a lot of joins and having where clauses using these rownumbers.
such as something like
select ADDRESS.ADDRESS FROM ADDRESS
INNER JOIN WORKHISTORY ON WORKHISTORY.ADDRESSRID=ADDRESS.ADDRESSRID
INNER JOIN PERSON ON PERSON.PERSONRID=WORKHISTORY.PERSONRID
WHERE PERSONRID=<some number> AND WORKHISTORY.ROWNUMBER=1
ROWNUMBER needs to be generated for this query on that one table though. So that if we want to access the second WORKHISTORY record's address, we could just go WORKHISTORY.ROWNUMBER=2 and if say we had two address's that matched, we could cycle through the addresses for one WORKHISTORY record using ADDRESS.ROWNUMBER=1 and ADDRESS.ROWNUMBER=2
This should be capable of being an automatically generated query. Thus, there could be more than 10 inner joins in order to get to the relevant table, and we need to be able to cycle through each table's record independently of the rest of the tables..
I'm aware there is the RANK and ROWNUMBER functions, but I'm not seeing how it will work for me because of all the inner joins
note: in this example query, ROWNUMBER should be automatically generated! It should never be stored in the actual table
Can you use a temp table?
I ask because you can write the code like this:
select a.field1, b.field2, c.field3, identity (int, 1,1) as TableRownumber into #temp
from table1 a
join table2 b on a.table1id = b.table1id
join table3 c on b.table2id = c.table2id
select * from #temp where ...

Resources