SQL query to group by day - sql

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)
}

Related

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

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.

How can I group by date time column without taking time into consideration

I have a bunch of product orders and I'm trying to group by the date and sum the quantity for that date. How can I group by the month/day/year without taking the time part into consideration?
3/8/2010 7:42:00 should be grouped with 3/8/2010 4:15:00
Cast/Convert the values to a Date type for your group by.
GROUP BY CAST(myDateTime AS DATE)
GROUP BY DATEADD(day, DATEDIFF(day, 0, MyDateTimeColumn), 0)
Or in SQL Server 2008 onwards you could simply cast to Date as #Oded suggested:
GROUP BY CAST(orderDate AS DATE)
In pre Sql 2008 By taking out the date part:
GROUP BY CONVERT(CHAR(8),DateTimeColumn,10)
CAST datetime field to date
select CAST(datetime_field as DATE), count(*) as count from table group by CAST(datetime_field as DATE);
GROUP BY DATE(date_time_column)
Here's an example that I used when I needed to count the number of records for a particular date without the time portion:
select count(convert(CHAR(10), dtcreatedate, 103) ),convert(char(10), dtcreatedate, 103)
FROM dbo.tbltobecounted
GROUP BY CONVERT(CHAR(10),dtcreatedate,103)
ORDER BY CONVERT(CHAR(10),dtcreatedate,103)
Here is the example works fine in oracle
select to_char(columnname, 'DD/MON/yyyy'), count(*) from table_name group by to_char(createddate, 'DD/MON/yyyy');
Well, for me it was pretty much straight, I used cast with groupby:
Example:
Select cast(created_at as date), count(1) from dbname.tablename GROUP BY cast(created_at as date)
Note: I am using this on MSSQL 2016.
I believe you need to group by , in that day of the month of the year .
so why not using TRUNK_DATE functions .
The way it works is described below :
Group By DATE_TRUNC('day' , 'occurred_at_time')

How do I get a maximium daily value of a numerical field over a year in SQL

How do I get a maximium daily value of a numerical field over a year in MS-SQL
This would query the daily maximum of value over 2008:
select
datepart(dayofyear,datecolumn)
, max(value)
from yourtable
where '2008-01-01' <= datecolumn and datecolumn < '2009-01-01'
group by datepart(dayofyear,datecolumn)
Or the daily maximum over each year:
select
datepart(year,datecolumn),
, datepart(dayofyear,datecolumn)
, max(value)
from yourtable
group by datepart(year,datecolumn), datepart(dayofyear,datecolumn)
Or the day(s) with the highest value in a year:
select
Year = datepart(year,datecolumn),
, DayOfYear = datepart(dayofyear,datecolumn)
, MaxValue = max(MaxValue)
from yourtable
inner join (
select
Year = datepart(year,datecolumn),
, MaxValue = max(value)
from yourtable
group by datepart(year,datecolumn)
) sub on
sub.Year = yourtable.datepart(year,datecolumn)
and sub.MaxValue = yourtable.value
group by
datepart(year,datecolumn),
datepart(dayofyear,datecolumn)
You didn't mention which RDBMS or SQL dialect you're using. The following will work with T-SQL (MS SQL Server). It may require some modifications for other dialects since date functions tend to change a lot between them.
SELECT
DATEPART(dy, my_date),
MAX(my_number)
FROM
My_Table
WHERE
my_date >= '2008-01-01' AND
my_date < '2009-01-01'
GROUP BY
DATEPART(dy, my_date)
The DAY function could be any function or combination of functions which gives you the days in the format that you're looking to get.
Also, if there are days with no rows at all then they will not be returned. If you need those days as well with a NULL or the highest value from the previous day then the query would need to be altered a bit.
Something like
SELECT dateadd(dd,0, datediff(dd,0,datetime)) as day, MAX(value)
FROM table GROUP BY dateadd(dd,0, datediff(dd,0,datetime)) WHERE
datetime < '2009-01-01' AND datetime > '2007-12-31'
Assuming datetime is your date column, dateadd(dd,0, datediff(dd,0,datetime)) will extract only the date part, and then you can group by that value to get a maximum daily value. There might be a prettier way to get only the date part though.
You can also use the between construct to avoid the less than and greater than.
Group on the date, use the max delegate to get the highest value for each date, sort on the value, and get the first record.
Example:
select top 1 theDate, max(theValue)
from TheTable
group by theDate
order by max(theValue) desc
(The date field needs to only contain a date for this grouping to work, i.e. the time component has to be zero.)
If you need to limit the query for a specific year, use a starting and ending date in a where claues:
select top 1 theDate, max(theValue)
from TheTable
where theDate between '2008-01-01' and '2008-12-13'
group by theDate
order by max(theValue) desc

