How to select multiple many to many in relation with a single table - sql

I'm currently working with database, but I've got stuck with a select query.
However, I'm not database expert.
The query should return the data from a table that has two relationships of many to many.
This is my tables Diagram that would shows the concept of my question
The Select Query should View three columns, which are VidTbl.Name, ActorTbl.Name and SubTitelTbl.name.
So, I've read and search in the Internet and I've given tries
First try
SELECT
VidTbl.NAME AS Video_Titel_Name,
ActorTbl.NAME AS Actor_Name
FROM ActorInVid
INNER JOIN VidTbl
ON VidTbl.Id = ActorInVid.FKVidId
INNER JOIN ActorTbl
ON ActorTbl.Id = ActorInVid.FKActorId
UNION all
SELECT
VidTbl.NAME AS Video_Titel_Name,
SubTitelTbl.NAME AS SubTitel_Langu
FROM SubTitelInVid
INNER JOIN VidTbl
ON VidTbl.Id = SubTitelInVid.FKVidId
INNER JOIN SubTitelTbl
ON SubTitelTbl.Id = SubTitelInVid.FKSTId
The Result I've got, it was wrong
Then I tried another way to solve this problem, but again I've got another error
second try
SELECT Temp1.*
From (SELECT VidTbl.Id AS Video_Id,
VidTbl.NAME AS Video_Titel_Name,
ActorTbl.NAME AS Actor_Name
FROM ActorInVid
INNER JOIN VidTbl
ON VidTbl.Id = ActorInVid.FKVidId
INNER JOIN ActorTbl
ON ActorTbl.Id = ActorInVid.FKActorId) AS Temp1
SELECT Temp2.*
FROM (SELECT VidTbl.Id AS Video_Id,
SubTitelTbl.NAME AS SubTitel_Langu
FROM SubTitelInVid
INNER JOIN VidTbl
ON VidTbl.Id = SubTitelInVid.FKVidId
INNER JOIN SubTitelTbl
ON SubTitelTbl.Id = SubTitelInVid.FKSTId) AS Temp2
SELECT *
FROM VidTbl
INNER JOIN Temp1
on Temp1.Video_Id = VidTbl.Id
INNER JOIN Temp2
on Temp2.Video_Id = VidTbl.Id
The error, I've got in the last select that was wrong
Thanks a lot for your help any ways
I wish that my question is clear and useful
Thanks again.

You are close. This should work...
SELECT
VidTbl.Name,
ActorTbl.Name,
SubTitelTbl.name
FROM VidTbl
INNER JOIN ActorInVid ON VidTbl.Id = ActorInVid.FKVidId
INNER JOIN ActorTbl ON ActorTbl.Id = ActorInVid.FKActorId
INNER JOIN SubTitelInVid ON VidTbl.Id = SubTitelInVid.FKVidId
INNER JOIN SubTitelTbl ON SubTitelTbl.Id = SubTitelInVid.FKSTId

SELECT DISTINCT vt.Name, at.Name, st.Name
FROM VidTbl vt
JOIN ActionInVid aiv ON aiv.VidId = vt.Id
JOIN SubtitleInVid siv ON siv.VidId = vt.Id
JOIN ActorTbl at ON at.Id = aiv.ActorId
JOIN SubTitleTbl st ON st.Id = siv.STId

Related

Optimising SQL Query with multiple joins, reducing query speed

