Use columns from select statement as parameter in function when joining [duplicate] - sql-server

This question already has an answer here:
pass parameter in table valued function using select statement
(1 answer)
Closed 7 years ago.
Consider the following sql query:
SELECT TaskId,FromItemId, IHV_FROM.NodePath as FromPath
FROM VIEW_TASKS with (nolock)
left Join fn_ITEM_HIERARCHY(FromItemId) IHV_FROM ON FromItemId = IHV_FROM.ItemId
WHERE ...
fn_ITEM_HIERARCHY is a function which takes one input parameter. I would like to use FromItemId from VIEW_TASKS as input parameter to the function.
When doing it like above, i get the error (Microsoft SQL Server 2008) "Invalid column name".
The SELECT statement returns multiple values, so it is not possible to assign the value to a variable in a separate select statement. Any ideas?

You probably need to use OUTER APPLY in this case:
SELECT TaskId,FromItemId, IHV_FROM.NodePath as FromPath
FROM VIEW_TASKS with (nolock)
OUTER APPLY fn_ITEM_HIERARCHY(FromItemId) IHV_FROM
WHERE ...
;
If the function always returns rows or if you only want results for values where the function does return rows, use CROSS APPLY instead.

Use Cross apply as shown here
http://blog.sqlauthority.com/2008/01/03/sql-server-2005-last-ran-query-recently-ran-query/

use alias
SELECT t.TaskId, t.FromItemId, IHV_FROM.NodePath as FromPath
FROM VIEW_TASKS t with (nolock)
left Join fn_ITEM_HIERARCHY(FromItemId) IHV_FROM ON t.FromItemId = IHV_FROM.ItemId

use OUTER APPLY instead of left join

Related

How to use a table valued function in select clause?

I have a tableA with one of the string columns (rawData) and I have a table-valued function (functionA) that functions will accept 'rawData' as an input parameter and returns five new fields. what will that function do? - this will do some string manipulation and split some data into five values
My motive is to select that string column (rawData) and also pass that table-valued function (functionA) and get those five new fields for every row in tableA
Here is the sample:
Select
(Select * from function (rawData))
from tableA
my expectations are I should get every row with that values from functionA along with rawData, but I'm getting below error:
Only one expression can be specified in the select list when the
subquery is not introduced with EXISTS.
How do I achieve this?
You would use a CROSS APPLY:
SELECT a.rawData, b.*
FROM TableA a
CROSS APPLY FunctionA(a.rawdata) b
Okay, first off, let's examine why you are getting an error. What is wrong with your syntax?
Well, a subquery in the select clause is expected to return at most one column. Your subquery, by using *, is returning all of the columns from the results of your function call, which appears to be more than one in this case.
Next, what are you trying to accomplish? It looks like you are trying to take the value of a column from tableA and apply functionA to the value in that column for each row returned from tableA.
The proper syntax to accomplish that is by using an apply. There is both cross apply and outer apply. The difference between them is like the difference between an inner join and a left join (or left outer join).
In other words, for the cross apply, if no rows are returned from the call to functionA for a particular row from tableA, then that row from tableA will not be included. For the outer apply, that case would be reversed, as the row from tableA would still be included, just the columns from the function call would be null.
An example query with this syntax based on the query in your question would be the following:
select fa.*
from tableA ta
outer apply functionA(ta.rawData) fa;
Note that I used an outer apply in my example, since your query didn't seem to be expecting rows from tableA with no rows returned from functionA to be excluded.

Using WITH CTE in IF NOT EXISTS [duplicate]

