SQL Query for hours of the day - sql

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.

Related

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.

SQL How can I get a count of messages going out by month

I have a table that sends out messages, I would like to get a total count of the messages that have been going out month by month over the last year . I am new to SQL so I am having trouble with it . I am using MSSQL 2012 this is my sql
SELECT sentDateTime, MessageID, status AS total, CONVERT(NVARCHAR(10), sentDateTime, 120) AS Month
FROM MessageTable
WHERE CAST(sentDateTime AS DATE) > '2017-04-01'
GROUP BY CONVERT(NVARCHAR(10), sentDateTime, 120), sentDateTime, MessageID, status
ORDER BY Month;
I think the month() and year() functions are more convenient than datepart() for this purpose.
I would go for:
select year(sentDateTime) as yr, month(sentDateTime) as mon, count(*)
from MessageTable
where sentDateTime > '2017-04-01'
group by year(sentDateTime), month(sentDateTime)
order by min(sentDateTime);
Additional notes:
Only include the columns in the select that you care about. This would be the ones that define the month and the count.
Only include the columns in the group by that you care about. Every combination of the expressions in the group by found in the data define a column.
There is no need to convert sentDateTime to a date explicitly for the comparison.
The order by orders the results by time. Using the min() is a nice convenience.
Including the year() makes sure you don't make a mistake -- say by including data from 2018-04 with 2017-04.
-- this selects the part of the date you are looking for, replace this with the date format you are using, this should give you what you are looking for
SELECT DATEPART(mm, GETDATE())
SELECT COUNT(DATEPART(mm, sentDateTime)), MessageID, status
From MessageTable where Cast(sentDateTime as date) > '2017-04-01'
group by DATEPART(mm, sentDateTime), MessageID, status
order by DATEPART(mm, sentDateTime)
You can group by the month number of the sentDateTime with the function DATEPART(MONTH, sentDateTime). The next select will also yield results if no message was sent for a particular month (total = 0).
;WITH PossibleMonths AS
(
SELECT
M.PossibleMonth
FROM
(VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) M(PossibleMonth)
),
MonthTotals AS
(
select
COUNT(1) AS Total,
DATEPART(MONTH, sentDateTime) [Month]
From
MessageTable
where
Cast(sentDateTime as date) > '2017-04-01'
group by
DATEPART(MONTH, sentDateTime)
)
SELECT
P.PossibleMonth,
Total = ISNULL(T.Total, 0)
FROM
PossibleMonths AS P
LEFT JOIN MonthTotals AS T ON P.PossibleMonth = T.Month

How to get a minimum value and the year it represents

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.

How to count number of records per day?

