How can I filter on attributes from a linked entity, outside of LinkEntity? - dynamics-crm-4

I'd like to make a complex query, I don't care about it being fetchXML or queryexpression, as long as it works :-)
I want to create either a query with a NOT IN(select from) structure, or its equivalent LEFT OUTER JOIN using a WHERE IS NULL.
The query is something like this:
SELECT t1.*
FROM table1 t1
LEFT OUTER JOIN table2 t2 ON t1.xid = t2.id
WHERE t2.id IS NULL
(query structure with an example: http://blog.sqlauthority.com/2008/04/22/sql-server-better-performance-left-join-or-not-in/)
As you can see, the tricky bit is "t2.id" in the where-clause. I have found no way to filter on this value using any tools or docs. Is it even possible?

This is one of the things that are not possible with CRM queries. There are (not necessarily workable) alternatives:
Retrieve the relevant values from t2 and query t1 using ConditionOperator.NotIn (in case NotIn is actually supported; not all available ConditionOperator values can really be handled by the CrmService).
Fully retrieve both tables and join them in memory (using LINQ or the like).
Do the actual join via SQL (which of course requires direct database access), return just the IDs and retrieve the result via the CrmService.

Related

SQL transform id and add where statement before join

I am pretty new to SQL. Here is an operation I am sure is simple for a lot of you. I am trying to join two tables across databases on the same server – dbB and dbA, and TableA (with IdA) and TableB (with IdB) respectively. But before doing that I want to transform column IdA into a number, where I would like to remove the “:XYZ” character from its values and add a where statement for another column in dbA too. Below I show my code for the join but I am not sure how to convert the values of the column. This allows me to match idAwith idB in the join. Thanks a ton in advance.
Select replace(idA, “:XYZ”, "")
from dbA.TableA guid
where event like “%2015”
left join dbB.TableB own
on guid.idA = own.idB
Few things
FROM, Joins, WHERE (unless you use subqueries) syntax order it's also the order of execution (notice select isn't listed as its near the end in order of operation but first syntactically!)
alias/fully qualify columns when multiple tables are involved so we know what field comes from what table.
order of operations has the SQL doing the from and JOINS 1st thus what you do in the select isn't available (not in scope yet) for the compiler, this is why you can't use select column aliases in the from, where or even group by as well.
I don't like Select * usually but as I don't know what columns you really need... I used it here.
As far as where before the join. most SQL compilers anymore use cost based optimization and figure out the best execution plan given your data tables and what not involved. So just put the limiting criteria in the where in this case since it's limiting the left table of the left join. If you needed to limit data on the right table of a left join, you'd put the limit on the join criteria; thus allowing it to filter as it joins.
probably need to cast IDA as integer (or to the same type as IDB) I used trim to eliminate spaces but if there are other non-display characters, you'd have issues with the left join matching)
.
SELECT guild.*, own.*
FROM dbA.TableA guid
LEFT JOIN dbB.TableB own
on cast(trim(replace(guid.idA, ':XYZ', '')) as int) = own.idB
WHERE guid.event like '%2015'
Or materialize the transformation first by using a subquery so IDA in its transformed state before the join (like algebra ()'s matter and get processed inside out)
SELECT *
FROM (SELECT cast(trim(replace(guid.idA, ':XYZ', '')) as int) as idA
FROM dbA.TableA guid
WHERE guid.event like '%2015') B
LEFT JOIN dbB.TableB own
on B.IDA = own.idB

Case statement in LEFT OUTER JOIN slowing the query in SQL Server 2008

I am getting a problem with my LEFT OUTER JOIN. I have a set of queries which gives me about 80,000 to 1,00000 records in a #Temp Table. Now when I LEFT OUTER JOIN this #Temp table with another table I have to put a CASE statement i.e. if the records are not found when joining with a particular column then take that particular column value and find its subsequent value in another table which has the matching records. The query is working fine for a particular data but for larger data it just goes on executing or just takes too much time. My query is like:
SELECT * FROM #Temp
LEFT OUTER JOIN TABLE1 ON #Temp.Materialcode =
CASE WHEN TABLE1.MaterialCode LIKE 'HY%'
THEN TABLE1.MaterialCode
ELSE REPLACE(TABLE1.MaterialCode,
TABLE1.MaterialCode,
(SELECT NewMaterialCode
FROM TABLE2
WHERE OldMaterialCode = TABLE1.MaterialCode))
END
Here TABLE2 has got only two columns NewMaterialCode and OldMetarialCode. What I have to do is if the Material Code is not found in TABLE1 LIKE 'HY%' type then it should take that material code and look for its subsequent NewMaterialCode in TABLE2 to get both types of records having 'HY' type and non 'HY' type. I think I made my problem clear. Any help would be greatly appreciated.
SELECT *
FROM #TEMP TMP
LEFT JOIN Table1 MATERIAL
ON TMP.MaterialCode = MATERIAL.MaterialCode
LEFT JOIN Table2 REPLACEMENT
ON MATERIAL.MaterialCode = REPLACEMENT.OldMaterialCode
WHERE ( COALESCE(MATERIAL.materialcode, '') LIKE 'HY%'
AND TMP.materialCode = MATERIAL.MaterialCode
)
OR MATERIAL.MaterialCode = REPLACEMENT.NewMaterialCode
I think this should do what you're trying to do, but I don't really know how the tables are related except by reverse-engineering your query.
For the record, the OUTER JOIN in your query isn't accomplishing a thing, because an outer condition would product null values for the columns in TABLE1, and the case condition wouldn't work (a NULL would be neither a match for 'HY%' nor an ELSE). That's counter-intuitive to those not used to working in the three-valued logic of the database world, but that's why we have COALESCE and ISNULL.

Is there a way to join an integer to a string, that always contains an integer, in Microsoft Access

In Microsoft Access, I have two linked tables which I can't change the structure of.
One of these tables contains an ID in integer format, the other contains the same ID, but in string format.
I want to join on these fields, but, obviously, MS Access isn't letting me.
Is there a way, possibly using casting or something similar to create this join?
Thanks
If ID is autonumber in t1 and text in t2, you can use CLng() in the ON expression to transform t2.ID to long integer.
SELECT *
FROM
t1 INNER JOIN t2
ON t1.ID = CLng(t2.ID);
Or you could use Val() instead of CLng() for other ID numeric types.
I'm not sure how well the query designer will cooperate with this in Design View, but you can do it in SQL View.
OTOH, you may prefer to create a separate query, "qryT2", for t2 which transforms the text ID to numeric.
SELECT CLng(ID) AS numeric_ID, t2.*
FROM t2;
Then you could substitute qryT2 for t2 in the first query, and have one which the query designer finds to be more congenial.
SELECT *
FROM
t1 INNER JOIN qryT2
ON t1.ID = qryT2.numeric_ID;
Go to the View > SQL View in the designer, and change your join clause to:
ON CSTR(IntegerID) = StringID
Of course, your ID names may vary, but you should ge the idea.

Streaming SQL Server 2008 Recursive CTEs

I have a set of data from a table (TableA) which relates to itself through TableB. Parents in TableA have children in TableA. Those children might also have children. Nothing amazing here.
I have a top-level set of rows from TableA that I need to operate on. Before I can operate on those rows, I must have each child row on hand. I must be able to operate on each top-level row of TableA (and it's children) as fast as possible in my application.
I can't find a way to do this.
Using a recursive CTE (TableA top-level set as anchor, TableB->TableA join as union), does not fulfill the requirements. The entire top-level set from TableA is returned in the CTE before it works on level 2 of the children. Then it works on level 3. Then level 4, etc. Since my top-level set is some 400,000 plus rows, my client application cannot begin working on rows until the ENTIRE dataset has been batched up on the server.
I need a better way to do this. I've tried streaming a flat set of top-level TableA rows to the client, and having the client issue the recursive CTE statement repeatedly for each top-level TableA row. This actually works. But there's too much noise. The sustained row retrieval rate is too large due to the repeated reissuing of statements.
I need a creative solution.
Snippet of the per-record CTE I'm using. In this example, TableA is Member, and TableB is MemberReplacement. I ripped out most of the select statement in the middle, and most of the joins.
WITH T_MemberRecurse
(
MemberId,
IncludedMemberId,
Level
) AS (
SELECT Member.Id,
Member.Id,
0
FROM MemberInput
INNER JOIN MemberInputItem
ON MemberInputItem.MemberInputId = MemberInput.Id
INNER JOIN Member
ON Member.Id = MemberInputItem.MemberId
UNION ALL
SELECT T_MemberRecurse.MemberId,
Member2.Id,
Level + 1
FROM T_MemberRecurse
INNER JOIN Member
ON Member.Id = T_MemberRecurse.IncludedMemberId
INNER JOIN MemberReplacement
ON MemberReplacement.MemberId = Member.Id
INNER JOIN Member Member2
ON Member2.Id = MemberReplacement.OriginalMemberId
)
SELECT Member.Id,
T_MemberRecurse.IncludedMemberId,
T_MemberRecurse.Level,
FROM MemberInput
INNER JOIN LotsOfTables
I'm thinking about this a bit right now, but first a stab in the dark that could help, due to experiences I've had with linked servers where forcing row-by-row operations improved performance by 2 orders of magnitude.
Turn your CTE into a rowset-returning function with one parameter, the desired Member Id.
Then:
SELECT
*
FROM
Member M
CROSS APPLY dbo.MemberChildren(M.Id) C
WHERE
{Conditions for desired set of Members here}
WITH (FAST 20);
Please let me know if this works. The idea is to force the engine to traverse deep-first rather than wide-first. It might be lower overall server performance, but theoretically should let your client begin working with some rows of data.
Update
Second idea: get the parent and child information separately and perform, logically, a merge join in the client. (An ordered nested loop that only advances the ordered second/inner input until it mismatches.) Get smaller chunks at once using key ranges or row_number. Or get the entire parent set then get smaller set of child rows.
Update 2
Idea 3: Instead of a recursive CTE, use 5 plain vanilla joins to get all the data you need. It sounds awful, but should let you do FAST 100 to get started on the data.

MySQL JOIN based on dynamic LIKE statement between multiple tables

I have a table called faq. This table consists from fields faq_id,faq_subject.
I have another table called article which consists of article_id,ticket_id,a_body and which stores articles in a specific ticket. Naturally there is also a table "ticket" with fields ticket_id,ticket_number.
I want to retrieve a result table in format:
ticket_number,faq_id,faq_subject.
In order to do this I need to search for faq_id in the article.a_body field using %LIKE% statement.
My question is, how can I do this dynamically such that I return with SQL one result table, which is in format ticket_number,faq_id,faq_subject.
I tried multiple configurations of UNION ALL, LEFT JOIN, LEFT OUTER JOIN statements, but they all return either too many rows, or have different problems.
Is this even possible with MySQL, and is it possible to write an SQL statement which includes #variables and can take care of this?
First off, that kind of a design is problematic. You have certain data embedded within another column, which is going to cause logic as well as performance problems (since you can't index the a_body in such a way that it will help the JOIN). If this is a one-time thing then that's one issue, but otherwise you're going to have problems with this design.
Second, consider this example: You're searching for faq_id #123. You have an article that includes faq_id 4123. You're going to end up with a false match there. You can embed the faq_id values in the text with some sort of mark-up (for example, [faq_id:123]), but at that point you might as well be saving them off in another table as well.
The following query should work (I think that MySQL supports CAST, if not then you might need to adjust that).
SELECT
T.ticket_number,
F.faq_id,
F.faq_subject
FROM
Articles A
INNER JOIN FAQs F ON
A.a_body LIKE CONCAT('%', F.faq_id, '%')
INNER JOIN Tickets T ON
T.ticket_id = A.ticket_id
EDIT: Corrected to use CONCAT
SELECT DISTINCT t.ticket_number, f.faq_id, f.faq_subject
FROM faq.f
INNER JOIN article a ON (a.a_body RLIKE CONCAT('faq_id: ',faq_id))
INNER JOIN ticket t ON (t.ticket_id = a.ticket_id)
WHERE somecriteria