I'd like some advice on how to optimize the code below. I have attached the relationship of table above, any feedback or direction you could point me to will be appreciated.
The current query seems to be taking quite long to process.
SELECT CUSTINVOICETRANS.INVENTTRANSID, CUSTINVOICETRANS.INVOICEDATE, CUSTINVOICETRANS.INVOICEID, CUSTINVOICETRANS.ITEMID, CUSTINVOICETRANS.LINEAMOUNT, CUSTINVOICETRANS.LINEAMOUNTTAX, CUSTINVOICETRANS.ORIGSALESID, CUSTINVOICETRANS.QTY, CUSTINVOICETRANS.SUMLINEDISC, CUSTINVOICEJOUR.CUSTGROUP, CUSTINVOICEJOUR.INVOICEACCOUNT, CUSTINVOICEJOUR.SALESID, SALESTABLE.VCORDERMODE, SALESTABLE.VCORDERRT, VCSALESTABLEINFO.RCVDATE, VCSALESTABLEINFO.SHPCSTMCD, VCSALESTABLEINFO.VCORIGINALINVOICEDATE, SALESLINE.DATAAREADID, SALESLINE.INVENTTRANSID, VCSALESLINEINFO.RLLINEID
FROM CUSTINVOICETRANS
INNER JOIN CUSTINVOICEJOUR
ON CUSTINVOICETRANS.INVOICEID = CUSTINVOICEJOUR.INVOICEID
AND CUSTINVOICETRANS.INVOICEDATE = CUSTINVOICEJOUR.INVOICEDATE
AND CUSTINVOICETRANS.INVOICEDATE>=DATEADD(DAY,-7,GETDATE())
INNER JOIN SALESTABLE
ON CUSTINVOICETRANS.ORIGSALESID = SALESTABLE.SALESID
AND CUSTINVOICETRANS.INVOICEDATE>=DATEADD(DAY,-7,GETDATE())
INNER JOIN VCSALESTABLEINFO
ON CUSTINVOICETRANS.ORIGSALESID = VCSALESTABLEINFO.SALESID
AND CUSTINVOICETRANS.INVOICEDATE>=DATEADD(DAY,-7,GETDATE())
INNER JOIN SALESLINE
ON CUSTINVOICETRANS.ORIGSALESID = SALESLINE.SALESID
AND CUSTINVOICETRANS.INVOICEDATE>=DATEADD(DAY,-7,GETDATE())
INNER JOIN VCSALESLINEINFO
ON SALESLINE.INVENTTRANSID = VCSALESLINEINFO.INVENTTRANSID```
You can use cte to filter first your customer invoice transactions before joining other tables.
WITH cte as
(
SELECT INVENTTRANSID, INVOICEDATE, INVOICEID
, ITEMID, LINEAMOUNT, LINEAMOUNTTAX
, ORIGSALESID, QTY, SUMLINEDISC
FROM CUSTINVOICETRANS WHERE INVOICEDATE>=DATEADD(DAY,-7,GETDATE())
)
SELECT t1.*, t2.CUSTGROUP, t2.INVOICEACCOUNT, t2.SALESID
, t3.VCORDERMODE, t3.VCORDERRT
, t4.RCVDATE, t4.SHPCSTMCD, t4.VCORIGINALINVOICEDATE
, t5.DATAAREADID, t5.INVENTTRANSID
, t6.RLLINEID
FROM cte t1
INNER JOIN CUSTINVOICEJOUR t2 on t2.INVOICEID = t1.INVOICEID and t1.INVOICEDATE = t2.INVOICEDATE
INNER JOIN SALESTABLE t3 on t3.SALESID = t1.ORIGSALESID
INNER JOIN VCSALESTABLEINFO t4 on t4.SALESID = t1.ORIGSALESID
INNER JOIN SALESLINE t5 on t5.SALESID = t1.ORIGSALESID
INNER JOIN VCSALESLINEINFO t6 on t6.INVENTTRANSID = t5.INVENTTRANSID
Pull the first INNER JOIN outcome to a dataframe / temp table t1.
Join the same with second INNER Join dataset.
pull the data into another temp table / data frame.
Drop the temp table t1 at the end.
Follow the step for for subsequesnt joins.
Regards

SQL many to many select people with multiple vacancies

I am working with sql server through SSMS right now. How can i choose all people with multiple(>2)vacancies?
I am trying something like that, but i dont understand how to make part with "more than 2 vacancies"?
SELECT dbo.applicants.FirstName, dbo.vacancy.Name
FROM dbo.applicants INNER JOIN
dbo.VacancyApplicant ON dbo.applicants.id = dbo.VacancyApplicant.ApplicantId INNER JOIN
dbo.vacancy ON dbo.VacancyApplicant.VacancyId = dbo.vacancy.id WHERE dbo.vacancy.Name='third vacancy'
SELECT dbo.applicants.FirstName, dbo.vacancy.Name
FROM dbo.applicants A INNER JOIN
dbo.VacancyApplicant V ON A.id = V.ApplicantId
WHERE EXIST(
SELECT 1
FROM dbo.applicants INNER JOIN
dbo.VacancyApplicant ON dbo.applicants.id =
dbo.VacancyApplicant.ApplicantId INNER JOIN
dbo.vacancy ON dbo.VacancyApplicant.VacancyId = dbo.vacancy.id
WHERE A.id=dbo.applicants.id
GROUP BY dbo.applicants.id,dbo.vacancy.id
HAVING COUNT(1)>2
)
Group By and Having are you basic answer. Below is a simple solution, might not be ideal, but can give you the idea.
I am finding target "applicants" ids in subquery, that uses GROUP BY and HAVING then outer query joins to that to output FirstName and LastName of applicant
SELECT dbo.applicants.FirstName, dbo.applicants.LastName FROM
dbo.applicants a INNER JOIN
(
SELECT dbo.applicants.id
FROM dbo.applicants INNER JOIN
dbo.VacancyApplicant ON dbo.applicants.id = dbo.VacancyApplicant.ApplicantId INNER JOIN
dbo.vacancy ON dbo.VacancyApplicant.VacancyId = dbo.vacancy.id AND dbo.vacancy.Name='third vacancy'
GROUP BY dbo.applications.id
HAVING COUNT(dbo.vacancy.id) > 2
) targetIds ON a.id = targetIds.id
"more than 2 vacancies"?
Your question only mentions vacancies but your query is filtering for a particular name. I assume you really want more than two of that name.
If I understand correctly, you want aggregation:
SELECT a.FirstName, a.Name
FROM dbo.applicants a INNER JOIN
dbo.VacancyApplicant va
ON a.id = va.ApplicantId INNER JOIN
dbo.vacancy v
ON va.VacancyId = v.id
WHERE v.Name = 'third vacancy'
GROUP BY a.FirstName, v.Name
HAVING COUNT(*) > 2;
Note the use of table aliases. They make the query easier to write and to read.
WITH TempCTE AS (
SELECT DISTINCT ap.FirstName
,vc.Name
,COUNT (va.VacancyId) OVER (PARTITION BY ap.id) AS NoOfVacancies
FROM dbo.applicants ap
JOIN dbo.VacancyApplicant va
ON ap.id = va.ApplicantId
JOIN dbo.vacancy vc
ON va.VacancyId = vc.id
)
SELECT FirstName,[Name], NoOfVacancies FROM TempCTE
WHERE NoOfVacancies > 2

LEFT JOINS in MS Access

I am trying to troubleshoot someone else's MS Access query and keep getting an invalid operation error. The Help doesn't seem to apply as I am just running a query. It all works as INNER JOINS but when I switch back to the LEFT JOIN the error.
SELECT *
FROM ((((orders
INNER JOIN orders_customers ON orders.CUST_ORDER_ID = orders_customers.ID)
LEFT JOIN quoted_theory ON orders.PART_ID = quoted_theory.PART_ID)
LEFT JOIN conversions ON orders.PART_ID = conversions.PART_ID)
LEFT JOIN dbo_WO_Header ON orders.CUST_ORDER_ID = dbo_WO_Header.PPC_Number)
INNER JOIN lines_qry ON orders.CUST_ORDER_ID = lines_qry.WORKORDER_BASE_ID
I can get one level of LEFT JOIN, but each time I add a second LEFT JOIN the error pops up.
Access' db engine frequently balks when mixing INNER and LEFT joins. If that query works without the last inner join ...
SELECT *
FROM
(((orders INNER JOIN orders_customers
ON orders.CUST_ORDER_ID = orders_customers.ID)
LEFT JOIN quoted_theory
ON orders.PART_ID = quoted_theory.PART_ID)
LEFT JOIN conversions
ON orders.PART_ID = conversions.PART_ID)
LEFT JOIN dbo_WO_Header
ON orders.CUST_ORDER_ID = dbo_WO_Header.PPC_Number
... then you could try that part as a subquery and inner join lines_qry to the subquery. It might get past the error.
SELECT *
FROM
(
SELECT *
FROM
(((orders INNER JOIN orders_customers
ON orders.CUST_ORDER_ID = orders_customers.ID)
LEFT JOIN quoted_theory
ON orders.PART_ID = quoted_theory.PART_ID)
LEFT JOIN conversions
ON orders.PART_ID = conversions.PART_ID)
LEFT JOIN dbo_WO_Header
ON orders.CUST_ORDER_ID = dbo_WO_Header.PPC_Number
) AS sub
INNER JOIN lines_qry
ON sub.CUST_ORDER_ID = lines_qry.WORKORDER_BASE_ID
If any other table besides orders includes a field named CUST_ORDER_ID, you will need something other than SELECT * within the subquery to avoid ambiguity.
SELECT *
FROM
(
SELECT *
FROM
(((orders INNER JOIN orders_customers
ON orders.CUST_ORDER_ID = orders_customers.ID)
LEFT JOIN quoted_theory
ON orders.PART_ID = quoted_theory.PART_ID)
LEFT JOIN conversions
ON orders.PART_ID = conversions.PART_ID)
LEFT JOIN dbo_WO_Header
ON orders.CUST_ORDER_ID = dbo_WO_Header.PPC_Number
) AS sub
INNER JOIN lines_qry
ON sub.CUST_ORDER_ID = lines_qry.WORKORDER_BASE_ID

Can you have an INNER JOIN without the ON keyword?

While debugging into some Oracle code, I came across this query:
SELECT TPM_TASK.TASKID FROM TPM_GROUP
INNER JOIN TPM_USERGROUPS ON TPM_GROUP.GROUPID = TPM_USERGROUPS.GROUPID
INNER JOIN TPM_TASK
INNER JOIN TPM_GROUPTASKS ON TPM_TASK.TASKID = TPM_GROUPTASKS.TASKID
INNER JOIN TPM_PROJECTVERSION ON TPM_TASK.PROJECTID = TPM_PROJECTVERSION.PROJECTID AND TPM_TASK.VERSIONID = TPM_PROJECTVERSION.VERSIONID
INNER JOIN TPM_TASKSTAGE ON TPM_TASK.STAGEID = TPM_TASKSTAGE.STAGEID
INNER JOIN TPM_PROJECTSTAGE ON TPM_PROJECTVERSION.STAGEID = TPM_PROJECTSTAGE.STAGEID
ON TPM_GROUP.GROUPID = TPM_GROUPTASKS.GROUPID
I'm confused by the line:
INNER JOIN TPM_TASK
I haven't seen a JOIN without an ON clause before. Also confusing is the line:
ON TPM_GROUP.GROUPID = TPM_GROUPTASKS.GROUPID
This seems like a random ON clause without any matching JOIN. The query runs without any errors, and returns a bunch of data, so obvious the syntax is perfectly valid. Can someone shed some light on exactly what's going on here?
Small universe... I ran across a tool generating this syntax yesterday and was rather flummoxed.
Apparently,
FROM a
INNER JOIN b
INNER JOIN c ON (b.id = c.id)
ON (a.id = c.id)
is equivalent to a nested subquery
FROM a
INNER JOIN (SELECT <<list of columns>>
FROM b
INNER JOIN c ON (b.id=c.id)) c
ON (a.id = c.id)
I think that this is only a problem of ordering your query (since there are only INNER JOINs, the order of them is not really that important). I rearrenged your query and now it looks like this:
SELECT TPM_TASK.TASKID
FROM TPM_GROUP
INNER JOIN TPM_USERGROUPS
ON TPM_GROUP.GROUPID = TPM_USERGROUPS.GROUPID
INNER JOIN TPM_GROUPTASKS
ON TPM_GROUP.GROUPID = TPM_GROUPTASKS.GROUPID
INNER JOIN TPM_TASK
ON TPM_TASK.TASKID = TPM_GROUPTASKS.TASKID
INNER JOIN TPM_PROJECTVERSION
ON TPM_TASK.PROJECTID = TPM_PROJECTVERSION.PROJECTID
AND TPM_TASK.VERSIONID = TPM_PROJECTVERSION.VERSIONID
INNER JOIN TPM_TASKSTAGE
ON TPM_TASK.STAGEID = TPM_TASKSTAGE.STAGEID
INNER JOIN TPM_PROJECTSTAGE
ON TPM_PROJECTVERSION.STAGEID = TPM_PROJECTSTAGE.STAGEID
Does it make more sense to you now?, it does to me.
It'd look fine if it had parenthesis in there...
SELECT TPM_TASK.TASKID
FROM
TPM_GROUP
INNER JOIN TPM_USERGROUPS ON TPM_GROUP.GROUPID = TPM_USERGROUPS.GROUPID
INNER JOIN (
TPM_TASK
INNER JOIN TPM_GROUPTASKS ON TPM_TASK.TASKID = TPM_GROUPTASKS.TASKID
INNER JOIN TPM_PROJECTVERSION ON TPM_TASK.PROJECTID = TPM_PROJECTVERSION.PROJECTID
AND TPM_TASK.VERSIONID = TPM_PROJECTVERSION.VERSIONID
INNER JOIN TPM_TASKSTAGE ON TPM_TASK.STAGEID = TPM_TASKSTAGE.STAGEID
INNER JOIN TPM_PROJECTSTAGE ON TPM_PROJECTVERSION.STAGEID = TPM_PROJECTSTAGE.STAGEID
) ON TPM_GROUP.GROUPID = TPM_GROUPTASKS.GROUPID
but since they are all inner joins I agree with Lamak's answer.

Top 5 comments from a specific post. How to write my SQL

I want to show only the top 5 comments for a specific post (Like the post on facebook where people cant comment them).
gbn was kind enough to help figure out that issue by doing the following:
select
*
FROM
tblPost P
OUTER APPLY
(SELECT TOP 5 * FROM tblComment C
WHERE P.id = C.postid
ORDER BY something) inline
But since I'm no sql grand master I would need your help to put that into my real sql statement.
SELECT *
FROM
memberactions INNER JOIN
actions ON memberactions.actionid = actions.id INNER JOIN
members ON memberactions.memberid = members.id LEFT OUTER JOIN
members members_2 INNER JOIN
actioncomments ON members_2.id = actioncomments.memberid INNER JOIN
comments ON actioncomments.commentid = comments.id ON actions.id = actioncomments.actionid
So my question is could you rearrange my sql to put the OUTER APPLY in my real sql statement.
Assuming that my table comments reprensent tblComment and that actioncomments represent the table tblPost
There does not seem to be a need for the member_2 table at all, but this is a faithful representation of what you had (preserving member_2)
SELECT *
FROM memberactions
INNER JOIN actions
ON memberactions.actionid = actions.id
INNER JOIN members
ON memberactions.memberid = members.id
OUTER APPLY (
select top(5) *
FROM actioncomments
inner join comments ON actioncomments.commentid = comments.id
inner join members members_2 ON members_2.id = actioncomments.memberid
WHERE actions.id = actioncomments.actionid
order by comments.id desc) comments
SELECT *
FROM
memberactions
INNER JOIN actions
ON memberactions.actionid = actions.id
INNER JOIN members
ON memberactions.memberid = members.id
LEFT OUTER JOIN members members_2
INNER JOIN actioncomments
ON members_2.id = actioncomments.memberid
OUTER APPLY
(SELECT TOP 5 * FROM comments C
WHERE actioncomments.commentid = comments.id
ORDER BY something)
ON actions.id = actioncomments.actioni
still don't know what you want to order by