SELECT records with condition that filters the last chronilogical multiple and specific value of a column - sql

I have a joined table that looks like that:
my goal is to filter all records that was created after the last 'active' value inside LineStatusName Column. (the yellow marked rows in the attached image).
here is what i have done so far, it is almost work as desired, but the problem is that the date that returns from the nested select steatment is not the date of the highest chronological datetime value of 'active' and if i try to do ORDER BY Changes.ChangeDateTim in the end of the nested select i get a syntax error:
Conversion failed when converting the nvarchar value '30-9000241' to data type int.
I will be grateful if someone can suggest a better solution to achieve that task or to improve my query.
SELECT Orders.OrderID,LineStatuses.LineStatusName,OrderTypes.OrderTypeName,
Changes.ChangeDateTime,Orders.ProjectNumber,Changes.Comments,Changes.ChangeTypeID
FROM Orders
INNER JOIN Changes ON Changes.ItemID = Orders.OrderID
INNER JOIN LineStatusSettings ON LineStatusSettings.LineStatusSettingID = Changes.NewValue
INNER JOIN LineStatuses ON LineStatuses.LineStatusID= LineStatusSettings.LineStatusID
INNER JOIN OrderTypes ON OrderTypes.OrderTypeID = LineStatusSettings.OrderTypeID
WHERE Orders.OrderID = 194 AND Orders.Deleted=0
AND
Changes.ChangeDateTime > (
SELECT TOP 1 Changes.ChangeDateTime
FROM Orders
INNER JOIN Changes ON Changes.ItemID = Orders.OrderID
INNER JOIN LineStatusSettings ON LineStatusSettings.LineStatusSettingID = Changes.NewValue
INNER JOIN LineStatuses ON LineStatuses.LineStatusID= LineStatusSettings.LineStatusID
INNER JOIN OrderTypes ON OrderTypes.OrderTypeID = LineStatusSettings.OrderTypeID
WHERE LineStatuses.LineStatusName = 'active'
) AND OrderTypes.OrderTypeName NOT IN ('disconnected line')
ORDER BY Changes.ChangeDateTime

Here is one method:
with jt as (
<your query here>
)
select jt.*
from jt
where jt.date > (select max(jt2.date)
from jt jt2
where jt2.orderid = jt.orderid and jt2.linestatusname = 'Active'
);

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

Access Subquery On mulitple conditions

