Joining query sql server - sql-server

I'm after some help please i'm new to SQL, can you help me join these to queries below I want all the data from the first query to be displayed and only the information that matches to be showed on the second query.
Part and subkey1 is the join
Thank you.
SELECT RHeads.[Document],
RLines.Part,
RHeads.Supp,
RHeads.DATETIME,
RLines.Unit,
RLines.CQty,
RHeads.POrder,
RHeads.Corder,
RHeads.Branch
FROM RLines
RIGHT OUTER JOIN RHeads ON RLines.[Document] = RHeads.[Document]
WHERE (RHeads.DATETIME >= DATEADD(MONTH, - 3, GETDATE()))
AND (RHeads.Corder = '02022076')
ORDER BY RHeads.DATETIME DESC;
SELECT Mvpr.Prefix,
Mvpr.SubKey1,
Mvpr.SubKey2,
Mvpr.A12
FROM Mvpr
INNER JOIN vwProduct ON Mvpr.SubKey1 = vwProduct.KeyCode
WHERE (Mvpr.Prefix = 'c');

Just stick both of these SQL statements into their own subquery (using parantheses) and give each subquery an alias so we can refer to it's result set in the main query:
SELECT
t1.*,
t2.*
FROM
(
SELECT RHeads.[Document],
RLines.Part,
RHeads.Supp,
RHeads.DATETIME,
RLines.Unit,
RLines.CQty,
RHeads.POrder,
RHeads.Corder,
RHeads.Branch
FROM RLines
RIGHT OUTER JOIN RHeads ON RLines.[Document] = RHeads.[Document]
WHERE (RHeads.DATETIME >= DATEADD(MONTH, - 3, GETDATE()))
AND (RHeads.Corder = '02022076')
) t1
LEFT OUTER JOIN
(
SELECT Mvpr.Prefix,
Mvpr.SubKey1,
Mvpr.SubKey2,
Mvpr.A12
FROM Mvpr
INNER JOIN vwProduct ON Mvpr.SubKey1 = vwProduct.KeyCode
WHERE (Mvpr.Prefix = 'c')
) t2 ON t1.Part = t2.SubKey1
ORDER BY t1.DATETIME DESC;
We're using a LEFT OUTER JOIN to get all of the records from t1 (first query) and only those records that match from t2 (second query).
Also I have moved the ORDER BY clause to the main query as you can't ORDER inside of a subquery (and even if you were allowed to, the ordering would be lost after the join so it would be superfluous).
Since you aren't doing any aggregating here, you could probably rewrite this without the subquery too.
I've made some assumptions about your data, but perhaps something like:
SELECT RHeads.[Document],
RLines.Part,
RHeads.Supp,
RHeads.DATETIME,
RLines.Unit,
RLines.CQty,
RHeads.POrder,
RHeads.Corder,
RHeads.Branch,
Mvpr.Prefix,
Mvpr.SubKey1,
Mvpr.SubKey2,
Mvpr.A12
FROM RHeads
LEFT OUTER JOIN RLines
ON RLines.[Document] = RHeads.[Document]
LEFT OUTER JOIN vwProduct
ON Mvpr.SubKey1 = vwProduct.KeyCode
LEFT OUTER JOIN Mvpr
ON vwProduct.KeyCode = Mvpr.Subkey1
AND Mvpr.Prefix = 'c'
WHERE
RHeads.DATETIME >= DATEADD(MONTH, - 3, GETDATE())
AND RHeads.Corder = '02022076'

