How to get youngest matching record in SQL? - sql-server

i am trying to create a table that tells me how long a product has aged until the date of the purchase. The code itself works, but I only want the youngest record to appear.
So far it matches the Order created with every historical receipt date of the product. However, I only want the youngest receipt date that is before Order created.
SELECT
OPF.Order_Number,
PD.[Product_Id],
PD.[Product_Title],
OPF.Order_Created,
MAX(R.[receipt_date]),
DATEDIFF(day, R.[receipt_date], OPF.Order_Created) AS 'Days Aged'
FROM [DataWarehouse].[dbo].[Product_D] PD (NOLOCK)
JOIN [DataWarehouse].[dbo].[Order_Product_F] OPF (NOLOCK)
ON PD.Product_Key = OPF.Product_Key
LEFT JOIN [Supply_Chain].[dbo].[Receipt_Product] RP (NOLOCK)
on PD.Product_Id = RP.product_id
JOIN [Supply_Chain].[dbo].[Receipt] R (NOLOCK)
ON RP.receipt_id = R.receipt_id
WHERE
OPF.Order_Number IN ('xxxxxxxx')
AND
R.[receipt_date] < OPF.Order_Created
GROUP BY
OPF.Order_Number,
PD.[Product_Id],
PD.[Product_Title],
OPF.Order_Created,
R.[receipt_date]
ORDER BY
DATEDIFF(day, R.[receipt_date], OPF.Order_Created) ASC
I think I will have to do a sub query, but I am not quite sure where to start.

Related

Two IDs matching one causing duplicates

I am trying to inner join however I keep getting this duplicate pop up where there are two job IDs matching one Invoice ID (inner joined with a middle table that links both).
I want to only get 1 invoice id and summing the total despite 2 job ids matching it.
Basically there is AINVOICEID (table:Invoice ) matching ABINVOICEID (table:INLines) and inside the INLines table, it contains ARJOBID that matches the JOBID in Jobs.
Select distinct sum(totalBASE) as InvoiceTotal,
DATEADD(MONTH, DATEDIFF(MONTH, 0, InvDate), 0)
from (select distinct left(JOBID,5)as JOBID
from jobs
group by JOBID
) jobs
inner join (select distinct ABINVOICEID, left(ARLJOBID,5) as arljobid
from INLines
group by ARLJOBID, ABINVOICEID
) INLines
on left(ARLJOBID,5) = left(JOBID,5)
inner join (select distinct AINVOICEID
, sum(totalBASE) as totalBASE
, InvDate
from Invoice
group by AINVOICEID, InvDate
) Invoice
on AINVOICEID = ABINVOICEID
where left(JOBID ,5)=left(ARLJOBID,5) and AINVOICEID = ABINVOICEID
and InvDate between '05/01/2022' AND '05/31/2022'
group by left(JOBID ,5), DATEADD(MONTH, DATEDIFF(MONTH, 0, InvDate), 0)
It is quite difficult to try and make sense of what you're asking without an example of the output that you're getting and what the expected output is.
However, I think you're wanting something like this:
SELECT I.AINVOICEID, SUM(I.totalBASE) AS totalBASE, InvDate
FROM Invoice I INNER JOIN
(
SELECT L.ABINVOICEID, J.JOBID
FROM INLines L INNER JOIN
Jobs J ON L.ARLJOBID = J.JOBID
GROUP BY L.ABINVOICEID, J.JOBID
) LJ ON I.AINVOICEID = L.ABINVOICEID
WHERE I.InvDate BETWEEN '05/01/2022' AND '05/31/2022'
GROUP BY I.AINVOICEID, InvDate
This is based on what your SQL query which doesn't really look like it needs to JOIN on the INLines or Jobs table because you're getting everything you need from the Invoice table in the SELECT ?
If this isn't what you're after, if you can elaborate a bit more, then the community on here should be able to better assist with your question.

Columns cannot bound in Joins