Execute count(*) on a group-by result-set

I am trying to do a nice SQL statement inside a stored procedure.
I looked at the issue of seeing the number of days that events happened between two dates.
My example is sales orders: for this month, how many days did we have sales orders?
Suppose this setup:
CREATE TABLE `sandbox`.`orders` (
`year` int,
`month` int,
`day` int,
`desc` varchar(255)
)
INSERT INTO orders (year, month, day, desc)
VALUES (2009,1,1, 'New Years Resolution 1')
,(2009,1,1, 'Promise lose weight')
,(2009,1,2, 'Bagel')
,(2009,1,12, 'Coffee to go')
For this in-data the result should be 3, since there has been three days with sale.
The best solution I found is as below.
However, making a temporary table, counting that then dropping it seemes excess. It "should" be possible in one statement.
Anyone who got a "nicer" solution then me?
/L
SELECT [Year], [Month], [Day]
INTO #Some_Days
FROM Quarter
WHERE Start >= '2009-01-01' AND [End] < '2009-01-16'
GROUP BY [Year], [Month], [Day]
SELECT count(*) from #Some_Days
Apologies if I'm misunderstanding the question, but perhaps you could do something like this, as an option:
SELECT COUNT(*) FROM
(SELECT DISTINCT(SomeColumn)
FROM MyTable
WHERE Something BETWEEN 100 AND 500
GROUP BY SomeColumn) MyTable
... to get around the temp-table creation and disposal?
There are two basic options which I can see. One is to group everything up in a sub query, then count those distinct rows (Christian Nunciato's answer). The second is to combine the multiple fields and count distinct values of that combined value.
In this case, the following formula coverts the three fields into a single datetime.
DATEADD(YEAR, [Quarter].Year, DATEADD(MONTH, [Quarter].Month, DATEADD(DAY, [Quarter].DAY, 0), 0), 0)
Thus, COUNT(DISTINCT [formula]) will give the answer you need.
SELECT
COUNT(DISTINCT DATEADD(YEAR, [Quarter].Year, DATEADD(MONTH, [Quarter].Month, DATEADD(DAY, [Quarter].DAY, 0), 0), 0))
FROM
Quarter
WHERE
[Quarter].Start >= '2009-01-01'
AND [Quarter].End < '2009-01-16'
I usually use the sub query route, but depending on what you're doing, indexes, size of table, simplicity of the formula, etc, this Can be faster...
Dems.
How about:
SELECT COUNT(DISTINCT day) FROM orders
WHERE (year, month) = (2009, 1);
Actually, I don't know if TSQL supports tuple comparisons, but you get the idea.
COUNT(DISTINCT expr) is standard SQL and should work everywhere.
You should use nested Select statements. Inner one should contain group by clause, and the outer one should count it. I think "Christian Nunciato" helped you already.
Select Count(1) As Quantity
From
(
SELECT [Year], [Month], [Day]
INTO #Some_Days
FROM Quarter
WHERE Start >= '2009-01-01' AND [End] < '2009-01-16'
GROUP BY [Year], [Month], [Day]
) AS InnerResultSet
SELECT [Year], [Month], [Day]
FROM Quarter
WHERE Start >= '2009-01-01' AND [End] < '2009-01-16'
GROUP BY [Year], [Month], [Day]
COMPUTE COUNT(*)