This SQL query needs to be done in ACCESS.
I am trying to do a subquery on the total sales, but I want to link the sale to the province AND to product. The below query will work with one or the other: (po.product_name = allp.all_products) AND (p.province = allp.all_province); -- but it will no take both.
I will be including every month into this query, once I can figure out the subquery on with two criteria.
Select
p.province as [Province],
po.product_name as [Product],
all_price
FROM
(purchase_order po
INNER JOIN person p
on p.person_id = po.person_id)
left join
(
select
po1.product_name AS [all_products],
sum(pp1.price) AS [all_price],
p1.province AS [all_province]
from (purchase_order po1
INNER JOIN product pp1
on po1.product_name = pp1.product_name)
INNER JOIN person p1
on po1.person_id = p1.person_id
group by po1.product_name, pp1.price, p1.province
)
as allp
on (po.product_name = allp.all_products) AND (p.province = allp.all_province);
Make the first select sql into a table by giving it an alias and join table 1 to table 2. I don't have your table structure or data to test it but I think this will lead you down the right path:
select table1.*, table2.*
from
(Select
p.province as [Province],
po.product_name as [Product]
--removed this ,all_price
FROM
(purchase_order po
INNER JOIN person p
on p.person_id = po.person_id) table1
left join
(
select
po1.product_name AS [all_products],
sum(pp1.price) AS [all_price],
p1.province AS [all_province]
from (purchase_order po1
INNER JOIN product pp1
on po1.product_name = pp1.product_name)
INNER JOIN person p1
on po1.person_id = p1.person_id
group by po1.product_name, pp1.price, p1.province --check your group by, I dont think you want pp1.price here if you want to aggregate
) as table2 --changed from allp
on (table1.product = table2.all_products) AND (table1.province = table2.all_province);

Putting the results of a query into new table in SQL Server

I want to insert query results into new table is there any way I can make changes in code so that it gets stored in a table.
My query:
SELECT DISTINCT TOP 5 a.DocEntry
,b.TrgetEntry
,b.itemcode
,a.DocNum AS 'Order No.'
,a.CardCode
,a.CardName
,b.DocDate AS [Delivery No.]
,c.targettype AS 'Ctargettype'
,c.trgetentry AS 'Ctargetentry'
,c.itemcode AS 'c-itemcode'
,c.docentry AS 'Cdocentry' a.CancelDate
,a.Project
,a.DocStatus
,b.ObjType
,a.ObjType
FROM ORDR a
INNER JOIN rdr1 b ON a.DocEntry = b.DocEntry
LEFT JOIN dln1 c ON c.TrgetEntry = b.DocEntry
AND b.itemcode = c.ItemCode order by c.itemcode;
You can do it as it will create a new table and insert the records into that table. If you have already created table then you can give name and individual columns also for both insertion and selection.
SELECT *
INTO YourTableName
FROM (
SELECT DISTINCT TOP 5 a.DocEntry
,b.TrgetEntry
,b.itemcode
,a.DocNum AS 'Order No.'
,a.CardCode
,a.CardName
,b.DocDate AS [Delivery No.]
,c.targettype AS 'Ctargettype'
,c.trgetentry AS 'Ctargetentry'
,c.itemcode AS 'c-itemcode'
,c.docentry AS 'Cdocentry' a.CancelDate
,a.Project
,a.DocStatus
,b.ObjType
,a.ObjType
FROM ORDR a
INNER JOIN rdr1 b ON a.DocEntry = b.DocEntry
LEFT JOIN dln1 c ON c.TrgetEntry = b.DocEntry
AND b.itemcode = c.ItemCode
)
a
For using order by clause you can try something like this.
SELECT DISTINCT
Insured_Customers.FirstName, Insured_Customers.LastName,
Insured_Customers.YearlyIncome, Insured_Customers.MaritalStatus
INTO Fast_Customers from Insured_Customers INNER JOIN
(
SELECT * FROM CarSensor_Data where Speed > 35
) AS SensorD
ON Insured_Customers.CustomerKey = SensorD.CustomerKey
ORDER BY YearlyIncome;
You can learn in detail about INTO Clause Here
This looks like SQL Server code. In that database, you add into after the select clause:
Select distinct top 5 o.DocEntry, r.TrgetEntry, r.itemcode, o.DocNum as order_num, o.CardCode,
o.CardName, r.DocDate as delivery_num,
d.targettype as Ctargettype, d.trgetentry as Ctargetentry,
d.itemcode as c_itemcode, d.docentry as Cdocentry
a.CancelDate,a.Project, a.DocStatus,b.ObjType,a.ObjType
into <new table>
from ORDR o inner join
rdr1 r
On o.DocEntry = r.DocEntry left join
dln1 d
on d.TrgetEntry = r.DocEntry and
d.itemcode = r.ItemCode;
Note that I changed the table aliases so they are meaningful. Arbitrary letters are very hard to follow. Table abbreviations are more useful.
I also changed the column aliases so they do not need to be escaped. Do not make troublesome aliases!

SQL: Linking a Count to a specific value through multiple tables

I'm trying to link a COUNT to a specific value across several tables in a SQL Server Database. In this case the tables only share values through correlation. I am returning the values I want but the COUNT is counting everything in a given project not just the ones linked to their work items.
SELECT
[d].[Id]
,COUNT([t].[ItemId]) AS ItemCount
,[d].[ItemName]
FROM
[dbo].[Project_Map] [rm] WITH (NOLOCK)
INNER JOIN
[dbo].[WorkProjects] [r] WITH (NOLOCK)
ON [r].[DomainId] = [rm].[DomainId]
AND [r].[ProjectId] = [rm].[ProjectId]
AND [r].[ReleaseId] = [rm].[ReleaseId]
INNER JOIN
[dbo].[Items] [d] WITH (NOLOCK)
ON [d].[DomainId] = [r].[DomainId]
AND [d].[ProjectId] = [r].[ProjectId]
AND [d].[ReleaseId] = [r].[ReleaseId]
INNER JOIN [dbo].[Projects] [p] with (NOLOCK)
ON r.DomainId = p.DomainId
AND r.ProjectId = p.ProjectId
INNER JOIN [dbo].[Tests] [t] with (NOLOCK)
ON p.DomainId = t.DomainId
AND p.ProjectId = t.ProjectId
INNER JOIN
(
SELECT [Id], MAX([LastModifiedDate]) AS MostRecent
FROM Items
Group By [Id]
) AS updatedItem
ON updatedItem.Id = d.Id
INNER JOIN
[dbo].[WorkItemStates] [ds] WITH (NOLOCK)
ON [ds].[ItemStateName] = [d].[ItemStatus]
WHERE
d.Id = 111111
AND d.UserCategory Like 'SOMESTRING'
GROUP BY d.Id, d.ItemName
RETURNS: In this case the count should be 1 but it returns the count for the entire project.
ID COUNT ITEMNAME
86 5169 SOME NAME
173 5169 SOME NAME
170 5169 SOME NAME
Am I missing a join somewhere?
Currently, your counts are counting all JOIN instances and not just distinct Item level records. Consider turning your Item unit level join into an aggregate query join and include the count field in outer grouping:
Specifically, change:
INNER JOIN [dbo].[Tests] [t] with (NOLOCK)
ON p.DomainId = t.DomainId
AND p.ProjectId = t.ProjectId
Into:
INNER JOIN
(SELECT t.DomaindId, t.ProjectId, Count(*) As ItemCount
FROM [dbo].[Tests] t
GROUP BY t.DomaindId, t.ProjectId) agg
ON p.DomainId = agg.DomainId
AND p.ProjectId = agg.ProjectId
And then the outer query structure becomes:
SELECT
[d].[Id]
,agg.ItemCount
,[d].[ItemName]
FROM
...
GROUP BY
[d].[Id]
,agg.ItemCount
,[d].[ItemName]
Interestingly, you already do such an aggregate query join but never use that derived table updateItem or the field MostRecent.

How to use group by only for some columns in sql Query?

The following query returns 550 records, which I am then grouping by some columns in the controller via linq. However, how can I achieve the "group by" logic in the SQL query itself? Additionally, post-grouping, I need to show only 150 results to the user.
Current SQL query:
SELECT DISTINCT
l.Id AS LoadId
, l.LoadTrackingNumber AS LoadDisplayId
, planningType.Text AS PlanningType
, loadStatus.Id AS StatusId
, loadWorkRequest.Id AS LoadRequestId
, loadStatus.Text AS Status
, routeIds.RouteIdentifier AS RouteName
, planRequest.Id AS PlanId
, originPartyRole.Id AS OriginId
, originParty.Id AS OriginPartyId
, originParty.LegalName AS Origin
, destinationPartyRole.Id AS DestinationId
, destinationParty.Id AS DestinationPartyId
, destinationParty.LegalName AS Destination
, COALESCE(firstSegmentLocation.Window_Start, originLocation.Window_Start) AS StartDate
, COALESCE(firstSegmentLocation.Window_Start, originLocation.Window_Start) AS BeginDate
, destLocation.Window_Finish AS EndDate
AS Number
FROM Domain.Loads (NOLOCK) AS l
INNER JOIN dbo.Lists (NOLOCK) AS loadStatus ON l.LoadStatusId = loadStatus.Id
INNER JOIN Domain.Routes (NOLOCK) AS routeIds ON routeIds.Id = l.RouteId
INNER JOIN Domain.BaseRequests (NOLOCK) AS loadWorkRequest ON loadWorkRequest.LoadId = l.Id
INNER JOIN Domain.BaseRequests (NOLOCK) AS planRequest ON planRequest.Id = loadWorkRequest.ParentWorkRequestId
INNER JOIN Domain.Schedules AS planSchedule ON planSchedule.Id = planRequest.ScheduleId
INNER JOIN Domain.Segments (NOLOCK) os on os.RouteId = routeIds.Id AND os.[Order] = 0
INNER JOIN Domain.LocationDetails (NOLOCK) AS originLocation ON originLocation.Id = os.DestinationId
INNER JOIN dbo.EntityRoles (NOLOCK) AS originPartyRole ON originPartyRole.Id = originLocation.DockRoleId
INNER JOIN dbo.Entities (NOLOCK) AS originParty ON originParty.Id = originPartyRole.PartyId
INNER JOIN Domain.LocationDetails (NOLOCK) AS destLocation ON destLocation.Id = routeIds.DestinationFacilityLocationId
INNER JOIN dbo.EntityRoles (NOLOCK) AS destinationPartyRole ON destinationPartyRole.Id = destLocation.DockRoleId
INNER JOIN dbo.Entities (NOLOCK) AS destinationParty ON destinationParty.Id = destinationPartyRole.PartyId
INNER JOIN dbo.TransportationModes (NOLOCK) lictm on lictm.Id = l.LoadInstanceCarrierModeId
INNER JOIN dbo.EntityRoles (NOLOCK) AS carrierPartyRole ON lictm.CarrierId = carrierPartyRole.Id
INNER JOIN dbo.Entities (NOLOCK) AS carrier ON carrierPartyRole.PartyId = carrier.Id
INNER JOIN dbo.EntityRoles (NOLOCK) AS respPartyRole ON l.ResponsiblePartyId = respPartyRole.Id
INNER JOIN dbo.Entities (NOLOCK) AS respParty ON respPartyRole.PartyId = respParty.Id
INNER JOIN Domain.LoadOrders (NOLOCK) lo ON lo.LoadInstanceId = l.Id
INNER JOIN Domain.Orders (NOLOCK) AS o ON lo.OrderInstanceId = o.Id
INNER JOIN Domain.BaseRequests (NOLOCK) AS loadRequest ON loadRequest.LoadId = l.Id
--Load Start Date
LEFT JOIN Domain.Segments (NOLOCK) AS segment ON segment.RouteId = l.RouteId AND segment.[Order] = 0
LEFT JOIN Domain.LocationDetails (NOLOCK) AS firstSegmentLocation ON firstSegmentLocation.Id = segment.DestinationId
LEFT JOIN dbo.Lists (NOLOCK) AS planningType ON l.PlanningTypeId = planningType.Id
LEFT JOIN dbo.EntityRoles (NOLOCK) AS billToRole ON o.BillToId = billToRole.Id
LEFT JOIN dbo.Entities (NOLOCK) AS billTo ON billToRole.PartyId = billTo.Id
WHERE o.CustomerId in (34236) AND originLocation.Window_Start >= '07/19/2015 00:00:00' AND originLocation.Window_Start < '07/25/2015 23:59:59' AND l.IsHistoricalLoad = 0
AND loadStatus.Id in (285, 286,289,611,290)
AND loadWorkRequest.ParentWorkRequestId IS NOT NULL
AND routeIds.RouteIdentifier IS NOT NULL
AND (planSchedule.EndDate IS NULL OR (planSchedule.EndDate is not null and CAST(CONVERT(varchar(10), planSchedule.EndDate,101) as datetime) > CAST(CONVERT(varchar(10),GETDATE(),101) as datetime))) ORDER BY l.Id DESC
linq:
//Get custom grouped data
var loadRequest = (from lq in returnList
let loadDisplayId = lq.LoadDisplayId
let origin = lq.OriginId //get this origin for route
let destination = lq.DestinationId // get this destination for route
group lq by new
{
RouteId = lq.RouteName,
PlanId = lq.PlanId,
Origin = lq.OriginId,
Destination = lq.DestinationId
}
into grp
select new
{
RouteId = grp.Key.RouteId,
PlanId = grp.Key.PlanId,
Origin = grp.Key.Origin,
Destination = grp.Key.Destination,
Loads = (from l in grp select l)
}).OrderBy(x => x.Origin).ToList();
I'm guessing you want to Group By column 1 but include columns 2 and 3 in your Select. Using a Group By you cannot do this. However, you can do this using a T-SQL Windowing function using the OVER() operator. Since you don't say how you want to aggregate, I cannot provide an example. But look at T-SQL Windowing functions. This article might help you get started.
One important thing you need to understand about GROUP BY is that you must assume that there are multiple values in every column outside of the GROUP BY list. In your case, you must assume that for each value of Column1 there would be multiple values of Column2 and Column3, all considered as a single group.
If you want your query to process any of these columns, you must specify what to do about these multiple values.
Here are some choices you have:
Pick the smallest or the largest value for a column in a group - use MIN(...) or MAX(...) aggregator for that
Count non-NULL items in a group - use COUNT(...)
Produce an average of non-NULL values in a group - use AVG(...)
For example, if you would like to find the smallest Column2 and an average of Column3 for each value of Column1, your query would look like this:
select
Column1, MIN(Column2), AVG(Column3)
from
TableName
group by
Column1