I am trying to calculate the leaves taken by employee and the addition and deduction in the salary for this month.
I am stuck at this point where I am joining these tables but I am getting error that I can't bound one of the column from table I specified in FROM clause.
Here is my query, If someone can help that'd be appreciated.
SELECT
[EI].[FirstName]+' '+[EI].[LastName] [Employee],
[Addition].[Amount] [AdditionAmount], [AdditionType].[FullName] [AdditionType],
[Deduction].[Amount] [DeductionAmount], [DeductionType].[FullName] [DeductionType],
MONTH([Leave].[ApprovedOn]) AS [Month], Count(*) AS [LeaveTaken]
FROM
[HRM].[tbl_EmployeeSalary] [Salary],
[HRM].[tbl_EmployeeInfo] [EI]
FULL JOIN [HRM].[tbl_EmployeeLeave] [Leave] ON [EI].[ID] = [Leave].[EmpCode]
FULL JOIN [HRM].[tbl_EmployeeSalaryAddition] [Addition] ON [Salary].[ID] = [Addition].[EmpSalaryCode]
FULL JOIN [HRM].[tbl_AdditionType] [AdditionType] ON [AdditionType].[ID] = [Addition].[AdditionTypeCode]
FULL JOIN [HRM].[tbl_EmployeeSalaryDeduction] [Deduction] ON [Salary].[ID] = [Deduction].[EmpSalaryCode]
FULL JOIN [HRM].[tbl_DeductionType] [DeductionType] ON [DeductionType].[ID] = [Deduction].[DeductionTypeCode]
WHERE
MONTH([Leave].[ApprovedOn]) = MONTH(GetDate())
GROUP BY
[EI].[FirstName]+' '+[EI].[LastName],
[Addition].[Amount], [AdditionType].[FullName],
[Deduction].[Amount] , [DeductionType].[FullName],
MONTH([Leave].[ApprovedOn])
I'm pretty much sure there is some sort of syntax issue like the order I am not able to set. I tried searching the issue but can't figure out in my case.
I don't have table structure still this query will remove your syntactical error
SELECT
[EI].[FirstName]+' '+[EI].[LastName] [Employee],
[Addition].[Amount] [AdditionAmount], [AdditionType].[FullName] [AdditionType],
[Deduction].[Amount] [DeductionAmount], [DeductionType].[FullName] [DeductionType],
MONTH([Leave].[ApprovedOn]) AS [Month], Count(*) AS [LeaveTaken]
FROM
[HRM].[tbl_EmployeeInfo] [EI]
FULL JOIN [HRM].[tbl_EmployeeLeave] [Leave]
ON [EI].[ID] = [Leave].[EmpCode],
[HRM].[tbl_EmployeeSalary] [Salary]
FULL JOIN [HRM].[tbl_EmployeeSalaryAddition] [Addition]
ON [Salary].[ID] = [Addition].[EmpSalaryCode]
FULL JOIN [HRM].[tbl_AdditionType] [AdditionType]
ON [AdditionType].[ID] = [Addition].[AdditionTypeCode]
FULL JOIN [HRM].[tbl_EmployeeSalaryDeduction] [Deduction]
ON [Salary].[ID] = [Deduction].[EmpSalaryCode]
FULL JOIN [HRM].[tbl_DeductionType] [DeductionType]
ON [DeductionType].[ID] = [Deduction].[DeductionTypeCode]
WHERE
MONTH([Leave].[ApprovedOn]) = MONTH(GetDate())
GROUP BY
[EI].[FirstName]+' '+[EI].[LastName],
[Addition].[Amount], [AdditionType].[FullName],
[Deduction].[Amount] , [DeductionType].[FullName],
MONTH([Leave].[ApprovedOn])

Get's records where gap between two dates is less than or equal to 5 days