This question already has answers here:
Using IF EXISTS with a CTE
(5 answers)
Closed 5 years ago.
I have a table-valued function that selects rows as part of a CTE, and I then want to perform a different select/insert into the returned table if no rows were selected in the CTE:
WITH myCte AS (SELECT * FROM abc WHERE xyz = 123)
IF NOT EXISTS (SELECT * FROM myCte)
BEGIN
...
END
However I'm getting a syntax error whenever I go to use CTE tables in the NOT EXISTS condition. My myCte is a lot more complex than the example, so it will be awkward to place the whole query in the condition.
How can I use the CTE result in the condition check?
You need to declare your common table expression in the context where it will be used and it can only be used for the statement that follows with. If you want to use the results multiple times, you can either repeat the common table expression multiple times, or you can use a table variable or temporary table to hold the results instead.
WITH myCte AS (SELECT * FROM abc WHERE xyz = 123)
select *
into #myTempTable
from myCte
IF NOT EXISTS (SELECT * FROM #myTempTable)
BEGIN
...
END

How to use 'string to table splitting' using a function in a query?

First query with my function
select *
from [dbo].fnSplitString('1|16|170','|')
Second query with data to split
select m.CategoryTree as s
from tblBuyOnlineMaster m
I want to join these two query to get all the categories from second query like a table column, like the first result
Help will be very useful.
Assuming your function fnSplitString is a table-valued function, you can use the cross apply operator to perform the correlated "join":
select *
from tblBuyOnlineMaster m
cross apply [dbo].fnSplitString(m.CategoryTree, '|') s
Note the cross apply operator is congruent to an inner join. If you want left join semantics, use the outer apply operator instead. See also https://technet.microsoft.com/en-us/library/ms175156%28v=sql.105%29.aspx?f=255&MSPPError=-2147217396 .

CROSS APPLY with table valued function restriction performance

I have problem with CROSS APPLY with parametrised table valued function.
Here is simplified pseudo code example:
SELECT *
FROM (
SELECT lor.*
FROM LOT_OF_ROWS_TABLE lor
WHERE ...
) AS lor
CROSS APPLY dbo.HeavyTableValuedFunction(lor.ID) AS htvf
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID
WHERE ...
Inner select on table LOT_OF_ROWS_TABLE is returning many rows.
Joining tables LOT_OF_ROWS_TABLE and ANOTHER_TABLE returns only one or few rows.
Table valued function is very time consuming and when calling for a lot of
rows the select lasts very long time.
My problem:
The function is called for all rows returned from LOT_OF_ROWS_TABLE regardless of the fact that the data will be limited when just join ANOTHER_TABLE.
The select has to be in the shown format - it is generated and in fact it is much more dificult.
When I try to rewrite it, it can be very fast, but it cannot be rewritten like this:
SELECT *
FROM (
SELECT lor.*
FROM LOT_OF_ROWS_TABLE lor
WHERE ...
) AS lor
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID
CROSS APPLY dbo.HeavyTableValuedFunction(at.ID) AS htvf
WHERE ...
I'd like to know:
Is there any setting or hint or something that forces select to call function only for finally restricted rows?
Thank you.
EDIT:
The table valued function is very complex: http://pastebin.com/w6azRvxR.
The select we are talking about is "user configured" and generated: http://pastebin.com/bFbanY2n.
you can divide this query into 2 parts use either table variable or temp table
SELECT lor.*,at.* into #tempresult
FROM (
SELECT lor.*
FROM LOT_OF_ROWS_TABLE lor
WHERE ...
) lor
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID
WHERE ...
now do the time consuming part which is table valued function right
SELECT * FROM #tempresult
CROSS APPLY dbo.HeavyTableValuedFunction(#tempresult.ID) AS htvf
I believe this is what you are looking for.
Plan Forcing Scenario: Create a Plan Guide to Force a Plan Obtained from a Rewritten Query
Basically it describes re-writing the query to get a generated plan using the correct order of joins. Then saving off that plan and forcing your existing query (that does not get changed) to use the plan you saved off.
The BOL link I put in even gives a specific example of re-writing the query putting the joins in a different order and using a FORCE ORDER hint. Then using sp_create_plan_guild to take the plan from the re-written query and use it on the original query.
YES and NO... it's hard to interprit what you're trying to achieve without sample data IN and result OUT, to compare outcomes.
I'd like to know:
Is there any setting or hint or something that forces select to call
function only for finally restricted rows?
So I'll answer your question above (3 years later!!) directly, with a direct statement:
You need to learn about CTE and the difference between CROSS APPLY
compared to INNER JOIN and why using CROSS APPLY in your case is
necessary. You "could" take the code in your function and apply it
into a single SQL statement using CTE.
ie:
Read this and this.
Essentially, something like this...
WITH t2o AS
(
SELECT t2.*, ROW_NUMBER() OVER (PARTITION BY t1_id ORDER BY rank) AS rn
FROM t2
)
SELECT t1.*, t2o.*
FROM t1
INNER JOIN
t2o
ON t2o.t1_id = t1.id
AND t2o.rn <= 3
Apply your query to extrapolate the date you want ONCE, and using CTE, then apply your second SQL using the CROSS APPLY.
You have no choice. You cannot do what you're trying to do in ONE SQL.

Call TVF on every record of a table and concat results

I thought that must be obvious but I can't figure it out.
Say there is a table tblData with a column ID and a table-valued-function (_tvf) that takes an ID as parameter. I need the results for all ID's in tblData.
But:
SELECT * FROM tblData data
INNER JOIN dbo._tvf(data.ID) AS tvfData
ON data.ID = tvfData.ID
gives me an error: The multi-part identifier "data.ID" could not be bound
What is the correct way to pass all ID's to this TVF and concat the results?
Thanks
I think you might need to use CROSS APPLY instead of an inner join here:
SELECT *
FROM dbo.tblData data
CROSS APPLY dbo._tvf(data.ID) AS tvfData
This will call the TVF function for each data.ID of the base table and join the results to the base table's columns.
See ressources here:
Using CROSS APPLY in SQL Server
Understanding APPLY clause in SQL Server
Using T-SQL CROSS APPLY and OUTER APPLY

Resources