SQL query to find last date before and all dates after a condition using CASE statement - sql

• Suppliers having PO date before 01 Jan 21 won’t be considered
• Exception-If all suppliers have PO date before 1 Jan 21, supplier with latest PO date will be considered.
Check the image for reference
SELECT
A.IPN,
A.[Manufacturer/Supplier],
A.[Last PO#],
A.[Last PO Date]
FROM (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY IPN,[Manufacturer/Supplier]
ORDER BY
(CASE
WHEN [Last PO Date] >= '01/01/2021'
THEN [Last PO Date]
WHEN [Last PO Date] < '01/01/2021'
THEN MAX([Last PO Date])
ELSE NULL
END)
DESC, IPN DESC) AS rn
FROM dbo.Sheet1$
) A
WHERE rn = 1
Can anyone explain?

I used a common table expression (CTE) for selecting records when there are no rows after 2021-01-01, ordering by date.
WITH DATA_CTE AS (
SELECT
A.IPN,
A.[Manufacturer/Supplier],
A.[PO#],
A.[PO Date]
FROM
dbo.Sheet1$ A
WHERE
A.[PO Date] < '2021-01-01'
AND NOT EXISTS(
SELECT B.IPN
FROM dbo.Sheet1$ B
WHERE B.[PO Date] >= '2021-01-01'
)
ORDER BY A.[PO Date] DESC
)
SELECT
A.IPN,
A.[Manufacturer/Supplier],
A.[PO#],
A.[PO Date]
FROM
dbo.Sheet1$
WHERE
A.[Last PO Date] >= '2021-01-01'
UNION
SELECT
TOP 1
A.IPN,
A.[Manufacturer/Supplier],
A.[PO#],
A.[PO Date]
FROM
DATA_CTE

Related

Return only the highest row number for a partitioned column

I'm trying to partition a list of submitted machining jobs by the date they were submitted and return a maximum row number for each partition.
I have tried using Group By, but I want to retain all rows in the result. Partition By does what I need, but I want to display all rows except the maximum row number as blank.
SELECT [Created Date]
,row_number() over(partition by format([Created Date],'d','en-gb') order by [Created Date] desc) AS [Jobs Submitted That Day]
FROM [UK_App].[dbo].[rvxDevMCRequests]
order by [Created Date] desc
Results:
Created Date Jobs Submitted That Day
31/12/2014 1
31/10/2019 1
31/10/2019 2
31/10/2019 3
31/10/2018 1
31/10/2018 2
The order by function is not working correctly, and I can't figure out how to display only the highest row number. I would like it to output this:
Created Date Jobs Submitted That Day
31/12/2014 1
31/10/2018
31/10/2018 2
31/10/2019
31/10/2019
31/10/2019 3
Not an elegant solution:
SELECT [Created Date]
, case when row_number() over(partition by format([Created Date],'d','en-gb') order by [Created Date] desc)
= count(*) over(partition by format([Created Date],'d','en-gb'))
then count(*) over(partition by format([Created Date],'d','en-gb'))
else null end AS [Jobs Submitted That Day]
FROM [UK_App].[dbo].[rvxDevMCRequests]
order by [Created Date] desc
Try this one:
SELECT
a.CreatedDate,
CASE
WHEN y.rnum IS NULL
THEN ''
ELSE
a.JobsSubmitted
END AS JobsSubmitted
FROM
input a
LEFT OUTER JOIN
(
SELECT
x.CreatedDate, x.JobsSubmitted, x.rnum
FROM (
SELECT
a.*,
ROW_NUMBER() OVER(PARTITION BY a.CreatedDate ORDER BY a.JobsSubmitted DESC) AS rnum
FROM
input a
) x
WHERE
x.rnum = 1
) y
ON (
a.CreatedDate = y.CreatedDate
AND a.JobsSubmitted = y.JobsSubmitted
);
SQL Fiddle link for demo: http://www.sqlfiddle.com/#!18/511abf/17
Why are you using format()? There is no reason to convert a date to a string, especially in this case.
One significant issue is that the column [Created Date] has duplicates. When you order by that column, the duplicates can be in any order. In fact, two different order bys on the column in the same query can result in different ordering.
The solution to that is to capture the ordering once in a subquery and then use that:
select [Created Date],
(case when cnt = seqnum then seqnum
end) as [Jobs Submitted That Day]
from (select r.*,
row_number() over (partition by [Created Date] order by [Created Date] desc) as seqnum,
count(*) over (partition by [Created Date]) as cnt
from [UK_App].[dbo].[rvxDevMCRequests]
) r
order by [Created Date] desc, seqnum;
In the above query, seqnum captures the ordering, so it is used for the outer order by.

How to select max date over the year function

I am trying to select the max date over the year, but it is not working. Any ideas on what to do?
SELECT a.tkinit [TK ID],
YEAR(a.tkeffdate) [Rate Year],
max(a.tkeffdate) [Max Date],
tkrt03 [Standard Rate]
FROM stageElite.dbo.timerate a
join stageElite.dbo.timekeep b ON b.tkinit = a.tkinit
WHERE a.tkinit = '02672'
and tkeffdate BETWEEN '2014-01-01' and '12-31-2014'
GROUP BY a.tkinit,
tkrt03,
a.tkeffdate
Perhaps you only want it by year and not rolled up by calendar date. For SQL server you can try this.
SELECT
…
MaxDate = MAX(a.tkeffdate) OVER (PARTITION BY a.tkinit, YEAR(a.tkeffdate)))
…
Or you could modify the query above to group by the year instead of date-->
GROUP BY a.tkinit,
tkrt03,
YEAR(a.tkeffdate)
You seem to want only one row and all the columns. Use ORDER BY and TOP:
SELECT TOP (1) tr.tkinit as [TK ID],
YEAR(tr.tkeffdate) as [Rate Year],
a.tkeffdate as [Max Date],
tkrt03 as [Standard Rate]
FROM stageElite.dbo.timerate tr JOIN
stageElite.dbo.timekeep tk
ON tk.tkinit = tr.tkinit
WHERE tr.tkinit = '02672' AND
tr.tkeffdate >= '2014-01-01' AND
tr.tkeffdate < '2015-01-01'
ORDER tr.tkeffdate DESC;
Note that I also fixed your date comparisons and table aliases.

SQL Query: 1 Employee Position/Post as 2 results

I have a list of employees in their current post/position with their start date in the position and their employment start date.
I need a query to generate current position as one result and if the start date of the position does not match start date of employment show a historic position as a second result.
Data
[Employee Number] Position [Start Date] [Employment Start Date]
-----------------------------------------------------------------------
12345 Admin 01/01/2017 01/01/2016
Output
[Employee Number] Position [Start Date] [End Date]
-----------------------------------------------------------
12345 Admin 01/01/2017 NULL
12345 Historic 01/01/2016 31/12/2017
SELECT
[Employee Number],
[Position],
[Start Date],
NULL AS [End Date]
FROM
TABLE_NAME
UNION ALL
SELECT
[Employee Number],
'Historic' AS [Position],
[Employment Start Date] AS [Start Date],
DATEADD( DAY,-1,[Start Date] ) AS [End Date]
FROM
TABLE_NAME
WHERE
[Start Date] <> [Employment Start Date]
You can use union all:
select employee_number, position, start_date, cast(null as date) end_date
from data
union all
select employee_number, position, employment_start_date, dateadd(day, -1, start_date)
from data
where employment_start_date < start_date;
WITH table1 AS (
SELECT * FROM (
VALUES
('12345', 'Admin','2017-01-01','2016-01-01')
) AS a (EmployeeNumber, position,StartDate,EmploymentStartDate)
)
select EmployeeNumber, position,StartDate, CASE WHEN StartDate!=EmploymentStartDate THEN NULL ELSE EmploymentStartDate END AS EndDate from table1
union
Select EmployeeNumber,'Historic',EmploymentStartDate as StartDate,DATEADD(dd,-1,DATEADD(yy,1,StartDate)) AS EndDate
From table1 where StartDate!=EmploymentStartDate

SQL Calculate Percentage in Group By

I have an SQL query that is used as the basis for a report. The report shows the amount of fuel used grouped by Year, Month and Fuel Type. I would like to calculate the percentage of the total for each fuel type, but I'm not having much luck. In order to calculate the percentage of the whole, I need to be able to get the total amount of fuel used regardless of the group it is in and I can't seem to figure out how to do this. Here is my query:
SELECT Year([DT1].[TransactionDate]) AS [Year], Month([DT1].[TransactionDate]) AS [Month], DT1.FuelType, Format(Sum(DT1.Used),"#.0") AS [Total Used],
FROM (SELECT TransactionDate, FuelType, Round([MeterAfter]-[MeterBefore],2) AS Used FROM FuelLog) AS DT1
WHERE (((DT1.TransactionDate) Between [Start Date] And [End Date]))
GROUP BY Year([DT1].[TransactionDate]), Month([DT1].[TransactionDate]), DT1.FuelType
ORDER BY Year([DT1].[TransactionDate]), Month(DT1.TransactionDate), DT1.FuelType;
I tried adding the following as a subquery but I get an error saying the subquery returns more than one result.
(SELECT Sum(Round([MeterAfter]-[MeterBefore],2)) AS Test
FROM Fuellog
WHERE Year([Year]) and Month([Month])
GROUP BY Year([TransactionDate]), Month([TransactionDate]))
Once I get the total of all fuel I will need to divide the amount of fuel used by the total amount of both fuel types. Should I be approaching this a different way?
Try this
SELECT A.[Year]
,A.[Month]
,A.[FuelType]
,A.[Total Used]
,(A.[Total Used] / B.[Total By Year Month]) * 100 AS Percentage
FROM
(
SELECT Year([DT1].[TransactionDate]) AS [Year]
, Month([DT1].[TransactionDate]) AS [Month]
, DT1.FuelType
, Format(Sum(DT1.Used),"#.0") AS [Total Used]
FROM (
SELECT TransactionDate
, FuelType
, Round([MeterAfter]-[MeterBefore],2) AS Used
FROM FuelLog
) AS DT1
WHERE (((DT1.TransactionDate) Between [Start Date] And [End Date]))
GROUP BY Year([DT1].[TransactionDate]), Month([DT1].[TransactionDate]), DT1.FuelType
ORDER BY Year([DT1].[TransactionDate]), Month(DT1.TransactionDate), DT1.FuelType
) A
INNER JOIN
(
SELECT Sum(Round([MeterAfter]-[MeterBefore],2)) AS [Total By Year Month]
, Year([TransactionDate]) AS [Year]
, Month([TransactionDate])) AS [Month]
FROM Fuellog
GROUP
BY Year([TransactionDate])
, Month([TransactionDate]))
) B
ON A.[Year] = B.[Year]
AND A.[Month] = B.[Month]
You need to join to the totals -- something like this (untested might have typos)
SELECT
Year([DT1].[TransactionDate]) AS [Year],
Month([DT1].[TransactionDate]) AS [Month],
DT1.FuelType,
Format(Sum(DT1.Used),"#.0") AS [Total Used],
(Sum(DT1.Used) / FT.Total) * 100 AS Percent
FROM (
SELECT
TransactionDate,
FuelType,
Round([MeterAfter]-[MeterBefore],2) AS Used
FROM FuelLog
) AS DT1
JOIN (
SELECT
Sum(Round([MeterAfter]-[MeterBefore],2)) AS Total
FuelType
FROM Fuellog
WHERE TransactionDate Between [Start Date] And [End Date]
GROUP BY FuelType
) FT ON DT1.FuelType = FT.FeulType
WHERE DT1.TransactionDate Between [Start Date] And [End Date]
GROUP BY Year([DT1].[TransactionDate]), Month([DT1].[TransactionDate]), DT1.FuelType, FT.Total
ORDER BY Year([DT1].[TransactionDate]), Month(DT1.TransactionDate), DT1.FuelType, FT.Total;