I have two tables: tickets with unique ticket id and tickethistory with multiple records of a ticket (like open,attend,forward,close etc). Want to get records of
customers whose current ticket is open and last closed ticket is within 5 days gap. Using following query gives multiple records of closed tickets. Want last closed ticket actiondate in order to calculate days gap. If current open ticket and last closed ticket are within 5 days gap, want to consider current ticket as repeated.
SELECT A.ticketId,A.username,A.status,A.areaName,A.subject
,d.deptId,d.action,d.actionDate odate,g.actionDate cdate,g.status
FROM tb_tickets A
INNER JOIN (SELECT action, actiondate, ticketId, deptId FROM tb_ticketHistory WHERE action='Open') d
on a.ticketId = d.ticketid
INNER JOIN (SELECT th.ticketid, tt.username, tt.status, actiondate FROM tb_ticketHistory th
INNER JOIN tb_tickets tt
on th.ticketId = tt.ticketId WHERE th.action='closed') g
on a.username = g.username
WHERE d.deptId=5 AND a.status!='closed'
ORDER BY ticketId ASC
Since you haven't give exact structure and sample data, it's tough to give an exact answer. but you can try following code by tweaking it as your structure -
select CurrentOpenTickets.customerid, CurrentOpenTickets.ticketid from
(
select customerid, t.ticketid, actiondate from [dbo].[tb_ticketHistory ] th
inner join [dbo].[tb_Tickets] t on t.ticketid = th.ticketid
where t.status != 'C'
) CurrentOpenTickets
inner join
(select customerid, t.ticketid, actiondate from [dbo].[tb_ticketHistory ] th
inner join [dbo].[tb_Tickets] t on t.ticketid = th.ticketid
where th.status = 'C'
) PastClosedTickets
on CurrentOpenTickets.customerid = PastClosedTickets.customerid and datediff(DAY, CurrentOpenTickets.actiondate, PastClosedTickets.actiondate) <= 5

Extract Specific Data After a aggregation (Or any other solution for the desired result)

