How to get a minimum value and the year it represents - sql

I have a list of orders in a table. these all have a date against them. How do I write a query to return the minimum orders in a year and the associated year.
SELECT Max(YearCounts.[CountForYear]) AS [MinForYear]
FROM ( SELECT COUNT(PK) AS [CountForYear] FROM Orders
WHERE DATEPART( year , TransactionDate) > '2002'
GROUP BY DATEPART( Year, TransactionDate ) ) YearCounts
So I am looking for 98008 orders in 2003 as an example
Thanks for the answers, I checked them out, the sub query option executed fastest. I take on board the single quotes comments, thanks for the assistance.

Just use TOP 1
SELECT TOP 1 YearCounts.[CountForYear] AS [MinForYear],
YearCounts.[YEAR]
FROM ( SELECT COUNT(PK) AS [CountForYear],
DATEPART( year , TransactionDate) as [YEAR] FROM Orders
WHERE DATEPART( year , TransactionDate) > '2002'
GROUP BY DATEPART( Year, TransactionDate ) ) YearCounts
ORDER BY YearCounts.[CountForYear]

You can do this without a subquery, just by using top and order by:
SELECT TOP 1 DATEPART(year, TransactionDate), COUNT(PK) AS CountForYear
FROM Orders o
WHERE DATEPART(year , TransactionDate) > 2002
GROUP BY DATEPART(Year, TransactionDate )
ORDER BY COUNT(PK) DESC ;
You can also write this using the year function (which I personally find easier to read):
SELECT TOP 1 YEAR(TransactionDate), COUNT(PK) AS CountForYear
FROM Orders o
WHERE YEAR(TransactionDate) > 2002
GROUP BY YEAR(TransactionDate)
ORDER BY COUNT(PK) DESC ;
Your original query had single quotes around '2002'. This is unnecessary. You should express numeric constants without single quotes. Only use single quotes for string and date constants.

Related

T-SQL query to summarize total per month per year, and cumulative amounts to date

I have a database table that captures every Sales Transaction:
Transactions
(
ID INT,
TransactionDate DATETIME,
SalesAmount MONEY
)
I want to write a T-SQL query which returns a report (snapshot sample below). First column it lists the month, next column Total-Sales per month within year, and last column cumulative amount of that year up to this month. Only for year of 2018.
Any thoughts or solutions? Thank you.
Try this:
;with cte as
(
Select
YEAR(TransactionDate) as [Year],
MONTH(TransactionDate) as [Month],
SUM (SalesAmount) as [MonthlySales],
DATEPART(m, TransactionDate) as [MonthNumber]
from Transactions
group by YEAR(TransactionDate), MONTH(TransactionDate)
)
select
a.[Month], a.MonthlySales as [MonthlySales 2018], SUM(b.MonthlySales) as [Cumulative 2018]
from cte a inner join cte b on a.MonthNumber >= b.MonthNumber
WHERE (a.[Year]) = 2018 AND (b.[Year]) = 2018
group by a.[Month], a.MonthlySales
ORDER by a.[Month]
Try this one:
With Q
as
(
Select DatePart(yyyy,TransactionDate) 'Year',DatePart(m,TransactionDate) 'Month', sum(SalesAmount) 'Sales'
From Transactions
Group by DatePart(yyyy,TransactionDate),DatePart(m,TransactionDate)
)
Select q.Year,q.Month,( Select sum(q1.Sales)
From Q q1
Where q1.Year=q.Year
And q1.Month <= q.Month
) 'Cumulative Sale'
From Q q
Order by q.Year,q.Month
You would use aggregation and window functions:
select datename(month, transaction_date) as mon,
sum(salesAmount) as monthly_sales,
sum(salesAumount) over (order by min(transaction_date)) as running_amount
from transactions t
where t.transaction_date >= '2018-01-01' and
t.transaction_date < '2019-01-01'
group by datename(month, transaction_date)
order by min(transaction_date);

Issues with grouping this SQL query