If you want to maintain the granularity of the 1st query put them in CTEs and check existence:
;WITH Q1 AS(
SELECT RHeads.[Document],
RLines.Part,
RHeads.Supp,
RHeads.DATETIME,
RLines.Unit,
RLines.CQty,
RHeads.POrder,
RHeads.Corder,
RHeads.Branch
FROM RLines
RIGHT OUTER JOIN RHeads ON RLines.[Document] = RHeads.[Document]
WHERE (RHeads.DATETIME >= DATEADD(MONTH, - 3, GETDATE()))
AND (RHeads.Corder = '02022076')
), Q2 AS (
SELECT Mvpr.Prefix,
Mvpr.SubKey1,
Mvpr.SubKey2,
Mvpr.A12
FROM Mvpr
INNER JOIN vwProduct ON Mvpr.SubKey1 = vwProduct.KeyCode
WHERE (Mvpr.Prefix = 'c')
)
SELECT q1.*
FROM Q1 q1
WHERE EXISTS(
SELECT *
FROM Q2 q2
WHERE q1.Part = q2.SubKey1
)
ORDER BY q1.DATETIME DESC

Related

SQL Query Group by Count and Left Join Tables

i need your help! I got some simple SQL skills, but this query kills me...
My Tables
Now i want the TOP5 WorkTimes on the Equipment (What Equipment got the longest WorkTime).
I want this OUTPUT:
MY Query:
SELECT
Equipment, EquipmentName, count(Equipment) as Count
FROM
Operations o
LEFT JOIN Orders ord ON ord.Id = o.[Order]
LEFT OUTER JOIN Equipments e ON ord.Equipment = e.EquipmentNumber
GROUP BY
Equipment, EquipmentName
ORDER BY Count DESC;
Another Question is how i can show o.Worktime?
i got an error with GroupBy...
please help me Thanks!
You can try this query:
select equip_nr,
(select equipmentname from table_equipments where equipmentnr = [to].equip_nr) equip_name,
sum(timeInMins) / 60.0 Worktime
from (
select (select equipmentnr from table_orders where id = [to].[order]) equip_nr,
case when workunittime = 'RH' then worktime * 60 else worktime end timeInMins
from table_operations [to]
where exists(select 1 from table_orders
where [to].[order] = id
and location = '152')
and [start] >= '2018-07-01 00:00:00.000' and [start] < '2018-08-01 00:00:00.000'
) [to] group by equip_nr
By the way, LEFT JOIN is equivalent to LEFT OUTER JOIN.
Just use SUM(worktime) as aggregate function, instead of COUNT(Equipment)
SELECT
e.[ID_Equipment]
, Name
, SUM( IIF(o.WorkUnitTime='MIN', worktime/60.0, worktime) ) as WorktimeMIN
FROM
Operations o
LEFT JOIN Orders ord ON ord.ID_Order = o.ID_Order
LEFT OUTER JOIN Equipment e ON ord.ID_Equipment = e.ID_Equipment
GROUP BY
e.[ID_Equipment]
, Name
ORDER BY
WorktimeMIN DESC
See SQL Fiddle here: http://sqlfiddle.com/#!18/5b5ed/11

optimize complex sql query