I want to select the Total "sales" of a specific "main_category" for the year 2016
(main categories that don't have sales in that year should appear as zero)
I have managed to select the "sales" of a specific "main category" with all the other "main_categories" (that doesn't have any sales) appearing as zero using below query:
SELECT
mc.name,
ISNULL(SUM(s.no_of_units * b.unit_price),0) AS tCatSales
FROM Sales s
INNER JOIN Invoice i ON i.invoice_ID = s.invoice_id
INNER JOIN Inventory inv ON inv.inventory_ID = s.inventory_ID
INNER JOIN Batch b ON b.batch_ID = inv.batch_ID
INNER JOIN Products p ON p.product_id = b.product_ID
INNER JOIN Category c ON c.category_ID = p.category_id
RIGHT JOIN Main_Category mc ON mc.cat_id = c.main_category
--WHERE YEAR(i.trans_date) = 2016
GROUP BY mc.name
--HAVING YEAR(i.trans_date)=2016
but when I try to further segregate it for year 2016 ONLY either by WHERE clause or HAVING clause, it stops showing "main_category" names that have zero sales in the year.
One thing that I can think of is to give the query invoices only from 2016
which I tried to did by doing something like,
Replacing the line:
INNER JOIN Invoice i ON i.invoice_ID = s.invoice_id
with:
INNER JOIN Invoice i ON i.invoice_ID IN (SELECT invoice_id FROM Invoice in2 WHERE Year(in2.trans_date)=2016)
which did display the categories with zero values but with increased the calculated Sales Amount (from 2069 to something 203151022.75).
I understand this addition is somewhat illogical and disrupts the whole Inner Joins but so far these are the closest thing I can think of or find on the web.
I REPEAT the desired result is: main categories that don't have sales in that year should appear as zero with the year given year/month/date
As Sean and Eli mentioned, RIGHT JOIN is not recommended, you may change it to LEFT JOIN, OR use subquery like this:
SELECT
mc.name,
tCatSales = ISNULL(
(
SELECT
SUM(s.no_of_units * b.unit_price) AS tCatSales
FROM Sales s
INNER JOIN Invoice i ON i.invoice_ID = s.invoice_id
INNER JOIN Inventory inv ON inv.inventory_ID = s.inventory_ID
INNER JOIN Batch b ON b.batch_ID = inv.batch_ID
INNER JOIN Products p ON p.product_id = b.product_ID
INNER JOIN Category c ON c.category_ID = p.category_id
WHERE mc.cat_id = c.main_category
AND YEAR(i.trans_date) = 2016
) , 0)
FROM Main_Category mc
try this:
WHERE ISNULL(YEAR(i.trans_date), 1) = 2016
if you put simple equals conditions on outer join it will eliminate nulls, which give zero-valued rows you desire.
Also note that something like:
WHERE YEAR(i.trans_date) = 2016
is not sargable, see here

How can I nest a query as a variable in SQL?

Obviously, SQL isn't my first language, so I need help with something that is probably trivial.
I have the following query:
SELECT Airports.IATA_Code,
COUNT(*) AS Departures,
(SELECT COUNT(*) FROM Flights WHERE DestinationAirportId = 63384) AS Arrivals,
SUM(Flights.Tickets) AS Tickets,
SUM(Flights.Fare * Flights.Tickets) As Revenue,
AVG(Flights.Demand) AS Demand
FROM Flights
LEFT JOIN Airports
ON Flights.OriginAirportId = Airports.Id
WHERE AnalysisId = 2
GROUP BY IATA_Code
ORDER BY Tickets DESC
This query works fine, but I need to replace the hard-coded id of 63384 with the actual Airport Id. This would be Airports.Id but when I try that, I get the following error:
Column 'Airports.Id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Solved!
Just needed to group by the Airport Id as well:
SELECT Airports.IATA_Code,
COUNT(*) AS Departures,
(SELECT COUNT(*) FROM Flights WHERE DestinationAirportId = Airports.Id) AS Arrivals,
SUM(Flights.Tickets) AS Tickets,
SUM(Flights.Fare * Flights.Tickets) As Revenue,
AVG(Flights.Demand) AS Demand
FROM Flights
LEFT JOIN Airports
ON Flights.OriginAirportId = Airports.Id
WHERE AnalysisId = 2
GROUP BY IATA_Code, Airports.Id <---------------------------
ORDER BY Tickets DESC
Just guessing here... there should be a FK on OriginAirportId referencing Airports.Id. If that's the case, you can do an inner join instead of left join.
Also, try using CROSS APPLY if that's an option for you.
SELECT a.IATA_Code,
COUNT(*) AS Departures,
t.Arrivals,
SUM(f.Tickets) AS Tickets,
SUM(f.Fare * f.Tickets) As Revenue,
AVG(f.Demand) AS Demand
FROM Flights f
INNER JOIN Airports a
ON f.OriginAirportId = a.Id
CROSS APPLY (
SELECT COUNT(*) AS Arrivals
FROM Flights f1
WHERE f1.DestinationAirportId = a.Id) t
WHERE AnalysisId = 2
GROUP BY IATA_Code, a.Id
ORDER BY Tickets DESC
I didn't test this code so please just use it as reference only please.
Or you can even try this...
;WITH AirportDepartureCount AS (
SELECT
OriginAirportId AS AirportId,
Count(*) AS DepartCount,
SUM(f.Tickets) AS Tickets,
SUM(f.Fare * f.Tickets) As Revenue,
AVG(f.Demand) AS Demand
FROM Flights
GROUP BY OriginAirportId
), AirportArrivalCount AS (
SELECT DestinationAirportId AS AirportId, COUNT(*) AS ArrivalCount
FROM Flights
GROUP BY DestinationAirportId
)
SELECT a.Id, a.IATA_Code,
COALESCE(depart.DepartCount,0) AS DepartCount,
COALESCE(arrival.ArrivalCount,0) AS ArrivalCount,
COALESCE(depart.Tickets,0) AS Tickets,
COALESCE(depart.Revenue,0) AS Revenue,
COALESCE(depart.Demand,0) AS Demand
FROM Airports a
LEFT JOIN AirportDepartureCount depart
ON a.Id = depart.AirportId
LEFT JOIN AirportArrivalCount arrival
ON a.Id = arrival.AirportId
ORDER BY COALESCE(depart.Tickets,0) DESC
Main difference here is that this code accounts for all airports (even those that did not have any flights). In your solution, you're ignoring any airports that did not have any departing flights. Perhaps that's by design but thought I'd throw this out there for completeness sake... ;)

Resources