SQL query for splitting the period of date into each date for corresponding employee id

I have one table with name "Employee"...It has 3 fields:
empid
from date
todate
I want to split the period of date (dates between from date & to date including both) for the corresponding emp id.
For example here's the table I've got:
emp id from date to date
1 1/1/2011 3/1/2011
2 5/1/2011 5/1/2011
From that I'm want to get this:
1 1/1/2011
1 2/1/2011
1 3/1/2011
2 5/1/2011
What's an SQL query that would do this for me?
You wants... I gives...
;with Employee([emp id],[from date],[to date]) as (
select 1, convert(datetime,'20110101'), convert(datetime,'20110103') union all
select 2, '20010105', '20110105'
)
-- your query below here
select [emp id], [from date] + w.number*1000 + v.number [the date]
from Employee e
inner join master..spt_values w
on w.type='P' and w.number <= datediff(d, [from date], [to date]) % 1000
inner join master..spt_values v
on v.type='P'
and v.number <= 999
and (w.number*1000) + v.number <= datediff(d, [from date], [to date])
order by [emp id], [the date]
Here's a simpler version if you don't ever deal with more than 6 years at a time
select [emp id], [from date] + v.number [the date]
from Employee e
inner join master..spt_values v
on v.type='P'
and v.number <= datediff(d, [from date], [to date])
order by [emp id], [the date]
A solution that uses a recursive CTE (works with SQL Server 2005+):
WITH Employee (emp_id, from_date, to_date) AS (
/* this is just a sample data definition */
SELECT 1, CAST('20110101' AS datetime), CAST('20110103' AS datetime) UNION ALL
SELECT 2, CAST('20110105' AS datetime), CAST('20110105' AS datetime)
),
unrolled AS (
/* and this is the recursive CTE */
SELECT
emp_id,
from_date AS date
FROM Employee
UNION ALL
SELECT
r.emp_id,
DATEADD(day, 1, r.date)
FROM Employee e
INNER JOIN unrolled r
ON e.emp_id = r.emp_id AND e.to_date > r.date
)
SELECT * FROM unrolled
ORDER BY emp_id, date