F# SqlDataConnection Type Provider query optimization - sql-server

I need some help with the optimization of a query with the F# SqlDataConnection Type Provider.
There is a table Items with the relations to 4 other tables:
Type - n : 1
SubItem1 - m : n
SubItem2 - m : n
SubItem3 - 1 : n
This is the Type Provider query code:
query {
for x in db.Items do
join t in db.ItemType on (x.Typy = t.Name)
select (x, t, x.ItemSubItem1, x.ItemSubItem2, x.SubItem3)
}
|> Seq.map toItem
It produces the following SQL statement:
SELECT [t0].[Id], [t0.Name], [t1].[Name], [t2].[ItemId], [t2].[SubItem1Id], (
SELECT COUNT(*)
FROM [dbo].[ItemSubItem1] AS [t3]
WHERE [t3].[ItemId] = [t0].[Id]
) AS [value]
FROM [dbo].[Item] AS [t0]
INNER JOIN [dbo].[ItemType] AS [t1] ON [t0].[Typ] = [t1].[Name]
LEFT OUTER JOIN [dbo].[ItemSubItem1] AS [t2] ON [t2].[ItemId] = [t0].[Id]
ORDER BY [t0].[Id], [t1].[Name], [t2].[SubItem1Id]
The problem is that only the Type and SubItems1 are joined. So when toItem is called for each entry in Items there will be 2 extra SQL queries generated to get SubItem2 and SubItem3. This is very inefficient.
Thanks for help!

Related

Combine MATCH clause and INNER JOIN in SQL Server graph database with mixed model

I have a some node and edge tables in SQL Server with a one to many relationship to a standard table which store users. Each edge and node table have this 1N relationship.
I would like to know how can I perform a query with match clause and a left join like this :
SELECT * FROM Node1Table n1, EdgeTable e, Node2Table n2
LEFT JOIN UserTable usr ON e.usr = usr.ID
MATCH (n1-(e)->n2)
I could write the query like this :
SELECT * FROM EdgeTable e
INNER JOIN Node1Table n1 ON e.$from_ID = n1.$node_ID
INNER JOIN Node2Table n2 ON e.$to_ID = n2.$node_ID
LEFT JOIN UserTable usr ON e.usr = usr.ID
But I don't know if n1 is from or to object.
I can't do an inner join because e.usr could be null
Thank you for your help
EDIT:
Test 1 :
SELECT * FROM
OBJ_APPLICATION n1, REL_APPLICATION_RESPONSABLE r INNER JOIN
Management_User u on u.[UserID] = r.[CPQ], OBJ_RESPONSABLE n2
WHERE MATCH(n1-(r)->n2)
error : The identifier "r" in a MATCH clause is used with a JOIN clause or an APPLY operator. JOIN and APPLY are not supported with MATCH clauses.
Test 2 :
SELECT * FROM
OBJ_APPLICATION n1, REL_APPLICATION_RESPONSABLE r, OBJ_RESPONSABLE n2
INNER JOIN Management_User u on u.[UserID] = r.[CPQ]
WHERE MATCH(n1-(r)->n2)
error : The multi-part identifier r.CPQ could not be bound
Test 3 :
SELECT * FROM
OBJ_APPLICATION n1, REL_APPLICATION_RESPONSABLE r, OBJ_RESPONSABLE n2, Management_User u
WHERE MATCH(n1-(r)->n2)
AND u.[UserID] = r.[CPQ]
Works with an INNER JOIN but in some cases I have to make a LEFT JOIN
Like Alex suggested, you can do a sub query. Below is a fully functioning query that I am actively working on.
SELECT
TokensConnectors.*
FROM
(
SELECT
leftWord.word As LeftSide,
MiddleWord.word AS MiddleWord,
DependsOn1.[DependencyType] As [DependencyType1],
DependsOn1.SentenceId
FROM
Pipeline.Words MiddleWord,
Pipeline.Words leftWord,
Pipeline.DependsOn DependsOn1
WHERE
MATCH(leftWord<-(DependsOn1)-MiddleWord)
AND leftWord.Word = 'differential'
and middleWord.word = 'diagnosis'
) AS DifferentialDiagnosis
INNER JOIN [Pipeline].[DependsOn] AS TokensConnectors ON TokensConnectors.[SentenceId] = DifferentialDiagnosis.SentenceId
Here is an example where I inner join Sentences, ClinicalNotes and DependsOn1. Think link is done in the Where statement.
SELECT
DependsOn1.SentenceId
FROM
Pipeline.Words RightWord,
Pipeline.Words LeftWord,
Pipeline.DependsOn DependsOn1,
Pipeline.Sentences,
Pipeline.ClinicalNotes
WHERE
MATCH(LeftWord<-(DependsOn1)-RightWord)
AND LeftWord.Word = 'differential'
and RightWord.word = 'diagnosis'
AND DependsOn1.SentenceId = Sentences.Id
AND ClinicalNotes.Id = Sentences.ClinicalNoteId
AND ClinicalNotes.ProcessingLogId = #processingLogIdessingLogId