So I'm trying to find the month/year that had the highest number of sale transactions.
my query currently is:
SELECT
DATENAME(M, OrderDate) as orderMonth,
year(OrderDate) as orderYear,
count(SalesOrderID) as orderCount
FROM
Sales.SalesOrderHeader soh
GROUP BY OrderDate
HAVING SUM(soh.SalesOrderID) >= ALL (
SELECT SUM(SalesOrderID) FROM Sales.SalesOrderHeader
GROUP BY OrderDate
)
however if I run everything above the HAVING line so that it returns all columns instead of just the highest column, it returns several duplicates of months/years and the orderCounts. for example, June 2011 has about 30 rows being returned in this query, each of those ranging somewhere between 2 and 11 orderCounts, in total the query returns 1124 rows, where it should only be returning 38 since the sales range from 2011 - 2014 and there's 38 months total within that range.
I'm pretty sure I need to specify a monthly group and should be changing my GROUP BYs to something like:
GROUP BY DATENAME(month, soh.OrderDate), DATENAME(YYYY, soh.OrderDate)
but then i get an error "Each GROUP BY expression must contain at least one column that is not an outer reference"
Your problem is that you are aggregating by OrderDate rather than by the month and year. So, your version of the query should look like:
SELECT DATENAME(MONTH, OrderDate) as orderMonth,
YEAR(OrderDate) as orderYear,
COUNT(*) as orderCount
FROM Sales.SalesOrderHeader soh
GROUP BY DATENAME(MONTH, OrderDate), YEAR(OrderDate)
HAVING COUNT(*) >= ALL (SELECT COUNT(*)
FROM Sales.SalesOrderHeader soh2
GROUP BY DATENAME(MONTH, OrderDate), YEAR(OrderDate)
);
However, no one would really write the query like that. It is simpler and more performant to use TOP and ORDER BY. The equivalent of your query is:
SELECT TOP (1) WITH TIES DATENAME(MONTH, OrderDate) as orderMonth,
YEAR(OrderDate) as orderYear,
COUNT(*) as orderCount
FROM Sales.SalesOrderHeader soh
GROUP BY DATENAME(MONTH, OrderDate), YEAR(OrderDate)
ORDER BY orderCount DESC;
Both these return all months with the maximum value -- if there are duplicates. If you want to guarantee only one row in the result set, use SELECT TOP (1) rather than SELECT TOP (1) WITH TIES.
Not sure which sql syntax you are using, but you could just sort by transactions and select the highest record?
SELECT top 1
DATENAME(M, OrderDate) as orderMonth,
year(OrderDate) as orderYear,
count(SalesOrderID) as orderCount
FROM
Sales.SalesOrderHeader soh
Group by orderMonth, orderYear
order by orderCount asc

Count the number of rows each month in SQL Server

I'm using SQL Server. I've a following table Orders:
Orders (Id, ItemId, CustomerId, Quantity, OrderDateTime)
I want to count the number of orders each month. I've written 2 of the following query.
Query #1:
SELECT
MONTH(OrderDateTime) AS MonthCol,
YEAR(OrderDateTime) AS YearCol,
COUNT(id) AS OrderCount
FROM
Orders
WHERE
OrderDateTime >= '2000' AND OrderDateTime <= '2018'
GROUP BY
YEAR(OrderDateTime), MONTH(OrderDateTime)
ORDER BY
YearCol, MonthCol
Query #2:
SELECT
DATEPART(mm, OrderDateTime) AS Month,
COUNT(*) AS OrderCount
FROM
Orders
WHERE
OrderDateTime >= '2000' AND OrderDateTime <= '2018'
GROUP BY
DATEPART(mm, OrderDateTime)
Issue with both queries is that I'm not getting the columns with 0 orders. How will I get it?
SQL will not give you data about months and year which do not exist as rows. To get 0 order rows you'd need to right join the results with a calendar table containing all needed months and years or you can also use a tally table.
Select T.MonthCol, T.YearCol,OrderCount= COALESCE(OrderCount,0)
from
(
SELECT MONTH(OrderDateTime) AS MonthCol, YEAR(OrderDateTime) AS YearCol, count(id) AS OrderCount
FROM Orders
WHERE OrderDateTime >= '2000' AND OrderDateTime <= '2018'
GROUP BY YEAR(OrderDateTime), MONTH(OrderDateTime)
ORDER BY YearCol, MonthCol)
P
RIGHT JOIN
(
select * from
( values (2000),(2001),(2002),(2003),(2004),(2005),(2006),(2007),(2008))v(YearCol)
cross join
( values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12))u(MonthCol)
)T
on P.MonthCol=T.MonthCol
and P.YearCol=T.YearCol
I would be inclined to use a recursive CTE for this -- this gives pretty easy flexibility on the range you want:
with dates as (
select cast('2000-01-01' as date) dte
union all
select dateadd(month, 1, dte)
from dates
where dte < '2018-12-01'
)
select year(OrderDateTime) AS year,
month(OrderDateTime) AS month,
count(o.id) as OrderCount
from dates left join
orders o
on d.OrderDateTime >= dates.dte and
d.OrderDateTime < dateadd(month, 1, dates.dte)
group by year(OrderDateTime), month(OrderDateTime)
order by year(OrderDateTime), month(OrderDateTime)
option (maxrecursion 0);
Notes:
This uses the JOIN to do the filtering. This makes it safer to change the range that you are looking for.
I find the year() and month() functions to be more convenient datepart().
When using date parts, spell them out. Why waste brain power trying to remember if mm really means months or minutes?
I added an order by. Presumably you want the results in chronological order.

