How to select max date over the year function - sql

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.

Related

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

• 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

Rewriting a long T- SQL query in a simpler way (SQL Server 2016)

I have the following T-SQL query that works but I am wondering if it can be written in a more elegant way?
SELECT *
FROM [2021_history]
WHERE FORMAT([Current Baseline DATE], 'yyyy-MM') = '2021-01'
AND FORMAT ([Reporting Date], 'yyyy-MM') = '2021-02'
UNION
SELECT *
FROM .[2021_history]
WHERE FORMAT([Current Baseline DATE], 'yyyy-MM') = '2021-02'
AND FORMAT([Reporting Date], 'yyyy-MM') = '2021-03'
UNION
SELECT *
FROM [2021_history]
WHERE FORMAT([Current Baseline DATE], 'yyyy-MM') = '2021-03'
AND FORMAT([Reporting Date], 'yyyy-MM') = '2021-04'
etc...etc...
UNION
SELECT *
FROM [2021_history]
WHERE FORMAT([Current Baseline DATE], 'yyyy-MM') = '2021-12'
AND FORMAT([Reporting Date], 'yyyy-MM') = '2021-11'
I think you just want to filter using the dates. You can simplify this to:
SELECT h.*
FROM [2021_history] h
WHERE [Current Baseline DATE] >= '2021-01-01' AND
[Current Baseline DATE] < '2021-02-01' AND
DATEDIFF(MONTH, [Current Baseline DATE], [Reporting Date]) = 1;
Note: This can use an index on [Current Baseline DATE] (which your current query cannot). If you had an index on [Reporting Date], the logic could be modified for that as well.
The UNION removes duplicates. So if you actually have duplicated rows (which seems like a data problem to me), then you would use SELECT DISTINCT h.*.

New to SQL. Would like to convert an IF(COUNTIFS()) Excel formula to SQL code and have SQL calculate it instead of Excel

I am running SQL Server 2008 R2 (RTM).
I have a SQL query that pulls Dates, Products, Customers and Units:
select
[Transaction Date] as Date,
[SKU] as Product,
[Customer Name] as Customer,
sum(Qty) as Units
from dataset
where [Transaction Date] < '2019-03-01' and [Transaction Date] >= '2016-01-01'
group by [Transaction Date], [SKU], [Customer Name]
order by [Transaction Date]
This pulls hundreds of thousands of records and I wanted to determine if a certain transaction was a new order or reorder based on the following logic:
Reorder: That specific Customer has ordered that specific product in the last 6 months
New Order: That specific Customer hasn’t ordered that specific product in the last 6 months
For that I have this formula in Excel that seems to be working:
=IF(COUNTIFS(A$1:A1,">="&DATE(YEAR(A2),MONTH(A2)-6,DAY(A2)),C$1:C1,C2,B$1:B1,B2),"Reorder","New Order")
The formula works when I paste it individually or in a smaller dataset, but when I try to copy paste it to all 500K+ rows, Excel gives up because it loops for each calculation.
This could probably be done in SQL, but I don’t have the knowledge on how to convert this excel formula to SQL, I just started studying it.
You're doing pretty well with the start of your query there. There are three additional functions you're looking to add to your query.
The first thing you'll need is the easiest. GETDATE() simply returns the current date. You'll need that when you're comparing the current date to the transaction date.
The second function is DATEDIFF, which will give you a unit of time between two dates (months, days, years, quarters, etc). Using DATEDIFF, you can say "is this date within the last 6 months". The format for this is pretty easy. It's DATEDIFF(interval, date1, date2).
The thrid function you're looking for is CASE, which allows you to tell SQL to give you one answer if one condition is met, but a different answer if a different condition is met. For your example, you can say "if the difference in days is < 60, return 'Reorder', if not give me 'New Order'".
Putting it all together:
SELECT CASE
WHEN DATEDIFF(MONTH, [Transaction Date], GETDATE()) <= 6
THEN 'Reorder'
ELSE 'New Order'
END as ORDER_TYPE
,[Transaction Date] AS DATE
,[SKU] AS PRODUCT
,[Customer Name] AS CUSTOMER
,Qty AS UNITS
FROM DATASET
For additonal examples on CASE, take a look at this site: https://www.w3schools.com/sql/sql_ref_case.asp
For additional examples on DATEDIFF, take a look here: See the
following webpage for examples and a chance to try it out:
https://www.w3schools.com/sql/func_sqlserver_datediff.asp
SELECT CASE
WHEN Datediff(day, [transaction date], Getdate()) <= 180 THEN 'reorder'
ELSE 'Neworder'
END,
[transaction date] AS Date,
[sku] AS Product,
[customer name] AS Customer,
qty AS Units
FROM datase
If I understand correctly, you want to peak at the previous date and make a comparison. This suggests lag():
select (case when lag([Transaction Date]) over (partition by SKU, [Customer Name] order by [Transaction Date]) >
dateadd(month, -6, [Transaction Date])
then 'Reorder'
else 'New Order'
end) as Order_Type
[Transaction Date] as Date,
[SKU] as Product,
[Customer Name] as Customer,
sum(Qty) as Units
from dataset d
group by [Transaction Date], [SKU], [Customer Name];
EDIT:
In SQL Server 2008, you can emulate the LAG() using OUTER APPLY:
select (case when dprev.[Transaction Date] >
dateadd(month, -6, d.[Transaction Date])
then 'Reorder'
else 'New Order'
end) as Order_Type
d.[Transaction Date] as Date,
d.[SKU] as Product,
d.[Customer Name] as Customer,
sum(d.Qty) as Units
from dataset d outer apply
(select top (1) dprev.*
from dataset dprev
where dprev.SKU = d.SKU and
dprev.[Customer Name] = d.[Customer Name] and
dprev.[Transaction Date] < d.[Transaction Date]
order by dprev.[Transaction Date] desc
) dprev
group by d.[Transaction Date], d.[SKU], d.[Customer Name];

SQL to get the dates between start date is included and end date is excluded

SELECT [order id],
pickingdate
FROM td_order1
WHERE sku = xyz
GROUP BY pickingdate,
[order id]
HAVING pickingdate >= Min(pickingdate)
AND pickingdate <= Max(pickingdate)
ORDER BY pickingdate
Is there anything wrong in this query?
What is wrong with the query is that you are using unaggregated columns in the having. My recommendation is to use window functions:
SELECT o.*
FROM (SELECT o.*,
MIN(pickingdate) OVER (PARTITION BY sku) as min_pd,
MAX(pickingdate) OVER (PARTITION BY sku) as max_pd
FROM td_order1 o
WHERE sku = xyz
) o
WHERE pickingdate > min_pd and pickingdate < max_pd
ORDER BY pickingdate;
Modify your condition as :
pickingdate < Max(pickingdate)
to exclude end date

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;