SSIS merge join lacks row (and also How to simulate SSIS join with tsql query)

In my project I have a merge join transformation, that uses inner join. It is supposed to join the files lookup with the rest of the data flow. However, the join seems to not include some rows, with files, even though it should? I'm trying to simulate the join in tsql, but I seem to be doing it wrong as it shows me the missing rows.
Here are the outputs I'm trying to join
Input A:
SELECT *
FROM
tblExpense expense
OUTER APPLY(
SELECT TOP 1 *
FROM tblExpenseDtl Details
WHERE expense.intExpenseID = Details.intExpenseID
ORDER BY Details.sintLineNo
) details
WHERE
expense.dtUpdateDateTime > '2017-06-01'
ORDER BY expense.intExpenseID desc
Input B:
SELECT f.*
FROM dbo.tblExpense e
JOIN tblExpenseDtl d ON d.intExpenseID = e.intExpenseID
JOIN tblExpReceiptFile f ON f.intExpenseDtlID = d.intExpenseDtlID
WHERE
e.dtUpdateDateTime > '2017-06-01'
ORDER BY e.intExpenseID desc
And the sql query that I thought would produce the same result as my SSIS inner join
SELECT *
FROM
tblExpense expense
OUTER APPLY(
SELECT TOP 1 *
FROM tblExpenseDtl Details
WHERE expense.intExpenseID = Details.intExpenseID
ORDER BY Details.sintLineNo
) details
inner join ( SELECT f.*
FROM dbo.tblExpense e
JOIN tblExpenseDtl d ON d.intExpenseID = e.intExpenseID
JOIN tblExpReceiptFile f ON f.intExpenseDtlID = d.intExpenseDtlID
WHERE
e.dtUpdateDateTime > '2017-06-01'
ORDER BY e.intExpenseID desc
) innerJ
WHERE
expense.dtUpdateDateTime > '2017-06-01'
ORDER BY expense.intExpenseID desc
The join key in the SSIS is the expense.intExpenseID = e.intExpenseID.
Input A gives 1 row, with an expenseID=X, and input B gives 2 rows with an expenseID=X
How are you sorting data before merging it? According to this SSIS is sorting in different way than SQL Server (in most cases). Maybe there is a problem.
Edit: What type is intExpenseID?

How to combine my three query?