I have a table in a with the following structure:
CustID --- DateAdded ---
396 2012-02-09
396 2012-02-09
396 2012-02-08
396 2012-02-07
396 2012-02-07
396 2012-02-07
396 2012-02-06
396 2012-02-06
I would like to know how I can count the number of records per day, for the last 7 days in SQL and then return this as an integer.
At present I have the following SQL query written:
SELECT *
FROM Responses
WHERE DateAdded >= dateadd(day, datediff(day, 0, GetDate()) - 7, 0)
RETURN
However this only returns all entries for the past 7 days. How can I count the records per day for the last 7 days?
select DateAdded, count(CustID)
from Responses
WHERE DateAdded >=dateadd(day,datediff(day,0,GetDate())- 7,0)
GROUP BY DateAdded
select DateAdded, count(CustID)
from tbl
group by DateAdded
about 7-days interval it's DB-depending question
SELECT DateAdded, COUNT(1) AS NUMBERADDBYDAY
FROM Responses
WHERE DateAdded >= dateadd(day,datediff(day,0,GetDate())- 7,0)
GROUP BY DateAdded
This one is like the answer above which uses the MySql DATE_FORMAT() function. I also selected just one specific week in Jan.
SELECT
DatePart(day, DateAdded) AS date,
COUNT(entryhash) AS count
FROM Responses
where DateAdded > '2020-01-25' and DateAdded < '2020-02-01'
GROUP BY
DatePart(day, DateAdded )
If your timestamp includes time, not only date, use:
SELECT DATE_FORMAT('timestamp', '%Y-%m-%d') AS date, COUNT(id) AS count FROM table GROUP BY DATE_FORMAT('timestamp', '%Y-%m-%d')
You could also try this:
SELECT DISTINCT (DATE(dateadded)) AS unique_date, COUNT(*) AS amount
FROM table
GROUP BY unique_date
ORDER BY unique_date ASC
SELECT count(*), dateadded FROM Responses
WHERE DateAdded >=dateadd(day,datediff(day,0,GetDate())- 7,0)
group by dateadded
RETURN
This will give you a count of records for each dateadded value. Don't make the mistake of adding more columns to the select, expecting to get just one count per day. The group by clause will give you a row for every unique instance of the columns listed.
select DateAdded, count(DateAdded) as num_records
from your_table
WHERE DateAdded >=dateadd(day,datediff(day,0,GetDate())- 7,0)
group by DateAdded
order by DateAdded
Unfortunately the best answer here IMO is a comment by #Profex on an incorrect answer , but the solution I went with is
SELECT FORMAT(DateAdded, 'yyyy-MM-dd'), count(CustID)
FROM Responses
WHERE DateAdded >= dateadd(day,datediff(day,0,GetDate())- 7,0)
GROUP BY FORMAT(DateAdded, 'yyyy-MM-dd')
ORDER BY FORMAT(DateAdded, 'yyyy-MM-dd')
Note that I haven't tested this SQL since I don't have the OP's DB , but this approach works well in my scenario where the date is stored to the second
The important part here is using the FORMAT(DateAdded, 'yyyy-MM-dd') method to drop the time without losing the year and month , as would happen if you used DATEPART(day, DateAdded)
When a day among last 7 days, has no record means, the following code will list out that day with count as zero.
DECLARE #startDate DATE = GETDATE() - 6,
#endDate DATE = GETDATE();
DECLARE #daysTable TABLE
(
OrderDate date
)
DECLARE #daysOrderTable TABLE
(
OrderDate date,
OrderCount int
)
Insert into #daysTable
SELECT TOP (DATEDIFF(DAY, #startDate, #endDate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #startDate)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b;
Insert into #daysOrderTable
select OrderDate, ISNULL((SELECT COUNT(*) AS OdrCount
FROM [dbo].[MyOrderTable] odr
WHERE CAST(odr.[CreatedDate] as date) = dt.OrderDate
group by CAST(odr.[CreatedDate] as date)
), 0) AS OrderCount from #daysTable dt
select * from #daysOrderTable
RESULT
OrderDate     OrderCount
2022-11-22     42
2022-11-23     6
2022-11-24     34
2022-11-25     0
2022-11-26     28
2022-11-27     0
2022-11-28     22
SELECT DATE_FORMAT(DateAdded, '%Y-%m-%d'),
COUNT(CustID)
FROM Responses
GROUP BY DATE_FORMAT(DateAdded, '%Y-%m-%d');

SQL query to group by day

I want to list all sales, and group the sum by day.
Sales (saleID INT, amount INT, created DATETIME)
NOTE: I am using SQL Server 2005.
if you're using SQL Server,
dateadd(DAY,0, datediff(day,0, created)) will return the day created
for example, if the sale created on '2009-11-02 06:12:55.000',
dateadd(DAY,0, datediff(day,0, created)) return '2009-11-02 00:00:00.000'
select sum(amount) as total, dateadd(DAY,0, datediff(day,0, created)) as created
from sales
group by dateadd(DAY,0, datediff(day,0, created))
For SQL Server:
GROUP BY datepart(year, datefield),
datepart(month, datefield),
datepart(day, datefield)
or faster (from Q8-Coder):
GROUP BY dateadd(DAY, 0, datediff(day, 0, created))
For MySQL:
GROUP BY year(datefield), month(datefield), day(datefield)
or better (from Jon Bright):
GROUP BY date(datefield)
For Oracle:
GROUP BY to_char(datefield, 'yyyy-mm-dd')
or faster (from IronGoofy):
GROUP BY trunc(created);
For Informix (by Jonathan Leffler):
GROUP BY date_column
GROUP BY EXTEND(datetime_column, YEAR TO DAY)
If you're using MySQL:
SELECT
DATE(created) AS saledate,
SUM(amount)
FROM
Sales
GROUP BY
saledate
If you're using MS SQL 2008:
SELECT
CAST(created AS date) AS saledate,
SUM(amount)
FROM
Sales
GROUP BY
CAST(created AS date)
For PostgreSQL:
GROUP BY to_char(timestampfield, 'yyyy-mm-dd')
or using cast:
GROUP BY timestampfield::date
if you want speed, use the second option and add an index:
CREATE INDEX tablename_timestampfield_date_idx ON tablename(date(timestampfield));
actually this depends on what DBMS you are using but in regular SQL convert(varchar,DateColumn,101) will change the DATETIME format to date (one day)
so:
SELECT
sum(amount)
FROM
sales
GROUP BY
convert(varchar,created,101)
the magix number 101 is what date format it is converted to
If you're using SQL Server, you could add three calculated fields to your table:
Sales (saleID INT, amount INT, created DATETIME)
ALTER TABLE dbo.Sales
ADD SaleYear AS YEAR(Created) PERSISTED
ALTER TABLE dbo.Sales
ADD SaleMonth AS MONTH(Created) PERSISTED
ALTER TABLE dbo.Sales
ADD SaleDay AS DAY(Created) PERSISTED
and now you could easily group by, order by etc. by day, month or year of the sale:
SELECT SaleDay, SUM(Amount)
FROM dbo.Sales
GROUP BY SaleDay
Those calculated fields will always be kept up to date (when your "Created" date changes), they're part of your table, they can be used just like regular fields, and can even be indexed (if they're "PERSISTED") - great feature that's totally underused, IMHO.
Marc
For oracle you can
group by trunc(created);
as this truncates the created datetime to the previous midnight.
Another option is to
group by to_char(created, 'DD.MM.YYYY');
which achieves the same result, but may be slower as it requires a type conversion.
The simplest and intuitive solution for MySQL is:
GROUP BY day(datefield)
use linq
from c in Customers
group c by DbFunctions.TruncateTime(c.CreateTime) into date
orderby date.Key descending
select new
{
Value = date.Count().ToString(),
Name = date.Key.ToString().Substring(0, 10)
}