SQL Sum of orders by date - sql

I should know this but for some reason its getting me stumped.
This simple code is outputting all orders by day
USE [K.1]
Select CreatedAt,Identifier,RoundedPriceSum from StarOrder
where SiteID = 1
and OrderType <>2
and CreatedAt between '2015/01/01' and '2015/08/20'
CreatedAt is a date, Identifier is unique order ID and RoundedPriceSum the total of the order.
Is it possible to amend the code to provide a total of RoundedPriceSum per day_

Use GROUP BY:
Select cast(CreatedAt as date) as CreatedDay, SUM(RoundedPriceSum)
from StarOrder so
where SiteID = 1 and OrderType <> 2 and
CreatedAt >= '2015-01-01' and
CreatedAt < '2015/08/20'
group by cast(CreatedAt as date)
order by CreatedDay;
Notes on changes to the query:
Changed the dates to ISO standard YYYY-MM-DD format.
Replaced the BETWEEN with >= and <. This works better for dates with times.
Use cast(as date) to remove the time component.
Added an ORDER BY so the results are in order by day.

select s.CreatedAt,s.Identifier,x.tot
from StarOrder s
join
(select CreatedAt,sum(RoundedPriceSum) as tot
from StarOrder
where SiteID = 1
and OrderType <>2
and CreatedAt between '2015/01/01' and '2015/08/20'
group by createdat) x
on x.createdat = s.createdat
where SiteID = 1
and OrderType <>2
and s.CreatedAt between '2015/01/01' and '2015/08/20'

Related

Need to generate "to date" from 2 (or more) different "from dates"

I have a cost table with id, price, and from date. I don't have a "to date". So item1 may have the price of £50 from 01/01/2019 in one row, then item1 will then have the price of £55 from 01/01/2020, in a second row.
If I want to know the price of item 1 today, I couldn't use WHERE today >= fromdate and <= todate.
How do I add "todate"? Where todate is the day before the next row's fromdate?
Ideally need to do this as view, want to avoid creating tables/stored proc, if possible?
Thanks
To get today's price get the row with the latest date not greater than today:
select c.price
from cost c
where c.id = 'Item1'
and c.fromdate = (
select max(fromdate) from cost
where id = c.id and fromdate <= getdate()
)
Or:
select top 1 price
from cost
where id = 'Item1' and fromdate <= getdate()
order by fromdate desc
To create a todate column:
with cte as (
select *, row_number() over (partition by id order by fromdate) rn
from cost
)
select c.id, c.price, c.fromdate, dateadd(day, -1, cc.fromdate) todate
from cte c left join cte cc
on cc.id = c.id and cc.rn = c.rn + 1
See a simplified demo.
As commented by Peter Schneider, a sensible option would be to use window function lead() to recover the fromdate of the next record for the same id:
select
t.*,
lead(fromdate) over(partition by id order by fromdate) todate
from mytable t
Note that with this technique, the record that has the highest fromdate for each id will have todate set to null. If you want to assign a default end date you can use coalesce().
You can put this in a view:
create view myview as
select
t.*,
lead(fromdate) over(partition by id order by fromdate) todate
from mytable t
And then you can query the view for the current price of a given item:
select *
from myview
where
id = ?
and getdate() >= fromdate
and (todate is null or getdate() < todate)

find people who have values in a specific date range but not in others