I am using azure sql server database. I have written one sql query to generate reprot. Here it is:
;WITH cte AS
(
SELECT ProjectID, CreatedDateUTC, ProductID, LicenseID, BackgroundID from Project p
WHERE CAST(p.CreatedDateUTC AS DATE) >= #StartDate and CAST(p.CreatedDateUTC AS DATE) <= #EndDate
and IsBackgroundUsed = 1
and s7ImageGenerated = 1 and p.SiteCode in ('b2c' )
)
SELECT ProjectID , CreatedDateUTC,
(SELECT BackgroundName from Background b WHERE b.BackgroundID = cte.BackgroundID) AS BackgroundName,
(SELECT Name FROM Product pr WHERE pr.ProductID = cte.ProductID) AS ProductName,
Case WHEN LicenseID is null THEN 'Standard' ELSE (SELECT LicenseName from License l WHERE l.LicenseID = cte.LicenseID) END AS CLA,
(SELECT PurchaseFG from Product_background pb WHERE pb.BackgroundID = cte.BackgroundID and pb.ProductId = cte.productID) AS PurchaseFG,
(SELECT FGcode from Product pr WHERE pr.ProductID = cte.ProductID) AS ProductFGCode,
--(Select dbo.[getProjectFGCodeByBackground](cte.ProductID, cte.BackgroundID)) AS FGCode,
'' AS ERPOrderNumber,
0 AS DesignQuanity
from cte
WHERE (SELECT count(*) from Approval.OrderDetail od WHERE od.ProjectID = cte.ProjectID) = 0
Is there any way to optimize this query. Timeout issue comes. I have written this query in store procedure and calling that store procedure using linq entity framework.
Earlier i have used join but it's more slow down so tried with sub query. Worked more then one year now not working.
This will definitely improve the performance, especially if the table Approval.OrderDetail is large:
...WHERE not exists
(SELECT 1 from Approval.OrderDetail od WHERE od.ProjectID = cte.ProjectID)
Writing a sub-select for every single field is a terrible way to retrieve data, as you'll likely end up with a lot of Loop Joins which have terrible performance over large data sets.
Your original JOIN method is the way to go, but you need to ensure you have appropriate indexes on your joining columns.
You can also replace the WHERE clause, with a LEFT JOIN and IS NULL combination
LEFT JOIN Approval.OrderDetail od
ON od.ProjectID = p.ProjectID
...
AND od.ProjectID IS NULL;
or a NOT EXISTS (although that is more likely to have to SCAN a wider range of rows for each row returned by the main query).
WHERE NOT EXISTS
(SELECT 1 FROM Approval.OrderDetail od WHERE od.ProjectID = cte.ProjectID)
In either case, make sure your Project table is appropriately indexed on (IsBackgroundUsed, s7ImageGenerated, SiteCode, CreatedDate) and that all joins are appropriately indexed.
I'd also question whether you actually need to cast your CreatedDateUTC fields to DATE types?
A possible simplification could be:
SELECT
p.ProjectID,
p.CreatedDateUTC,
b.BackgroundName,
pr.Name,
IIF(p.LicenseID IS NULL, 'Standard', l.LicenseName) AS CLA,
pb.PurchaseFG,
pr.FGCode AS ProductFGCode,
'' AS ERPOrderNumber,
0 AS DesignQuantity
FROM Project p
LEFT JOIN Approval.OrderDetail od
ON od.ProjectID = p.ProjectID
LEFT JOIN Background b
ON b.BackgroundID = p.BackgroundID
LEFT JOIN Product pr
ON pr.ProductID = p.ProductID
LEFT JOIN License l
ON l.LicenseID = p.LicenseID
LEFT JOIN Product_Background pb
ON pb.BackgroundID = p.BackgroundID
AND pb.ProductID = p.ProductID
WHERE p.CreatedDateUTC >= #StartDate AND p.CreatedDateUTC <= #EndDate
AND p.IsBackgroundUsed = 1
AND p.s7ImageGenerated = 1
AND p.SiteCode = 'b2c'
AND od.ProjectID IS NULL;
WHERE CAST(p.CreatedDateUTC AS DATE) >= #StartDate and CAST(p.CreatedDateUTC AS DATE) <= #EndDate
make this SARGAble ,create non clustered index on CreatedDateUTC
Suppose this is the parameter ,
declare #StartDate datetime='2018-02-01'
declare #EndDate datetime='2018-02-28'
Then,
set #EndDate=dateadd(second,-1,dateadd(day,1,#EndDate))
now you can safely use do this,
WHERE p.CreatedDateUTC >= #StartDate and p.CreatedDateUTC <= #EndDate
I think,#Mark Sinkinson query will work ok than sub query.( I will try NOT EXISTS clause once)
Use INNER JOIN if possible.
Hope you are using Store Procedure and calling the SP.
Create index on all joins columns.
Since your sub query is working fine output wise without TOP 1 so it appear that all tables have ONE to ONE relation with Project .
CREATE NONCLUSTERED INDEX IX_Project ON project (
CreatedDateUTC
,IsBackgroundUsed
,s7ImageGenerated
,SiteCode
) include (ProductID,LicenseID,BackgroundID);
Hope projectID is already Clustered Index.
Might not be much faster but easier to read for me.
You should be able to adjust #StartDate and #EndDate and not have to cast to date.
Have an index on all join and where conditions.
If those are FK you should be able to use an inner join (and should).
SELECT P.ProjectID , P.CreatedDateUTC,
b.BackgroundName,
pr.Name AS ProductName,
isnull(l.LicenseName, 'Standard') as CLA,
pb.PurchaseFG,
pr.FGcode AS ProductFGCode,
'' AS ERPOrderNumber,
0 AS DesignQuanity
from Project p
left join Background b
on b.BackgroundID = p.BackgroundID
left join Product pr
on pr.ProductID = p.ProductID
left join License l
on l.LicenseID = p.LicenseID
left join Product_background pb
on pb.BackgroundID = p.BackgroundID
and pb.ProductId = p.productID
left join Product pr
on pr.ProductID = p.ProductID
WHERE CAST(p.CreatedDateUTC AS DATE) >= #StartDate
and CAST(p.CreatedDateUTC AS DATE) <= #EndDate
and p.IsBackgroundUsed = 1
and p.s7ImageGenerated = 1
and p.SiteCode = 'b2c'
and not exists (SELECT 1
from Approval.OrderDetail od
WHERE od.ProjectID = p.ProjectID)

