Summing a column by all transactions in a day - sql

I'm trying to sum up all transactions for each day in my database.
SELECT DISTINCT
SUM(Balance) OVER (partition by Date) AS account_total,
Date
FROM tbl_FundData
ORDER BY Date;
The problem with the output is if a transaction is completed at a different time it becomes its own unique sum instead of rolling into the one day. I'm not sure how to modify the query to fix this.
I'm using SQL Server 2008 (I think)

Seems yo use DateTime as column data type so cast it as DATE :
SELECT DISTINCT SUM(Balance) OVER (partition by CAST([Date] AS DATE)) AS account_total, CAST([Date] AS DATE)
FROM tbl_FundData
ORDER BY CAST([Date] AS DATE);
Also you'd better use Group By in this case as :
SELECT SUM(Balance) AS account_total, CAST([Date] AS DATE)
FROM tbl_FundData
GROUP BY CAST([Date] AS DATE);

SELECT DISTINCT
SUM(Balance) OVER (partition by convert(varchar, Date, 103)) AS account_total,
convert(varchar, Date, 103) Date
FROM tbl_FundData
ORDER BY convert(varchar,Date,103)

SELECT SUM(Balance) account_total
,CAST(FLOOR(CAST(IssueDate AS FLOAT)) AS DATETIME) IssueDate
FROM tbl_FundData
GROUP BY
CAST(FLOOR(CAST(IssueDate AS FLOAT)) AS DATETIME)
ORDER BY
CAST(FLOOR(CAST(IssueDate AS FLOAT)) AS DATETIME)

I guess you have a timestamp as well in your date that's why you get unique values when you sum. Use this:
SELECT sum(balance)
FROM tbl_FundData
GROUP BY convert(date ,date, 106)
106 is a format for date. But you could use whatever.

Related

Lag function for dates in SQL

I am using LAG SQL function to get the difference of 2 consecutive dates in the records. THe issue is, the result it is returning is in DATE -TIME format whereas I want it either to be in Days, or hours. Attached is Output it outcome and the expected result.
Code:
select
*,
(action_date - lag(action_date) over (partition by voucher_no order by action_date)) as diff
from cte3
I would recommend using time for the last column -- although it does give you seconds as well:
SELECT DATEDIFF(day, LAG(Date) OVER (ORDER BY Date), Date ) AS diff_day,
CONVERT(TIME, Date - LAG(Date) OVER (ORDER BY Date)) as time
FROM t;
It is simple enough to convert this to just HH:MM format if you prefer:
SELECT DATEDIFF(day, LAG(Date) OVER (ORDER BY Date), Date ) AS diff_day,
CONVERT(VARCHAR(5), CONVERT(TIME, Date - LAG(Date) OVER (ORDER BY Date))) as time_hhmm
FROM t;
Here is a db<>fiddle.
I prefer this method because it is easier to format the time. In particular, the fiddle includes an example where the time is 00:01 and it is formatted as 00:01 rather than 0:1.
You can use DATEDIFF() function such as
SELECT
DATEDIFF(day, LAG(Date) OVER (ORDER BY Date), Date ) AS diff_day,
CONCAT(
DATEDIFF(minute, LAG(Date) OVER (ORDER BY Date), Date )/60,
':',
DATEDIFF(minute, LAG(Date) OVER (ORDER BY Date), Date )%60
) AS diff_hour_minute, *
FROM t
in order to get the desired difference values.
Demo

How to write an SQL aggregate function/query