I have 3 query to find my data. But i can't combine to 1 query and get my data. what should I do with my query? please help me, thanks.
SELECT distinct pk_pgw_master, fk_kelas, rombel, pk_matpel, nama_rombel as wali_kelas, null as row_group
FROM pgw_master
LEFT JOIN akd_program_ajar ON pgw_master.pk_pgw_master = akd_program_ajar.fk_pgw_master
LEFT JOIN akd_matpel ON akd_program_ajar.fk_matpel = akd_matpel.pk_matpel
LEFT JOIN akd_pengajar ON pgw_master.pk_pgw_master = akd_pengajar.fk_pgw_master
LEFT JOIN akd_wali_kelas ON akd_pengajar.pk_pengajar = akd_wali_kelas.fk_pengajar
LEFT JOIN akd_akademisi ON akd_akademisi.kode_rombel = akd_program_ajar.rombel
WHERE pk_pgw_master = 'pgw050'
second query :
SELECT count(pk_kompetensi_dasar) as jml_kd FROM akd_kompetensi_dasar where fk_mapel='MP1610004' and fk_kelas='2'
3rd query :
SELECT count(pk_akademisi) as jumlah_siswa FROM akd_akademisi where kode_rombel='XI TPTL 1'
this is three result from 3 query
how can I get 1 result?
You can aliasing all queries and Selecting them in the select query.
SELECT x.a, y.b z.c FROM (SELECT * from a) as x, (SELECT * FROM b) as y ,(SELECT * FROM c) as z
Link to sql fiddle to test your query

Recursive query SQL Server not working as expected

thanks in advance for you help. I'm still quite new to MS SQL db but I was wondering why my recursive query for MSSQL below does not return the value i'm expecting. I've done my research and at the bottom is the code I came up with. Lets say I have the following table...
CategoryID ParentID SomeName
1 0 hmm
2 0 err
3 0 woo
4 3 ppp
5 4 ttt
I'm expecting the query below to return 3 4 5. I basically wanted to get the list of category id's heirarchy below it self inclusive based on the category id I pass in the recursive query. Thanks for you assistance.
GO
WITH RecursiveQuery (CategoryID)
AS
(
-- Anchor member definition
SELECT a.CategoryID
FROM [SomeDB].[dbo].[SomeTable] AS a
WHERE a.ParentID = CategoryID
UNION ALL
-- Recursive member definition
SELECT b.CategoryID
FROM [SomeDB].[dbo].[SomeTable] AS b
INNER JOIN RecursiveQuery AS d
ON d.CategoryID = b.ParentID
)
-- Statement that executes the CTE
SELECT o.CategoryID
FROM [SomeDB].[dbo].[SomeTable] AS o
INNER JOIN RecursiveQuery AS d
ON d.CategoryID = 3
GO
If you want tree from specific root:
DECLARE #rootCatID int = 3
;WITH LessonsTree (CatID)
AS
(
SELECT a.CategoryID
FROM [EducationDatabase].[dbo].[LessonCategory] AS a
WHERE a.CategoryID = #rootCatID ---<<<
UNION ALL
SELECT b.CategoryID
FROM LessonsTree as t
INNER JOIN [EducationDatabase].[dbo].[LessonCategory] AS b
ON b.ParentID = t.CatID
)
SELECT o.*
FROM LessonsTree t
INNER JOIN [EducationDatabase].[dbo].[LessonCategory] AS o
ON o.CategoryID = t.CatID
As stated in the comments, the anchor isn't restricted. Easiest solution is to add the criterium in the anchor
with RecursiveQuery (theID)
AS
(
SELECT a.ParentID --root id=parentid to include it and to prevent an extra trip to LessonCategory afterwards
FROM [LessonCategory] AS a
WHERE a.ParentID = 3 --restriction here
UNION ALL
SELECT b.CategoryID
FROM [LessonCategory] AS b
INNER JOIN RecursiveQuery AS d
ON d.theID = b.ParentID
)
SELECT* from RecursiveQuery
Another option is to have the recursive query be general (no restricted anchor) and have it keep the rootid as well. Then the query on the cte can restrict on the rootid (the first option is probably better, this second one is mainly suitable if you are created some sort of root-view)
with RecursiveQuery
AS
(
SELECT a.ParentID theID, a.ParentID RootID
FROM [LessonCategory] AS a
UNION ALL
SELECT b.CategoryID, d.RootID
FROM [LessonCategory] AS b
INNER JOIN RecursiveQuery AS d
ON d.theID = b.ParentID
)
SELECT theID from RecursiveQuery where RootID = 3