Slow Left Outer Join

I wonder if anyone can advise me on this issue. I have a query which runs slowly when a left outer join is introduced. Without the left outer join (Inner instead) it runs pretty much immediately, but with the left outer it runs 20 seconds or more. The joined columns are indexed. My execution plan shows a hash match if that helps. Thank you again for your assistance..
Derek
SELECT DISTINCT
dbo.Staff.strStaffName AS [Staff Name], dbo.Staff.strEmailAddress1 AS NegEmailAddress, ISNULL(dbo.qryContactEmailDJ.Address,
dbo.Staff.strEmailAddress1) AS AppEmailAddress
FROM dbo.Contacts INNER JOIN
dbo.Staff ON dbo.Contacts.strResponsibilityOf = dbo.Staff.strStaffName LEFT OUTER JOIN
dbo.qryContactEmailDJ ON dbo.Contacts.ContactPK = dbo.qryContactEmailDJ.ContactFK INNER JOIN
dbo.Property ON dbo.Contacts.CompanyFK = dbo.Property.CompanyFK INNER JOIN
dbo.qryLS_ApplicantLastMadeActive ON dbo.Contacts.ContactPK = dbo.qryLS_ApplicantLastMadeActive.ContactPK
WHERE (dbo.Contacts.strApplicantStatus = 'Active')
AND (CONVERT(VarChar, dbo.qryLS_ApplicantLastMadeActive.LatestActiveDate, 112) = CONVERT(VarChar, GETDATE() - 84,112))
This will make it a bit more readable and faster, the issue is your way of comparing the dates in the WHERE clause:
SELECT --(do you really need distinct ?)
Staff.strStaffName AS [Staff Name],
Staff.strEmailAddress1 AS NegEmailAddress,
ISNULL(con.qryContactEmailDJ.Address, Staff.strEmailAddress1) AS AppEmailAddress
FROM dbo.Contacts
JOIN dbo.Staff
ON Contacts.strResponsibilityOf = Staff.strStaffName
LEFT JOIN dbo.qryContactEmailDJ con
ON Contacts.ContactPK = con.ContactFK
JOIN dbo.Property
ON Contacts.CompanyFK = Property.CompanyFK
JOIN dbo.qryLS_ApplicantLastMadeActive qryl
ON Contacts.ContactPK = qryl.ContactPK
WHERE
(Contacts.strApplicantStatus = 'Active')
AND qryl.LatestActiveDate >= dateadd(d, datediff(d, 0, GETDATE()), -84)
AND qryl.LatestActiveDate < dateadd(d, datediff(d, 0, GETDATE()), -83)

What alternative do I have to a Left Join in this query?