I have a query that displays the total value (sum of amount) for each day.
The query:
SELECT CAST(date AS DATE), SUM(amount) AS total_amount FROM table
WHERE date BETWEEN '2019-01-01 00:00:00' AND '2019-12-31 00:00:00'
GROUP BY CAST(date AS DATE)
The CAST is to abbreviate the datetime format to just a date.
Now I want to select only the day which has the highest sum with the max function.
To do this I tried writing the following aggregate query:
SELECT s.date, s.total_amount
FROM (SELECT CAST(date AS DATE), SUM(amount) AS total_amount FROM table
WHERE date BETWEEN '2019-01-01 00:00:00' AND '2019-12-31 00:00:00'
GROUP BY CAST(date AS DATE)) s
WHERE s.total_amount = (SELECT MAX(s.total_amount) FROM table)
This does not work. I know the problem is with the final WHERE clause, but I need help with making it work.
Use ORDER BY with LIMIT :
SELECT CAST(date AS DATE), SUM(amount) AS total_amount
FROM table
WHERE date BETWEEN '2019-01-01 00:00:00' AND '2019-12-31 00:00:00'
GROUP BY CAST(date AS DATE)
ORDER BY total_amount DESC
LIMIT 1;
If you are working with SQL Server then you can use TOP :
SELECT TOP (1) CAST(date AS DATE), SUM(amount) AS total_amount
FROM table
WHERE date BETWEEN '2019-01-01 00:00:00' AND '2019-12-31 00:00:00'
GROUP BY CAST(date AS DATE)
ORDER BY total_amount DESC;
If you want ties then you can use window function :
SELECT t.*
FROM (SELECT CAST(date AS DATE), SUM(amount) AS total_amount,
RANK() OVER (ORDER BY SUM(amount) DESC) as Seq
FROM table
WHERE date BETWEEN '2019-01-01 00:00:00' AND '2019-12-31 00:00:00'
GROUP BY CAST(date AS DATE)
) t
WHERE seq = 1;
You can use CTE :
WITH CTE AS (
SELECT CAST(date AS DATE), SUM(amount) AS total_amount
FROM table
WHERE date BETWEEN '2019-01-01 00:00:00' AND '2019-12-31 00:00:00'
GROUP BY CAST(date AS DATE)
)
SELECT c.*
FROM CTE C
WHERE C.total_amount = (SELECT MAX(total_amount) FROM CTE);
Note : If your DBMS doesn't support CTE expression then you need repeat the SELECT statement in Subquery.
SELECT CAST(date AS DATE), SUM(amount) AS total_amount
FROM table
WHERE date BETWEEN '2019-01-01 00:00:00' AND '2019-12-31 00:00:00'
GROUP BY CAST(date AS DATE)
HAVING SUM(amount) = (SELECT MAX(total_amount)
FROM (SELECT CAST(date AS DATE), SUM(amount) AS total_amount
FROM table
WHERE date BETWEEN '2019-01-01 00:00:00' AND '2019-12-31 00:00:00'
GROUP BY CAST(date AS DATE)
) t
);
If you are using SQL Server then you can use TOP
SELECT TOP 1 CAST(date AS DATE), SUM(amount) AS total_amount
FROM table
WHERE date BETWEEN '2019-01-01 00:00:00' AND '2019-12-31 00:00:00'
GROUP BY CAST(date AS DATE)
ORDER BY total_amount DESC
Use window function row_number() - should work with MySQL 8.0, PostgreSQL, Oracle and SQL Server.
select
date,
total_amount
from
(
SELECT
CAST(date AS DATE) as date,
SUM(amount) AS total_amount,
row_number() over (order by SUM(amount) desc) as rnk
FROM table
WHERE date BETWEEN '2019-01-01 00:00:00' AND '2019-12-31 00:00:00'
GROUP BY CAST(date AS DATE)
) val
where rnk = 1
SELECT s.dt, s.total_amount
FROM (SELECT CAST(date AS DATE) as dt, SUM(amount) AS total_amount
FROM table
WHERE CAST(date as date) BETWEEN '2019-01-01' AND '2019-12-31'
GROUP BY CAST(date AS DATE)) s
WHERE s.total_amount = (Select max(total_amount)
FROM (SELECT CAST(date AS DATE) as dt, SUM(amount) AS total_amount
FROM table
WHERE CAST(date as date) BETWEEN '2019-01-01' AND '2019-12-31'
GROUP BY CAST(date AS DATE)) ss )

Unable to get MIN and MAX time from a Datetime Column from every backday

I am trying to get MIN and MAX time from a Datetime (InOut) column but output is same for both column.
My query:
SELECT
CONVERT(NVARCHAR(12),MIN(Punch_history.Ecode)) as EmpCode,
CONVERT(NVARCHAR(12),MIN(EmployeeMaster.RecommandedBy)) as EmpID,
convert(date, InOut) as Report_date,
CONVERT(VARCHAR(10),(InOut),108) as InTime,
CONVERT(VARCHAR(10),(InOut),108) as OutTime,
CONVERT(NVARCHAR(12),MIN(TID)) as LOCATION
FROM Punch_history inner join EmployeeMaster on Punch_history.ECode = EmployeeMaster.Ecode
where CAST (InOut as DATE) between CAST(getdate() -1 as DATE ) and CAST(getdate() -1 as DATE ) and
EmployeeMaster.RecommandedBy like 'M0%' group by EmpID,InOut
Try grouping by the converted date instead of inout.
SELECT
CONVERT(NVARCHAR(12),MIN(Punch_history.Ecode)) as EmpCode,
convert(date, InOut) as Report_date,
CONVERT(NVARCHAR(10),min(InOut),108) as InTime,
CONVERT(NVARCHAR(10),max(InOut),108) as OutTime
FROM Punch_history
where CAST (InOut as DATE) between CAST(getdate() -1 as DATE )
and CAST(getdate() -1 as DATE )
group by EmpID, convert(date, InOut)
In addition to the grouping issue your where clause is quite strange. First of all using shortcuts for date math is a no win situation. It will fail with datetime2. And using between two identical values is just strange.
SELECT
CONVERT(NVARCHAR(12), MIN(Punch_history.Ecode)) as EmpCode,
convert(date, MIN(InOut)) as Report_date,
CONVERT(NVARCHAR(10), min(InOut), 108) as InTime,
CONVERT(NVARCHAR(10), max(InOut), 108) as OutTime
FROM Punch_history
where convert(date, InOut) = convert(date, dateadd(day, -1, getdate()))
group by EmpID
The major issue is that you should not group by InOut (datetime), that is why in the result max and min are the same. Actually, this is cancelling the grouping which you want to happen on daily basis.
SELECT
CONVERT(NVARCHAR(12),MIN(Punch_history.Empcode)) as EmpCode,
CONVERT(DATE , Max(InOut)) as Report_date,
CONVERT(NVARCHAR(10),min(InOut),108) as InTime,
CONVERT(NVARCHAR(10),max(InOut),108) as OutTime
FROM Punch_history
where datediff(day, CAST(InOut as DATE ) , CAST(getdate() as DATE ) )=1
group by EmpID
In addition, if empid and empcode are 1-1 (logically they should be)
then you can group directly with empcode, or both of them
avoiding this rather strange Min(empcode).