SQL mutliple count

Could you explain how I get this particular table result?
My 4 queries to individually get each column separately are also below.
I am not sure on method here do I nest the last 3 queries into the first or do I use a union between the queries.
Bearing in mind that the information in each one doesn't really match I assume Union or Union All isn't going to be useful.
Would a derived table be a better method. Sorry my SQL skills are fairly basic.
I need to also retain the ability to 'tweak' the where clauses as my admin decides to exclude certain records later (you IT folks will be used to that!)
Some the ability to alter the where clauses would be good in a solution.
Just to make it more annoying for ya ;-)
Query table would need to look a little like this
Company Department Total_B Total_R Total_Ret RushJobs
ACME LSD 2 100 24 3
The four queries (that work separately to get each column above are here ( I have left in the respective Group By and where clauses incidentally I_Department does map to just Department in the case of 2nd query.
-- Total B count query from B
Select Company,Department, count(*) as Total_B from B
Group by Company,Department
Order BY Company;
--Select h count from h table
Select count(*) as Total_R, I_Department from H
where L ='re-box'
Group By IDepartment
-- Select r count
Select Company,Department,Count (B_Number) AS Total_Ret
from P Inner Join B ON P.Record_Number = B.B_Number
where P.Request_Date > = 'SOMEDATE' and P.Request_Date < = 'SOMEDATERANGE'
Group By Company,Department
-- Select Rush Jobs
Select Company,Department,Count (*) as RushJobs
from Res
Inner Join B on Res.Item_Number = B.B_Number
where Res.Setup_Date >= 'Somedate' and Res.Setup_Date<= 'somedaterange'
and Res.Res_Priority = '1'
Group By Company,Department
So final table
<table><TBODY>
<TR>
<TH>Company</TH>
<TH>Department</TH>
<TH>Total_B</TH>
<TH>Total_R </TH>
<TH>Total_Ret</TH>
<TH>RushJobs</TH></TR>
<TR>
<TD>ACME</TD>
<TD>LSD</TD>
<TD>100</TD>
<TD>2</TD>
<TD>4</TD>
<TD>1</TD></TR></TBODY></table>
One approach would be to use a Common table expression (CTE) aka with statement..
This allows each query to continue to be independent allowing you to easily twerk (I was going to correct that typo but it was just too funny) the where clauses for each and combines the results in the end returning 1 record with 4 columns.
-- Total B count query from B
With B as (
Select Company,Department, count(*) as Total_B from B
Group by Company,Department
Order BY Company),
H as (
--Select h count from h table
Select count(*) as Total_R, I_Department from H
where L ='re-box'
Group By IDepartment),
R as (-- Select r count
Select Company,Department,Count (B_Number) AS Total_Ret
from P Inner Join B ON P.Record_Number = B.B_Number
where P.Request_Date > = 'SOMEDATE' and P.Request_Date < = 'SOMEDATERANGE'
Group By Company,Department),
RushJobs as (-- Select Rush Jobs
Select Company,Department,Count (*) as RushJobs
from Res
Inner Join B on Res.Item_Number = B.B_Number
where Res.Setup_Date >= 'Somedate' and Res.Setup_Date<= 'somedaterange'
and Res.Res_Priority = '1'
Group By Company,Department)
SELECT coalesce(B.Company, R.Company, RJ.Company)
, coalesce(B.Department,R.Department, Rj.Department)
, B.Total_B, H.Total_R, R.Total_Ret, RJ.RushJobs
FROM
FULL OUTER JOIN H
on B.Company = H.Company
FULL OUTER JOIN R
on B.company = R.Company
and B.Department = R.Department
FULL OUTER JOIN RushJobs RJ
on H.company = RJ.Company
and H.Department = RJ.Department

Resources