I have this query that is used in a SSRS report that someone else created. The left join is the cause of the problem. If I change it to an inner join I get results (not the correct results) in about 15 seconds. With the Left Join I end up canceling the query after 20 minutes. I added an index to both Budgets.Professionals and Transactions.Professionals with no change in performance. Is there a way to rewrite the query and not use the Left Join?
SELECT
profs.ProfName as orig
,profs.Initials
,DATEPART(year, TransDate) as [Year]
,SUM(CASE WHEN IsFlatFee = 'Y' OR COALESCE(MT.Admin, 'N') = 'Y'
THEN 0.0
ELSE Units * (aph.assignedpercent/100) * isnull(B.rate, 0.0)
END) AS ctp
,SUM(CASE WHEN IsFlatFee = 'Y' OR COALESCE(MT.Admin, 'N') = 'Y'
THEN 0
ELSE Units
END * (aph.assignedpercent/100)) AS worked_hours
,SUM(Value * (aph.assignedpercent/100)) AS worked_value
, 0 AS billed_hours
,0 AS billed_value
,0 AS billed_netamt
, 0.0 as paid
, 0.0 as wo
FROM Transactions Trans
INNER JOIN Matters Matts ON Trans.matters = Matts.matters
INNER JOIN MatterTypes MT ON Matts.mattertype = MT.mattertypesdesc
and MT.Admin <> 'Y'
INNER JOIN Components Comps ON Comps.components = Trans.components
and Comps.CompType = 'F'
INNER JOIN AssignedProfsHistory APH on APH.Matters = Trans.Matters
and APH.AssignedType = 'Originating'
and Trans.TransDate between APH.EffectiveDate and
ISNULL(EndDate,'12/31/2099')
INNER JOIN Professionals profs on profs.Professionals = APH.Professionals
and profs.ProfType = 'Member'
and profs.IsActive = 'Y'
and profs.IsBillable = 'Y'
**LEFT join** (SELECT Budgets.Professionals as timekeeper, Budgets.Amount as
rate, Budgets.PeriodDate
FROM Matters Matts
INNER JOIN Budgets ON Matts.matters = Budgets.matters
and cast(Budgets.PeriodDate as Date) <= '2017-12-31'
AND MONTH('2017-12-31') = MONTH(Budgets.PeriodDate)
WHERE Matts.MatterID = '99999-99.003') as B
*on B.timekeeper = Trans.Professionals*
and YEAR(B.PeriodDate) = DATEPART(year, TransDate)
WHERE cast(transdate as DATE) between dateadd(day, 1, DATEADD(year, -3,
'2017-12-31')) and '2017-12-31'
GROUP BY profs.ProfName, profs.Initials, DATEPART(year, TransDate)
As Sean and Aaron said. There are too many things that are potentially an issue.
You seem (I'm guessing from column names) that you are joining on text columns mattertypesdesc for one. In fact most of the work is done against text columns. Even Matts.MatterID is textual. This may not be possible in your scenario but it would perform better if the tables had integer primary keys and you join on those.
Anyway, guessing aside.... You might get a quick win if you replace your sub query in the left join with a temp table.
so before you existing query just do ...
SELECT Budgets.Professionals as timekeeper, Budgets.Amount as rate, Budgets.PeriodDate
INTO #t
FROM Matters Matts
INNER JOIN Budgets ON Matts.matters = Budgets.matters
and cast(Budgets.PeriodDate as Date) <= '2017-12-31'
AND MONTH('2017-12-31') = MONTH(Budgets.PeriodDate)
WHERE Matts.MatterID = '99999-99.003'
then in your exisintg query, replace the subquery with
SELECT ...
...
...
LEFT JOIN #t as B
ON B.timekeeper = Trans.Professionals
....
You can also try with the APPLY operator... remove left join & it's on condition, use outer apply and include on conditions inside the outer apply script like
AND budgets.timekeeper = trans.professionals
AND year(budgets.perioddate) = datepart(year, transdate)
Sample
OUTER APPLY
(
SELECT budgets.professionals AS timekeeper,
budgets.amount AS rate,
budgets.perioddate
FROM matters matts
INNER JOIN budgets
ON matts.matters = budgets.matters
AND cast(budgets.perioddate AS date) <= '2017-12-31'
AND month('2017-12-31') = month(budgets.perioddate)
AND budgets.timekeeper = trans.professionals
AND year(budgets.perioddate) = datepart(year, transdate)
WHERE matts.matterid = '99999-99.003'
) AS b
Thanks everyone who responded. I took your suggestions and I was able to come up with a solution. The query that I had to kill after running for 2 hrs now finishes in about 14 seconds.
I ended up creating a cte at the beginning of the script.
;with cte as
(SELECT Transactions FROM Transactions t
WHERE cast(t.TransDate as DATE) between dateadd(day, 1, DATEADD(year, -3,
#EndDate)) and #EndDate)
Then I linked the CTE to Transactions.
FROM Transactions Trans
INNER JOIN cte ON cte.Transactions = Trans.Transactions
I then was able to remove the 'where' clause that was causing the issue.
WHERE cast(transdate as DATE) between dateadd(day, 1, DATEADD(year, -3,
#EndDate)) and #EndDate

How to return latest record from SQL Server

I have this query:
SELECT
t_ticket.ticketID, t_ticket.addedDate, t_ticket.question,
t_ticket.code, t_ticket.priority, t_orgSection.title,
t_actionTicket.addedDateAction, t_actionTicket.title AS Expr1
FROM
t_actionTicket
INNER JOIN
t_ticket ON t_actionTicket.ticketID_FK = t_ticket.ticketID
INNER JOIN
t_orgSection ON t_ticket.orgSectionID_FK = t_orgSection.orgSectionID
WHERE
(t_ticket.userID_FK = #userid) AND (t_ticket.cusDelete = 0)
I want to return just the latest record in t_actionTicket table for each row in t_ticket table.
You can use row_number to pick just the top row for each ticket ID, by ordering by your date and then making row = 1 one of your join criteria. See as follows:
Replace
FROM t_actionTicket INNER JOIN
t_ticket ON t_actionTicket.ticketID_FK = t_ticket.ticketID
with
FROM
(select *
, row_number() over (partition by ticketID_FK order by TicketActionDate desc) as RN
from t_actionTicket ) at
INNER JOIN t_ticket
ON at.ticketID_FK = t_ticket.ticketID and at.RN = 1
I guessed at the name of your date column in ActionTicket, so you will probably need to change that.
You can try this one too, just alternative:
SELECT t_ticket.ticketID, t_ticket.addedDate, t_ticket.question,t_ticket.code, t_ticket.priority, t_orgSection.title,t_actionTicket.addedDateAction, t_actionTicket.title AS Expr1
FROM t_ticket INNER JOIN
(select TOP 1 t_actionTicket.* from t_actionTicket INNER JOIN
t_ticket on t_ticket.ticketID = t_actionTicket.ticketID_FK ORDER BY
t_actionTicket.addedDateAction DESC ) AS t_actionTicket
ON t_actionTicket.ticketID_FK = t_ticket.ticketID
INNER JOIN t_orgSection ON t_ticket.orgSectionID_FK = t_orgSection.orgSectionID
WHERE (t_ticket.userID_FK = #userid) AND (t_ticket.cusDelete = 0)
I assume that addedDateAction uses timestamp when new record is inserted.
I find this solution
SELECT t_ticket.ticketID, t_ticket.addedDate, t_ticket.question,
t_ticket.code, t_ticket.priority, t_actionTicket.addedDateAction,
t_actionTicket.title AS Expr1
FROM t_actionTicket INNER JOIN t_ticket ON
t_actionTicket.ticketID_FK = t_ticket.ticketID INNER JOIN
(SELECT ticketID_FK, MAX(addedDateAction) AS maxDate
FROM t_actionTicket AS t_actionTicket_1
GROUP BY ticketID_FK) AS b ON t_actionTicket.ticketID_FK = b.ticketID_FK AND t_actionTicket.addedDateAction = b.maxDate
WHERE (t_ticket.userID_FK = #userid) AND (t_ticket.cusDelete = 0)

Resources