Grouping by Week in SQL, but displaying full datetime?

the following statement:
group by datepart(wk, createdon)
Groups the selected rows according to the week in which they fall. My select statement shows the following:
SELECT
datepart(wk, createdon) week,
How do I display the actual datetime of the week("12-10-2012"), instead of the number ("12")?
If I understand you correctly, you're wanting to group by week but also return the full datetime. You must include the selected fields in aggregate columns.
Thusly should work:
SELECT DATEPART(wk, createdon) week, createdon
FROM TableName
GROUP BY DATEPART(wk, createdon), createdon
Works on MSSQL2008R2
Edit:
As the OP seems to want the starting date of the week, SO has the answer.
One option is using a cte with ROW_NUMBER instead:
WITH CTE AS
(
SELECT
RN = ROW_NUMBER() OVER (PARTITION BY datepart(wk, createdon) ORDER BY createdon)
, DATEADD(ww, DATEDIFF(ww,0,createdon), 0) As Week
, *
FROM dbo.Table
)
SELECT * FROM CTE
WHERE RN = 1
You can't group by a week, and then show constituent parts of it, i.e. days. You will need group by the date instead.

SQL Query for hours of the day

I have a SQL Server 2008 database with a table that has a column (datetime datatype) recording when an order is placed.
I would like to run a query that will give a breakdown of total amount of orders per hour on any given date or date range but am unsure of the best way to write the query.
It should be something along the lines of:
SELECT DATEPART(HOUR, OrderDate) AS [Hour], COUNT(*) AS [Count]
FROM [Orders]
WHERE OrderDate BETWEEN #StartDate AND #EndDate --or whatever criteria
GROUP BY DATEPART(HOUR, OrderDate)
You can use DATEPART and GROUP BY to get this:
SELECT DATEPART(Hour, DateField), COUNT(*)
FROM Orders
WHERE Date = #DateParam -- or your range check here
GROUP BY DATEPART(Hour, Datefield)
I believe it would be as simple as this:
SELECT
[Hour] = DATEPART(HOUR,DateTimeField)
,Orders = COUNT(*)
FROM
tblORDERS
GROUP BY
DATEPART(HOUR,DateTimeField)
You're probably looking for something like:
;WITH OrdersPerHour AS
(
SELECT
CAST(OrderDate AS DATE) 'OrderDate',
DATEPART(HOUR, OrderDate) AS 'Hour',
SalesAmount
FROM
dbo.YourOrderTable
)
SELECT
OrderDate, Hour,
COUNT(*), -- number of orders
SUM(SalesAmount) -- sum of the amounts for those orders
FROM
OrdersPerHour
WHERE
OrderDate = '20120113' -- or whatever you're looking for
GROUP BY
OrderDate, Hour
Not sure if you mean the total sum of the order amounts - or the number of orders - when you say breakdown of total amount of orders per hour - if you need the count, just use COUNT(*) instead of the SUM(SalesAmount) I put in my query.