I am querying a User based database, and trying to find people that have made purchases withing a certain date range only.
e.g:
bring back all the people that purchased only between '2017-7-01' and '2017-08-01' but have not purchased since.
I have tried:
select payment_id
from table1
where created_at between '2017-7-01'
and '2017-08-01'
and not between '2017-7-01' and '2017-08-01';
and all kinds of variations on this.
I guess a subquery is in order here, but don't really know how to approach
hope someone can help :)
Thanks
select payment_id
from (
select payment_id
from table1
where created_at between '2017-7-01' and '2017-08-01' )
where created_at > '2017-08-01'
Use conditional COUNT() to see if user have any purchase in that date range and no purchase after the upper range limit.
Also you need something related to users, I guess user_id so you can group everything.
SELECT user_id
FROM yourTable
GROUP BY user_id
HAVING COUNT(CASE WHEN created_at between '2017-07-01'
and '2017-08-01'
THEN 1
END) > 0
AND COUNT(CASE WHEN created_at > '2017-08-01'
THEN 1
END) = 0
Select userid
From table1
Where userid not in (select userid from table1 where createdat between #startdate and #enddate)
Where createdat > #enddate
If you want to filter ensuring the MAX(date) is less than 2017-08-01 then you can use GROUP BY with HAVING.
Ex.
select payment_id
from table1
where created_at between '2017-07-01' AND '2017-08-01'
GROUP BY payment_id
HAVING MAX(created_at) < '2017-08-01' --most recent date less than requested date

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');

Refactor subqueries using GROUP BY/HAVING?

I'm building a MySQL query to determine how many items from each of several categories appear in a given date range. My initial attempt looked like this:
select Title,
(select count(*) from entries where CategoryID=1
and Date >= #StartDate and Date <= #EndDate) as Cat1,
(select count(*) from entries where CategoryID=2
and Date >= #StartDate and Date <= #EndDate) as Cat2,
(select count(*) from entries where CategoryID is null
and Date >= #StartDate and Date <= #EndDate) as UnkownCategory
from entries
where Date >= #StartDate and Date <= #EndDate
The table is quite large and I'd like to refactor the query to speed it up, but I'm not sure how - can this be rewritten using GROUP BY/HAVING statements or is there another way I'm missing?
Edit: Sample result set - something like this:
Title | Category 1 Total | Category 2 Total | Unknown Category Total
ABC 1 3 0
DEF 2 7 2
select Title, SUM(CategoryID=1) as Cat1, SUM(categoryID=2) as Cat2,
SUM(categoryID IS NULL) as UnknownCategory
FROM entries
WHERE Date BETWEEN #StartDate AND #EndDate
GROUP BY Title
You can stick expressions in sum() functions: truth equals 1, false equals 0. Also I used the BETWEEN operator which is a little faster.
An alternative that would return a different result layout but is a little conceptually simpler:
select Title, CategoryID, count(*)
from entries
WHERE Date BETWEEN #StartDate AND #EndDate
group by Title, CategoryID
How about grouping by category id then using the having statement to filter out specific categories, like:
select CategoryID, count(*)
from entries
where Date >= #StartDate AND Date <= #EndDate
group by CategoryID
having CategoryID = 1 or CategoryID = 2 or CategoryID is null
If there are multiple titles per category you could group by both fields:
select Title, CategoryID, count(*)
from entries
where Date >= #StartDate AND Date <= #EndDate
group by Title, CategoryID
having CategoryID = 1 or CategoryID = 2 or CategoryID is null
Select COUNT(*), sTitle, CategoryID FROM entries
WHERE Date >= #StartDate and Date <= #EndDate
GROUP BY CategoryID, sTitle

Group by date only on a Datetime column

Having a table with a column like: mydate DATETIME ...
I have a query such as:
SELECT SUM(foo), mydate FROM a_table GROUP BY a_table.mydate;
This will group by the full datetime, including hours and minutes. I wish to make the group by, only by the date YYYY/MM/DD not by the YYYY/MM/DD/HH/mm.
How to do this?
Cast the datetime to a date, then GROUP BY using this syntax:
SELECT SUM(foo), DATE(mydate) FROM a_table GROUP BY DATE(a_table.mydate);
Or you can GROUP BY the alias as #orlandu63 suggested:
SELECT SUM(foo), DATE(mydate) DateOnly FROM a_table GROUP BY DateOnly;
Though I don't think it'll make any difference to performance, it is a little clearer.
I found that I needed to group by the month and year so neither of the above worked for me. Instead I used date_format
SELECT date
FROM blog
GROUP BY DATE_FORMAT(date, "%m-%y")
ORDER BY YEAR(date) DESC, MONTH(date) DESC
Or:
SELECT SUM(foo), DATE(mydate) mydate FROM a_table GROUP BY mydate;
More efficient (I think.) Because you don't have to cast mydate twice per row.
SELECT SUM(No), HOUR(dateofissue)
FROM tablename
WHERE dateofissue>='2011-07-30'
GROUP BY HOUR(dateofissue)
It will give the hour by sum from a particular day!
this worked for me
select
CONVERT(date, CONVERT(VARCHAR(10),sd.Date,112)) as Date,
sd.CodId as CodId,
p.Description ,
sum(sd.Quantity)as Quantity,
sum(sd.TotalQuantityXPriceWithIva) as TotalWithIva
from
SaleDetails sd
join Sales s on sd.SaleId = s.SaleId
join Products p on sd.ProductId = p.ProductId
Where
(
sd.Date >=' 1/1/2021 00:00:00'
and sd.Date <= '26/10/2021 23:59:59'
and p.BarCode = '7790628000034'
and ((s.VoucherTypeId >= 16 and s.VoucherTypeId <= 18)
or s.VoucherTypeId = 32 ))
group by
CONVERT(VARCHAR(10),sd.Date,112),
sd.CodId ,
p.Description
order by CONVERT(VARCHAR(10),sd.Date,112) desc