Trying to get an SQL command that gets the new customers from each month but i cant seem to get it working

I am trying to pull the new customers from each month from an SQL database. I've tried this:
SELECT COUNT (Name)
FROM Customer
WHERE Date_created BETWEEN CONVERT(date, getdate()) AND CONVERT(date, getdate()) - (30)
From your query I think this would do it simpler :
SELECT COUNT (Name) FROM Customer WHERE MONTH(Date_created)= MONTH(GETDATE())
although am not sure this is what you expect as your question could be interpreted in several ways
Edit : taking account of different years:
SELECT COUNT (Name) FROM Customer
WHERE MONTH(Date_created)= MONTH(GETDATE())
AND YEAR(Date_created)= YEAR(GETDATE())
Standard SQL:
select
extract(year from Date_created) as yr
,extract(month from Date_created) as mth
,count(*)
from Customer
group by
extract(year from Date_created) as yr
,extract(month from Date_created) as mth
order by yr, mth
Replace EXTRACT with a matching function in you DBMS, e.g. for SQL Server datepart(year, date)
You could use convert(varchar(6), getdate(), 112) to get the month in yyyymm format:
SELECT convert(varchar(6), getdate(), 112) as Month
, count(*)
FROM Customer
GROUP BY
convert(varchar(6), getdate(), 112)
I'm not a fan of using BETWEEN with dates (see this blog What do BETWEEN and the Devil Have in Common). However, the problem with your query is that the dates are in the wrong order. The smaller value has to go first:
SELECT COUNT(Name)
FROM Customer
WHERE Date_created BETWEEN CONVERT(date, getdate() - 30) AND CONVERT(date, getdate())
This is better written as :
SELECT COUNT(Name)
FROM Customer
WHERE Date_Created >= CONVERT(date, getdate() - 30) AND
Date_Created < CONVERT(date, getdate());
I'm not sure if this satisfies your definition of "month", but at least the query will return 30 days worth of creates.

SQL Server Server query - Count distinct DateTime field

Supposing we have the following records in an SQL Server table.
Date
19/5/2009 12:00:00 pm
19/5/2009 12:15:22 pm
20/5/2009 11:38:00 am
What is the SQL syntax for getting something like this one?
Date Count
19/5/2009 2
20/5/2009 1
You need to do any grouping on a Date only version of your datefield, such as this.
SELECT
CONVERT(VARCHAR(10), YourDateColumn, 101),
COUNT(*)
FROM
YourTable
GROUP BY
CONVERT(VARCHAR(10), YourDateColumn, 101)
I usually do this though, as it avoids conversion to varchar.
SELECT
DATEPART(yy, YourDateColumn),
DATEPART(mm, YourDateColumn),
DATEPART(dd, YourDateColumn),
COUNT(*)
FROM
YourTable
GROUP BY
DATEPART(yy, YourDateColumn),
DATEPART(mm, YourDateColumn),
DATEPART(dd, YourDateColumn)
EDIT: Another way to get just the date part of a datetime
DATEADD(d, 0, DATEDIFF(d, 0, YourDateColumn))
That would depend on your database engine. For SQL Server 2008 (and future versions), you can use the date type to do this.
select
convert(date, date_column_name) as Date,
count(1) as Count
from table_name
group by convert(date, date_column_name)
Depends on your DBMS. Example for Mysql:
SELECT DATE_FORMAT(dateColumn, '%e/%c/%Y') as `date`, COUNT(*)
FROM YourTable
GROUP BY `date`
What RDBMS are you on? Using Sybase, your query would look like this:
select date(datetimeColumn) as myDate, count(*) as myTotal
from thisTable
Group by myDate
Order by myTotal, myDate
After Googling found this one too...
SELECT CAST(FLOOR(CAST(Expr1 AS FLOAT)) AS DATEtime) AS Expr1,
COUNT(*) AS Expr2
FROM MY_TABLE
GROUP BY
CAST(FLOOR(CAST(Expr1 AS FLOAT)) AS DATEtime)
The cons?
High speed execution
The results returned are in the original locale. Ex for Greek 19/5/2009
Thank you all